Alex A. Naanou 27aef3db40 dos linefeeds converted to unix...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
2024-10-27 11:01:12 +03:00

250 lines
6.6 KiB
JavaScript
Executable File

/**********************************************************************
*
* Features:
* - config
* general config API
* - localstorage-config
* maintain configuration state in localStorage
* - fs-config
* maintain configuration state in file system
*
* XXX this module need refactoring...
*
*
**********************************************************************/
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
(function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/
var toggler = require('lib/toggler')
var actions = require('lib/actions')
var features = require('lib/features')
var core = require('features/core')
/*********************************************************************/
// XXX might be a good idea to add "sandbox" mode -- i.e. all settings
// are saved to sessionStorage and a re-open will load the old settings...
// XXX might be a good idea to add a .configLoaded(..) and .configChanged(..)
// events thought it's not clear how are we going to track changes...
var ConfigStoreActions = actions.Actions({
config: {
// XXX should this include path???
// ...there should be modes:
// - 'read-only' -- don't save...
// - 'portable' -- use APP dir
// - 'normal' -- use $HOME
'config-fs-filename': '.ImageGrid.json',
'config-auto-save-interval': 1000*5,
'config-load-sequence': [
// localStorage...
'storage:${INSTANCE}/config',
// FS...
// XXX should we load both or just one???
'fileSync:${APP}/.ImageGrid.json',
'fileSync:${HOME}/.ImageGrid.json',
// temporary config...
// NOTE: this is active until we re-open the app...
'session:${INSTANCE}/config',
],
},
__config_base: null,
__config_loaded_from: null,
// XXX handle save order -- need to save to one location only...
// ...use: .__config_loaded_from in reverse order (stop on session:..)
// XXX keep record of what we loaded...
// XXX should we only support sync stores??? (current state)
loadConfig: ['File/Load configuration',
core.doc`
NOTE: might need to reload after this.
`,
function(query){
// store loaded...
var loaded = this.__config_loaded_from = []
this.resetConfig()
// do the load...
;(query ?
(query instanceof Array ? query : [query])
: (this.config['config-load-sequence'] || ['storage:config']))
.forEach(function(query){
query = this.parseStoreQuery(query)
var cfg = this.loadStore(query)
// select store...
cfg = query.store
.map(function(store){ return cfg[store] })
.filter(function(cfg){ return Object.keys(cfg).length > 0 })
.shift() || {}
// select key...
cfg = query.key
.map(function(key){ return cfg[key] })
.filter(function(cfg){ return !!cfg })
.shift()
// merge the config...
cfg
&& Object.assign(this.config, cfg)
&& loaded.push(query.query)
}.bind(this))
}],
storeConfig: ['File/Save configuration',
function(query){
// XXX
this.saveStore(query || 'storage:${INSTANCE}/config')
}],
// XXX this needs to be confirmed...
resetConfig: ['File/Reset configuration',
core.doc`
NOTE: might need to reload after this.
`,
function(){
var base = this.__config_base = this.__config_base || this.config
this.config = Object.create(base)
}],
// XXX use timer events... (???)
toggleConfigAutoStore: ['File/Auto-save configuration',
toggler.Toggler(null,
function(_, state){
var timer = 'config-auto-save-timer'
if(state == null){
return this.isPersistentInterval(timer) || 'none'
} else {
var that = this
var interval = this.config['config-auto-save-interval']
// no timer interval set...
if(!interval){
return false
}
// start/restart...
if(state == 'running' && interval){
this.setPersistentInterval(timer, 'storeConfig', interval*1000)
// stop...
} else {
this.clearPersistentInterval(timer)
}
}
},
'running')],
// XXX does not work yet...
toggleConfigSandbox: ['- File/',
toggler.Toggler(null,
function(_, state){
if(state == null){
return Object.keys(this.store('session:${INSTANCE}/config').session).length > 0 || 'none'
} else if(state == 'sandboxed'){
this.store('session:${INSTANCE}/config', undefined)
} else {
this.storeConfig('session:${INSTANCE}/config')
}
},
'sandboxed')],
})
var ConfigStore =
module.ConfigStore = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'store-config',
priority: 80,
depends: [
'timers',
'store-localstorage',
],
suggested: [
'store-fs-json-sync',
],
actions: ConfigStoreActions,
handlers: [
// XXX need to update rather than rewrite things...
['prepareStoreToSave',
function(res, query, data){
var ls_path = '${INSTANCE}/config'
//var ls_path = 'config'
query = this.parseStoreQuery(query)
// config not requested...
if(query.key != '*'
&& query.key.indexOf('config')
&& query.key.indexOf(ls_path)){
return
}
// localStorage...
// NOTE: we do not need to clone anything here as this
// will be done by the localStorage handler...
if(query.store.indexOf('storage') >= 0){
//res.data.storage[ls_path] = this.config
res.data.storage[ls_path] = data || this.config
}
if(query.store.indexOf('fileSync') >= 0){
// XXX should this include path???
//res.data.fileSync[this.config['config-fs-filename'] || '.ImageGrid.json'] = this.config
res.data.fileSync[this.config['config-fs-filename'] || '.ImageGrid.json'] = data || this.config
}
}],
//['prepareIndexForLoad',
// function(){
// }],
// NOTE: this is sync for sync stores...
['storeDataLoaded',
function(_, store, data){
var base = this.__config_base = this.__config_base || this.config
var ls_path = '${INSTANCE}/config'
// XXX sort out load priority/logic...
// - one or the other or both?
// - what order?
if((data.storage || {})[ls_path]){
var config = data.storage[ls_path] || {}
config.__proto__ = base
this.config = config
}
if((data.fsJSONSync || {}).config){
var config = data.fsJSONSync.config || {}
config.__proto__ = base
this.config = config
}
// auto-start auto-save...
this.config['config-auto-save-interval'] > 0
&& this.toggleConfigAutoStore('?') == 'off'
&& this.toggleConfigAutoStore()
}],
],
})
/**********************************************************************
* vim:set ts=4 sw=4 : */ return module })