mirror of
https://github.com/zero-peak/ZeroOmega.git
synced 2025-01-22 15:08:12 -05:00
Enhance your Gist sync experience with built-in browser sync
This commit is contained in:
parent
bc69662911
commit
f5f987253c
@ -452,6 +452,9 @@ msgstr "Syncing (Experimental)"
|
|||||||
msgid "options_syncEnable"
|
msgid "options_syncEnable"
|
||||||
msgstr "Enable Syncing"
|
msgstr "Enable Syncing"
|
||||||
|
|
||||||
|
msgid "options_useBuiltInSyncEnhance"
|
||||||
|
msgstr "Enhance your Gist sync experience with built-in browser sync"
|
||||||
|
|
||||||
msgid "options_syncEnableForce"
|
msgid "options_syncEnableForce"
|
||||||
msgstr "Download from Syncing"
|
msgstr "Download from Syncing"
|
||||||
|
|
||||||
|
@ -413,6 +413,9 @@ msgstr "选项同步 (测试中)"
|
|||||||
msgid "options_syncEnable"
|
msgid "options_syncEnable"
|
||||||
msgstr "启用同步"
|
msgstr "启用同步"
|
||||||
|
|
||||||
|
msgid "options_useBuiltInSyncEnhance"
|
||||||
|
msgstr "使用浏览器内置同步功能增强 Gist 同步使用体验"
|
||||||
|
|
||||||
msgid "options_syncEnableForce"
|
msgid "options_syncEnableForce"
|
||||||
msgstr "下载云端版本"
|
msgstr "下载云端版本"
|
||||||
|
|
||||||
|
@ -5,6 +5,9 @@ Promise.longStackTraces()
|
|||||||
OmegaTargetCurrent.Log = Object.create(OmegaTargetCurrent.Log)
|
OmegaTargetCurrent.Log = Object.create(OmegaTargetCurrent.Log)
|
||||||
Log = OmegaTargetCurrent.Log
|
Log = OmegaTargetCurrent.Log
|
||||||
|
|
||||||
|
|
||||||
|
BUILTINSYNCKEY = 'zeroOmegaSync'
|
||||||
|
|
||||||
# TODO 将来可能代码需要重构下,这里写得有点乱. (suziwen1@gmail.com)
|
# TODO 将来可能代码需要重构下,这里写得有点乱. (suziwen1@gmail.com)
|
||||||
globalThis.isBrowserRestart = globalThis.startupCheck is undefined
|
globalThis.isBrowserRestart = globalThis.startupCheck is undefined
|
||||||
globalThis.hasStartupCheck = not globalThis.isBrowserRestart
|
globalThis.hasStartupCheck = not globalThis.isBrowserRestart
|
||||||
@ -212,7 +215,10 @@ zeroBackground = (zeroStorage, opts) ->
|
|||||||
|
|
||||||
if chrome?.storage?.sync or browser?.storage?.sync
|
if chrome?.storage?.sync or browser?.storage?.sync
|
||||||
syncStorage = new OmegaTargetCurrent.SyncStorage('sync', state)
|
syncStorage = new OmegaTargetCurrent.SyncStorage('sync', state)
|
||||||
sync = new OmegaTargetCurrent.OptionsSync(syncStorage)
|
builtInSyncStorage = new OmegaTargetCurrent.Storage('sync')
|
||||||
|
sync = new OmegaTargetCurrent.OptionsSync(
|
||||||
|
syncStorage, builtInSyncStorage, state
|
||||||
|
)
|
||||||
sync.transformValue = OmegaTargetCurrent.Options.transformValueForSync
|
sync.transformValue = OmegaTargetCurrent.Options.transformValueForSync
|
||||||
|
|
||||||
proxyImpl = OmegaTargetCurrent.proxy.getProxyImpl(Log)
|
proxyImpl = OmegaTargetCurrent.proxy.getProxyImpl(Log)
|
||||||
@ -228,7 +234,46 @@ zeroBackground = (zeroStorage, opts) ->
|
|||||||
if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId and false
|
if chrome.runtime.id != OmegaTargetCurrent.SwitchySharp.extId and false
|
||||||
options.switchySharp = new OmegaTargetCurrent.SwitchySharp()
|
options.switchySharp = new OmegaTargetCurrent.SwitchySharp()
|
||||||
options.switchySharp.monitor()
|
options.switchySharp.monitor()
|
||||||
|
if sync and options and builtInSyncStorage
|
||||||
|
builtInSyncStorage.watch [
|
||||||
|
BUILTINSYNCKEY
|
||||||
|
], (changes, opts = {}) ->
|
||||||
|
builtInSyncConfig = changes[BUILTINSYNCKEY]
|
||||||
|
if builtInSyncConfig
|
||||||
|
{gistId, gistToken, lastGistCommit} = builtInSyncConfig
|
||||||
|
state.set({gistId, gistToken})
|
||||||
|
if sync.enabled
|
||||||
|
console.log('check gist change', lastGistCommit)
|
||||||
|
sync.init({gistId, gistToken})
|
||||||
|
state.get({
|
||||||
|
'lastGistCommit': ''
|
||||||
|
}).then((syncConfig) ->
|
||||||
|
if syncConfig.lastGistCommit isnt lastGistCommit
|
||||||
|
console.log(
|
||||||
|
'no match last gist commit, will check change',
|
||||||
|
syncConfig.lastGistCommit
|
||||||
|
)
|
||||||
|
sync.checkChange()
|
||||||
|
)
|
||||||
|
else
|
||||||
|
# try to enable sync
|
||||||
|
state.get({
|
||||||
|
'syncOptions': ''
|
||||||
|
'lastGistCommit': ''
|
||||||
|
}).then((syncConfig) ->
|
||||||
|
return if syncConfig.lastGistCommit is lastGistCommit
|
||||||
|
if syncConfig.syncOptions in ['pristine', 'conflict']
|
||||||
|
state.set({
|
||||||
|
syncOptions: 'conflict'
|
||||||
|
}).then( ->
|
||||||
|
options.setOptionsSync(true, {
|
||||||
|
gistId,
|
||||||
|
gistToken,
|
||||||
|
useBuiltInSync: true,
|
||||||
|
force: true
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
tabs = new OmegaTargetCurrent.ChromeTabs(actionForUrl)
|
tabs = new OmegaTargetCurrent.ChromeTabs(actionForUrl)
|
||||||
tabs.watch()
|
tabs.watch()
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ isPulling = false
|
|||||||
isPushing = false
|
isPushing = false
|
||||||
|
|
||||||
state = null
|
state = null
|
||||||
|
optionsSync = null
|
||||||
|
|
||||||
mainLetters = ['Z','e', 'r', 'o', 'O', 'm','e', 'g', 'a']
|
mainLetters = ['Z','e', 'r', 'o', 'O', 'm','e', 'g', 'a']
|
||||||
optionFilename = mainLetters.concat(['.json']).join('')
|
optionFilename = mainLetters.concat(['.json']).join('')
|
||||||
@ -97,7 +98,7 @@ processPush = (syncStore) ->
|
|||||||
processPush.sequence.push(syncStore)
|
processPush.sequence.push(syncStore)
|
||||||
return if isPushing
|
return if isPushing
|
||||||
isPushing = true
|
isPushing = true
|
||||||
_processPush()
|
setTimeout(_processPush, 600) # use timeout to merge push
|
||||||
|
|
||||||
processPush.sequence = []
|
processPush.sequence = []
|
||||||
|
|
||||||
@ -155,11 +156,16 @@ updateGist = (gistId, options) ->
|
|||||||
).then((data) ->
|
).then((data) ->
|
||||||
if data.message
|
if data.message
|
||||||
throw data.message
|
throw data.message
|
||||||
|
lastGistCommit = data.history[0]?.version
|
||||||
state?.set({
|
state?.set({
|
||||||
'lastGistCommit': data.history[0]?.version
|
'lastGistCommit': lastGistCommit
|
||||||
'lastGistState': 'success'
|
'lastGistState': 'success'
|
||||||
'lastGistSync': Date.now()
|
'lastGistSync': Date.now()
|
||||||
})
|
}).then( ->
|
||||||
|
optionsSync?.updateBuiltInSyncConfigIf({
|
||||||
|
lastGistCommit
|
||||||
|
})
|
||||||
|
)
|
||||||
return data
|
return data
|
||||||
).catch((e) ->
|
).catch((e) ->
|
||||||
state?.set({
|
state?.set({
|
||||||
@ -262,6 +268,8 @@ class ChromeSyncStorage extends OmegaTarget.Storage
|
|||||||
# param(withRemoteData) retrive gist file content
|
# param(withRemoteData) retrive gist file content
|
||||||
##
|
##
|
||||||
init: (args) ->
|
init: (args) ->
|
||||||
|
optionsSync = args.optionsSync
|
||||||
|
state = args.state
|
||||||
gistId = args.gistId || ''
|
gistId = args.gistId || ''
|
||||||
if gistId.indexOf('/') >= 0
|
if gistId.indexOf('/') >= 0
|
||||||
# get gistId from url `https://gist.github.com/{username}/{gistId}`
|
# get gistId from url `https://gist.github.com/{username}/{gistId}`
|
||||||
|
@ -101,8 +101,9 @@ class Options
|
|||||||
'gistToken': ''
|
'gistToken': ''
|
||||||
}).then(({syncOptions, gistId, gistToken}) =>
|
}).then(({syncOptions, gistId, gistToken}) =>
|
||||||
unless gistId
|
unless gistId
|
||||||
syncOptions = 'pristine'
|
unless syncOptions is 'disabled'
|
||||||
@_state.set({'syncOptions': 'pristine'})
|
syncOptions = 'pristine'
|
||||||
|
@_state.set({'syncOptions': syncOptions})
|
||||||
@sync.enabled = syncOptions is 'sync'
|
@sync.enabled = syncOptions is 'sync'
|
||||||
unless @sync.enabled
|
unless @sync.enabled
|
||||||
@_storage.get(null)
|
@_storage.get(null)
|
||||||
@ -182,6 +183,8 @@ class Options
|
|||||||
###
|
###
|
||||||
init: (startupCheck = -> true) ->
|
init: (startupCheck = -> true) ->
|
||||||
# startupCheck 一定要放在 isBrowserRestart 后面
|
# startupCheck 一定要放在 isBrowserRestart 后面
|
||||||
|
# startupProfileName 如果为空,就使用当前的 currentProfileName
|
||||||
|
# 如果没有 currentProfileName, 就使用默认的 fallbackProfileName
|
||||||
# TODO (suziwen1@gmail.com)
|
# TODO (suziwen1@gmail.com)
|
||||||
# 1. 好像有 bug , 一直没法重现,但就是很不经意就能出现,概率很小的样子
|
# 1. 好像有 bug , 一直没法重现,但就是很不经意就能出现,概率很小的样子
|
||||||
# 2. 有全局变量,容易污染代码,需要重构初始化流程
|
# 2. 有全局变量,容易污染代码,需要重构初始化流程
|
||||||
@ -189,12 +192,17 @@ class Options
|
|||||||
if globalThis.isBrowserRestart and
|
if globalThis.isBrowserRestart and
|
||||||
startupCheck() and
|
startupCheck() and
|
||||||
@_options['-startupProfileName']
|
@_options['-startupProfileName']
|
||||||
|
console.log(
|
||||||
|
'apply browser restart startup profile',
|
||||||
|
@_options['-startupProfileName']
|
||||||
|
)
|
||||||
@applyProfile(@_options['-startupProfileName'])
|
@applyProfile(@_options['-startupProfileName'])
|
||||||
else
|
else
|
||||||
@_state.get({
|
@_state.get({
|
||||||
'currentProfileName': @fallbackProfileName
|
'currentProfileName': @fallbackProfileName
|
||||||
'isSystemProfile': false
|
'isSystemProfile': false
|
||||||
}).then (st) =>
|
}).then (st) =>
|
||||||
|
console.log('apply init startup profile', st)
|
||||||
if st['isSystemProfile']
|
if st['isSystemProfile']
|
||||||
@applyProfile('system')
|
@applyProfile('system')
|
||||||
else
|
else
|
||||||
@ -208,7 +216,7 @@ class Options
|
|||||||
).then => @getAll()
|
).then => @getAll()
|
||||||
|
|
||||||
@ready.then =>
|
@ready.then =>
|
||||||
@sync.requestPush(@_options) if @sync?.enabled
|
#@sync.requestPush(@_options) if @sync?.enabled
|
||||||
|
|
||||||
@_state.get({'firstRun': ''}).then ({firstRun}) =>
|
@_state.get({'firstRun': ''}).then ({firstRun}) =>
|
||||||
@onFirstRun(firstRun) if firstRun
|
@onFirstRun(firstRun) if firstRun
|
||||||
@ -296,14 +304,20 @@ class Options
|
|||||||
reset: (options) ->
|
reset: (options) ->
|
||||||
@log.method('Options#reset', this, arguments)
|
@log.method('Options#reset', this, arguments)
|
||||||
options ?= @getDefaultOptions()
|
options ?= @getDefaultOptions()
|
||||||
@upgrade(@parseOptions(options)).then ([opt]) =>
|
_options = @parseOptions(options)
|
||||||
|
@upgrade(_options).then ([opt]) =>
|
||||||
# Disable syncing when resetting to avoid affecting sync storage.
|
# Disable syncing when resetting to avoid affecting sync storage.
|
||||||
@sync.enabled = false if @sync?
|
@sync.enabled = false if @sync?
|
||||||
@_state.remove(['syncOptions'])
|
@_state.remove(['syncOptions'])
|
||||||
|
@_watchStop?()
|
||||||
|
@_watchStop = null
|
||||||
@_storage.remove().then(=>
|
@_storage.remove().then(=>
|
||||||
@_storage.set(opt)
|
@_storage.set(opt)
|
||||||
).then =>
|
).then( =>
|
||||||
@init()
|
@init()
|
||||||
|
).then =>
|
||||||
|
if _options['-startupProfileName']
|
||||||
|
@applyProfile(_options['-startupProfileName'])
|
||||||
|
|
||||||
###*
|
###*
|
||||||
# Called on the first initialization of options.
|
# Called on the first initialization of options.
|
||||||
@ -1055,7 +1069,7 @@ class Options
|
|||||||
}).then ({syncOptions, lastGistCommit}) =>
|
}).then ({syncOptions, lastGistCommit}) =>
|
||||||
if not enabled
|
if not enabled
|
||||||
if syncOptions == 'sync'
|
if syncOptions == 'sync'
|
||||||
@_state.set({'syncOptions': 'pristine'})
|
@_state.set({'syncOptions': 'disabled'})
|
||||||
@sync.enabled = false
|
@sync.enabled = false
|
||||||
@_syncWatchStop?()
|
@_syncWatchStop?()
|
||||||
@_syncWatchStop = null
|
@_syncWatchStop = null
|
||||||
@ -1082,9 +1096,26 @@ class Options
|
|||||||
if syncOptions == 'conflict'
|
if syncOptions == 'conflict'
|
||||||
# Try to re-init options from sync.
|
# Try to re-init options from sync.
|
||||||
@sync.enabled = false
|
@sync.enabled = false
|
||||||
@_storage.remove().then =>
|
@_watchStop?()
|
||||||
|
@_watchStop = null
|
||||||
|
@_storage.remove().then( =>
|
||||||
|
if remoteOptions
|
||||||
|
console.log('flush data')
|
||||||
|
@sync.flush({data: remoteOptions})
|
||||||
|
).then =>
|
||||||
@sync.enabled = true
|
@sync.enabled = true
|
||||||
@init()
|
@init().then( =>
|
||||||
|
if remoteOptions
|
||||||
|
if remoteOptions['-startupProfileName']
|
||||||
|
console.log('apply startup')
|
||||||
|
@applyProfile(remoteOptions['-startupProfileName'])
|
||||||
|
if args.useBuiltInSync
|
||||||
|
@sync.toggleBuiltInSync(true)
|
||||||
|
else
|
||||||
|
@sync.toggleBuiltInSync(false)
|
||||||
|
).then( =>
|
||||||
|
@updateProfile()
|
||||||
|
)
|
||||||
else
|
else
|
||||||
if remoteOptions?.schemaVersion
|
if remoteOptions?.schemaVersion
|
||||||
@sync.flush({data: remoteOptions}).then( =>
|
@sync.flush({data: remoteOptions}).then( =>
|
||||||
@ -1097,6 +1128,10 @@ class Options
|
|||||||
@_syncWatchStop?()
|
@_syncWatchStop?()
|
||||||
@sync.requestPush(@_options)
|
@sync.requestPush(@_options)
|
||||||
@_syncWatchStop = @sync.watchAndPull(@_storage)
|
@_syncWatchStop = @sync.watchAndPull(@_storage)
|
||||||
|
if args.useBuiltInSync
|
||||||
|
@sync.toggleBuiltInSync(true)
|
||||||
|
else
|
||||||
|
@sync.toggleBuiltInSync(false)
|
||||||
return
|
return
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -6,6 +6,9 @@ Log = require './log'
|
|||||||
jsondiffpatch = require 'jsondiffpatch'
|
jsondiffpatch = require 'jsondiffpatch'
|
||||||
TokenBucket = require('limiter').TokenBucket
|
TokenBucket = require('limiter').TokenBucket
|
||||||
|
|
||||||
|
|
||||||
|
BUILTINSYNCKEY = 'zeroOmegaSync'
|
||||||
|
|
||||||
class OptionsSync
|
class OptionsSync
|
||||||
@TokenBucket: TokenBucket
|
@TokenBucket: TokenBucket
|
||||||
|
|
||||||
@ -31,7 +34,15 @@ class OptionsSync
|
|||||||
###
|
###
|
||||||
storage: null
|
storage: null
|
||||||
|
|
||||||
constructor: (@storage, @_bucket) ->
|
###*
|
||||||
|
# Use browser built-in sync to enhance gist sync function
|
||||||
|
# @type Storage
|
||||||
|
###
|
||||||
|
builtInSyncStorage: null
|
||||||
|
|
||||||
|
state: null
|
||||||
|
|
||||||
|
constructor: (@storage, @builtInSyncStorage, @state, @_bucket) ->
|
||||||
@_pending = {}
|
@_pending = {}
|
||||||
@_bucket ?= new TokenBucket(10, 10, 'minute', null)
|
@_bucket ?= new TokenBucket(10, 10, 'minute', null)
|
||||||
@_bucket.clear ?= =>
|
@_bucket.clear ?= =>
|
||||||
@ -207,12 +218,45 @@ class OptionsSync
|
|||||||
doPull()
|
doPull()
|
||||||
else
|
else
|
||||||
pullScheduled = setTimeout(doPull, @pullThrottle)
|
pullScheduled = setTimeout(doPull, @pullThrottle)
|
||||||
|
toggleBuiltInSync: (useBuiltInSync) ->
|
||||||
|
@getBuiltInSyncConfig().then((builtInSyncConfig) =>
|
||||||
|
@state.get({
|
||||||
|
'gistId': '',
|
||||||
|
'gistToken': '',
|
||||||
|
'lastGistCommit': ''
|
||||||
|
}).then((syncConfig) =>
|
||||||
|
if useBuiltInSync is undefined
|
||||||
|
useBuiltInSync = !builtInSyncConfig
|
||||||
|
if useBuiltInSync is true
|
||||||
|
_obj = {}
|
||||||
|
_obj[BUILTINSYNCKEY] = syncConfig
|
||||||
|
@builtInSyncStorage.set(_obj)
|
||||||
|
else
|
||||||
|
@builtInSyncStorage.remove(BUILTINSYNCKEY)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
getBuiltInSyncConfig: ->
|
||||||
|
@builtInSyncStorage.get(BUILTINSYNCKEY).then((_obj) ->
|
||||||
|
return _obj[BUILTINSYNCKEY]
|
||||||
|
)
|
||||||
|
updateBuiltInSyncConfigIf: (_builtInSyncConfig) ->
|
||||||
|
@getBuiltInSyncConfig().then((builtInSyncConfig) =>
|
||||||
|
if !!builtInSyncConfig
|
||||||
|
newBuiltInSyncConfig = Object.assign(
|
||||||
|
{}, builtInSyncConfig, _builtInSyncConfig
|
||||||
|
)
|
||||||
|
_obj = {}
|
||||||
|
_obj[BUILTINSYNCKEY] = newBuiltInSyncConfig
|
||||||
|
@builtInSyncStorage.set(_obj)
|
||||||
|
)
|
||||||
checkChange: ->
|
checkChange: ->
|
||||||
@storage.checkChange({
|
@storage.checkChange({
|
||||||
immediately: true
|
immediately: true
|
||||||
force: true
|
force: true
|
||||||
})
|
})
|
||||||
init: (args) ->
|
init: (args) ->
|
||||||
|
args.optionsSync = this
|
||||||
|
args.state = @state
|
||||||
@storage.init(args)
|
@storage.init(args)
|
||||||
destroy: ->
|
destroy: ->
|
||||||
@storage.destroy()
|
@storage.destroy()
|
||||||
|
@ -2,6 +2,7 @@ angular.module('omega').controller 'IoCtrl', (
|
|||||||
$scope, $rootScope, $window, $http, omegaTarget, downloadFile
|
$scope, $rootScope, $window, $http, omegaTarget, downloadFile
|
||||||
) ->
|
) ->
|
||||||
|
|
||||||
|
$scope.useBuiltInSync = true
|
||||||
getGistId = (gistUrl = '') ->
|
getGistId = (gistUrl = '') ->
|
||||||
# get gistId from url `https://gist.github.com/{username}/{gistId}`
|
# get gistId from url `https://gist.github.com/{username}/{gistId}`
|
||||||
# or directly gistId
|
# or directly gistId
|
||||||
@ -32,7 +33,7 @@ angular.module('omega').controller 'IoCtrl', (
|
|||||||
plainOptions = angular.fromJson(angular.toJson($rootScope.options))
|
plainOptions = angular.fromJson(angular.toJson($rootScope.options))
|
||||||
content = JSON.stringify(plainOptions)
|
content = JSON.stringify(plainOptions)
|
||||||
blob = new Blob [content], {type: "text/plain;charset=utf-8"}
|
blob = new Blob [content], {type: "text/plain;charset=utf-8"}
|
||||||
downloadFile(blob, "OmegaOptions.bak")
|
downloadFile(blob, "Zero" + """OmegaOptions.bak""")
|
||||||
|
|
||||||
$scope.importSuccess = ->
|
$scope.importSuccess = ->
|
||||||
$rootScope.showAlert(
|
$rootScope.showAlert(
|
||||||
@ -89,6 +90,7 @@ angular.module('omega').controller 'IoCtrl', (
|
|||||||
return
|
return
|
||||||
args.gistId = $scope.gistId
|
args.gistId = $scope.gistId
|
||||||
args.gistToken = $scope.gistToken
|
args.gistToken = $scope.gistToken
|
||||||
|
args.useBuiltInSync = $scope.useBuiltInSync
|
||||||
$scope.enableOptionsSyncing = true
|
$scope.enableOptionsSyncing = true
|
||||||
omegaTarget.setOptionsSync(true, args).then( ->
|
omegaTarget.setOptionsSync(true, args).then( ->
|
||||||
$window.location.reload()
|
$window.location.reload()
|
||||||
|
@ -59,6 +59,10 @@ section.settings-group
|
|||||||
a(href="https://github.com/settings/tokens/new" role="button" target="_blank")
|
a(href="https://github.com/settings/tokens/new" role="button" target="_blank")
|
||||||
| {{ 'Create a token that manages the Gist.(Only gist permission is required.)'}}
|
| {{ 'Create a token that manages the Gist.(Only gist permission is required.)'}}
|
||||||
div(ng-show='syncOptions == "pristine" || syncOptions == "disabled"')
|
div(ng-show='syncOptions == "pristine" || syncOptions == "disabled"')
|
||||||
|
div.checkbox
|
||||||
|
label
|
||||||
|
input#use-built-in-sync-enhance(type='checkbox' ng-model='useBuiltInSync')
|
||||||
|
span {{'options_useBuiltInSyncEnhance' | tr}}
|
||||||
p.help-block(omega-html='"options_syncPristineHelp" | tr')
|
p.help-block(omega-html='"options_syncPristineHelp" | tr')
|
||||||
p
|
p
|
||||||
button.btn.btn-default(ng-click='enableOptionsSync()' ladda='enableOptionsSyncing' data-spinner-color="currentColor")
|
button.btn.btn-default(ng-click='enableOptionsSync()' ladda='enableOptionsSyncing' data-spinner-color="currentColor")
|
||||||
@ -89,6 +93,10 @@ section.settings-group
|
|||||||
= ' '
|
= ' '
|
||||||
| {{'options_syncDisable' | tr}}
|
| {{'options_syncDisable' | tr}}
|
||||||
div(ng-show='syncOptions == "conflict"')
|
div(ng-show='syncOptions == "conflict"')
|
||||||
|
div.checkbox
|
||||||
|
label
|
||||||
|
input#use-built-in-sync-enhance(type='checkbox' ng-model='useBuiltInSync')
|
||||||
|
span {{'options_useBuiltInSyncEnhance' | tr}}
|
||||||
p.alert.alert-danger.width-limit
|
p.alert.alert-danger.width-limit
|
||||||
span.glyphicon.glyphicon-info-sign
|
span.glyphicon.glyphicon-info-sign
|
||||||
= ' '
|
= ' '
|
||||||
|
Loading…
Reference in New Issue
Block a user