Add ability export/import preferences

Closes #671.
pull/666/merge
Thibaut Courouble 8 years ago
parent a16059a834
commit 44e6316100

@ -1,9 +1,23 @@
class app.Settings
DOCS_KEY = 'docs'
DARK_KEY = 'dark'
LAYOUT_KEY = 'layout'
SIZE_KEY = 'size'
TIPS_KEY = 'tips'
PREFERENCE_KEYS = [
'hideDisabled'
'hideIntro'
'manualUpdate'
'fastScroll'
'arrowScroll'
'docs'
'dark'
'layout'
'size'
'tips'
]
INTERNAL_KEYS = [
'count'
'schema'
'version'
'news'
]
@defaults:
count: 0
@ -32,24 +46,24 @@ class app.Settings
return
hasDocs: ->
try !!@store.get(DOCS_KEY)
try !!@store.get('docs')
getDocs: ->
@store.get(DOCS_KEY)?.split('/') or app.config.default_docs
@store.get('docs')?.split('/') or app.config.default_docs
setDocs: (docs) ->
@set DOCS_KEY, docs.join('/')
@set 'docs', docs.join('/')
return
getTips: ->
@store.get(TIPS_KEY)?.split('/') or []
@store.get('tips')?.split('/') or []
setTips: (tips) ->
@set TIPS_KEY, tips.join('/')
@set 'tips', tips.join('/')
return
setLayout: (name, enable) ->
layout = (@store.get(LAYOUT_KEY) || '').split(' ')
layout = (@store.get('layout') || '').split(' ')
$.arrayDelete(layout, '')
if enable
@ -58,22 +72,34 @@ class app.Settings
$.arrayDelete(layout, name)
if layout.length > 0
@set LAYOUT_KEY, layout.join(' ')
@set 'layout', layout.join(' ')
else
@del LAYOUT_KEY
@del 'layout'
return
hasLayout: (name) ->
layout = (@store.get(LAYOUT_KEY) || '').split(' ')
layout = (@store.get('layout') || '').split(' ')
layout.indexOf(name) isnt -1
setSize: (value) ->
@set SIZE_KEY, value
@set 'size', value
return
dump: ->
@store.dump()
export: ->
data = @dump()
delete data[key] for key in INTERNAL_KEYS
data
import: (data) ->
for key, value of @export()
@del key unless data.hasOwnProperty(key)
for key, value of data
@set key, value if PREFERENCE_KEYS.indexOf(key) isnt -1
return
reset: ->
@store.reset()
@cache = {}

@ -14,6 +14,7 @@ class @CookieStore
return
value = 1 if value == true
value = parseInt(value, 10) if value and INT.test?(value)
Cookies.set(key, '' + value, path: '/', expires: 1e8)
@constructor.onBlocked(key, value, @get(key)) if @get(key) != value
return

@ -1,5 +1,8 @@
[
[
"2017-09-10",
"<a href=\"/settings\">Preferences</a> can now be exported and imported."
], [
"2017-09-03",
"New documentations: <a href=\"/d/\">D</a>, <a href=\"/nim/\">Nim</a> and <a href=\"/vulkan/\">Vulkan</a>"
], [

@ -30,6 +30,10 @@ app.templates.notifInvalidLocation = ->
textNotif """ DevDocs must be loaded from #{app.config.production_host} """,
""" Otherwise things are likely to break. """
app.templates.notifImportInvalid = ->
textNotif """ Oops, an error occured. """,
""" The file you selected is invalid. """
app.templates.notifNews = (news) ->
notif 'Changelog', """<div class="_notif-content _notif-news">#{app.templates.newsList(news, years: false)}</div>"""

@ -35,5 +35,10 @@ app.templates.settingsPage = (settings) -> """
</div>
</div>
<p class="_hide-on-mobile">
<button type="button" class="_btn" data-action="export">Export</button>
<label class="_btn _file-btn"><input type="file" form="settings" name="import" accept=".json">Import</label>
<p>
<button type="button" class="_btn-link _reset-btn" data-behavior="reset">Reset all preferences and data</button>
"""

@ -5,6 +5,7 @@ class app.views.SettingsPage extends app.View
@className: '_static'
@events:
click: 'onClick'
change: 'onChange'
render: ->
@ -46,6 +47,34 @@ class app.views.SettingsPage extends app.View
app.settings.set(name, enable)
return
export: ->
data = new Blob([JSON.stringify(app.settings.export())], type: 'application/json')
link = document.createElement('a')
link.href = URL.createObjectURL(data)
link.download = 'devdocs.json'
link.style.display = 'none'
document.body.appendChild(link)
link.click()
document.body.removeChild(link)
return
import: (file, input) ->
unless file and file.type is 'application/json'
new app.views.Notif 'ImportInvalid', autoHide: false
return
reader = new FileReader()
reader.onloadend = ->
data = try JSON.parse(reader.result)
unless data and data.constructor is Object
new app.views.Notif 'ImportInvalid', autoHide: false
return
app.settings.import(data)
$.trigger input.form, 'import'
return
reader.readAsText(file)
return
onChange: (event) =>
input = event.target
switch input.name
@ -55,10 +84,20 @@ class app.views.SettingsPage extends app.View
@toggleLayout input.value, input.checked
when 'smoothScroll'
@toggleSmoothScroll input.checked
when 'import'
@import input.files[0], input
else
@toggle input.name, input.checked
return
onClick: (event) =>
target = $.eventTarget(event)
switch target.getAttribute('data-action')
when 'export'
$.stopEvent(event)
@export()
return
onRoute: (context) ->
@render()
return

@ -9,6 +9,7 @@ class app.views.Settings extends app.View
backBtn: 'button[data-back]'
@events:
import: 'onImport'
change: 'onChange'
submit: 'onSubmit'
click: 'onClick'
@ -41,11 +42,16 @@ class app.views.Settings extends app.View
@addClass '_in'
return
save: ->
save: (options = {}) ->
unless @saving
@saving = true
if options.import
docs = app.settings.getDocs()
else
docs = @docPicker.getSelectedDocs()
app.settings.setDocs(docs)
@saveBtn.textContent = if app.appCache then 'Downloading\u2026' else 'Saving\u2026'
disabledDocs = new app.collections.Docs(doc for doc in app.docs.all() when docs.indexOf(doc.slug) is -1)
disabledDocs.uninstall ->
@ -66,6 +72,11 @@ class app.views.Settings extends app.View
@save()
return
onImport: =>
@addClass('_dirty')
@save(import: true)
return
onClick: (event) =>
return if event.which isnt 1
if event.target is @backBtn

@ -398,12 +398,16 @@
}
._btn {
display: inline-block;
vertical-align: top;
line-height: normal;
white-space: nowrap;
padding: .375rem .675rem;
background-image: linear-gradient(lighten($boxBackground, 4%), darken($boxBackground, 2%));
border: 1px solid $boxBorder;
border-radius: 3px;
box-shadow: 0 1px rgba($boxBorder, .08);
cursor: pointer;
&:active {
background-color: $boxBackground;
@ -411,6 +415,20 @@
}
}
._file-btn {
position: relative;
overflow: hidden;
> input {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
visibility: hidden;
}
}
._btn-link {
line-height: inherit;
color: $linkColor;

Loading…
Cancel
Save