moved to new store for config...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-02-14 16:49:44 +03:00
parent 1949aa884f
commit 35a7a16539
9 changed files with 310 additions and 332 deletions

View File

@ -11,6 +11,7 @@
var core = require('features/core')
require('features/base')
require('features/store')
require('features/collections')
require('features/sort')
require('features/tags')

View File

@ -24,274 +24,6 @@ var core = require('features/core')
/*********************************************************************/
// XXX move store to a separate module...
// XXX should we unify this with the save/load API
var StoreActions = actions.Actions({
config: {
// Storage mode...
//
// This can be:
// 'read-only'
// 'read-write'
// null - ignore store
//
// NOTE: this only affects start/stop/timer event handling, manual
// call to .loadData(..) / .saveData(..) are not affected...
'store-mode': 'read-write',
},
// Store handler dict...
//
// Format:
// {
// <store-tag>: <handler-action>,
// ...
// }
//
// XXX this is almost the same as .collection_handlers...
get store_handlers(){
return this.cache('store_handlers', function(d){
var res = {}
this.actions.forEach(function(action){
var store = this.getActionAttr(action, 'handle_data_store')
res[store]
&& console.warn('Multiple handlers for store:', store)
if(store){
res[store] = action
}
}.bind(this))
return res
}) },
// events...
storeDataLoaded: ['- Store/',
core.doc`Store data loaded event...
This is tirggered as soon per store as soon as data is loaded,
this is sync for sync stores.
NOTE: only one store data set is included per call.`,
core.Event(function(data){
// Store data loaded event...
//
// Not intended for direct use, use .declareReady() to initiate.
return data
})],
// base API...
prepareStoreToSave: ['- Store/',
core.doc`
Modes:
'fast' - fast timer
'full' - full store
Format:
{
// metadata...
mode: <mode>,
data: <timestamp>,
// the actual data...
store: {
<store-type>: {
<data-key>: <data>,
...
},
...
},
}
`,
function(mode, date){
var store = {}
// populate the store...
Object.keys(this.store_handlers)
.forEach(function(key){ store[key] = {} })
return {
mode: mode || 'full',
date: date || Date.timeStamp(),
store: store,
}
}],
prepareStoreToLoad: ['- Store/',
core.doc`
NOTE: this can be called multiple times, once per each store.
NOTE: only one store data set is included per call.`,
function(data){ return data || {} }],
// XXX async???
// XXX we need to be able to save/load specific part of the data...
// ...i.e. query by store and/or key...
saveData: ['- Store/',
function(mode, date){
var handlers = this.store_handlers
var data = this.prepareStoreToSave(mode, date)
Object.keys(data.store).forEach(function(store){
var handler = handlers[store]
handler
&& this[handler].call(this, data.store[store])
}.bind(this))
}],
loadData: ['- Store/',
function(){
var handlers = this.store_handlers
var data = {}
return Promise
.all(Object.keys(handlers)
.map(function(s){
var res = this[handlers[s]]()
return res instanceof Promise ?
// async store...
res.then(function(d){ d
&& (data[s] = d)
&& this.storeDataLoaded(
this.prepareStoreToLoad({[s]: d})) }.bind(this))
// sync store...
: (res
&& (data[s] = res)
&& this.storeDataLoaded(
this.prepareStoreToLoad({[s]: res})))
}.bind(this)))
.then(function(){ return data })}],
// XXX do we need to do a partial clear???
clearData: ['- Store/',
function(target){
var handlers = this.store_handlers
Object.keys(handlers).forEach(function(store){
var handler = handlers[store]
handler
&& this[handler].call(this, null)
}.bind(this))
}],
})
var Store =
module.Store = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'store',
depends: [
'cache',
],
suggested: [
'store-localstorage',
],
isApplicable: function(){ return typeof(localStorage) != 'undefined' },
actions: StoreActions,
handlers: [
['start.pre',
function(){
if(this.config['store-mode'] != null){
this.requestReadyAnnounce()
this
.loadData()
.then(function(){
this.declareReady() }.bind(this))
} }],
['stop',
function(){
this.config['store-mode'] == 'read-write' && this.saveData() }],
// XXX timer???
// XXX
],
})
//---------------------------------------------------------------------
// XXX we should have a separate store config with settings of how to
// load the store... (???)
var StoreLocalStorageActions = actions.Actions({
config: {
// XXX
'store-root-key': 'test-store-root-key',
},
// XXX get root key from config...
// ...this would require us to store the store config separately...
localStorageDataHandler: ['- Store/',
{handle_data_store: 'localStorage',},
function(data){
// XXX get this from config...
var root = this.config['store-root-key']
// clear...
if(data === null){
delete localStorage[root]
// set...
} else if(data){
localStorage[root] = JSON.stringify(data)
// get...
} else {
var d = localStorage[root]
return d != undefined ? JSON.parse(d) : {}
}
}],
sessionStorageDataHandler: ['- Store/',
{handle_data_store: 'sessionStorage',},
function(data){
// XXX get this from config...
var root = this.config['store-root-key']
// clear...
if(data === null){
delete sessionStorage[root]
// set...
} else if(data){
sessionStorage[root] = JSON.stringify(data)
// get...
} else {
var d = localStorage[root]
return d != undefined ? JSON.parse(d) : {}
}
}],
})
var StoreLocalStorage =
module.StoreLocalStorage = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'store-localstorage',
depends: [
'store',
],
isApplicable: function(){
return typeof(localStorage) != 'undefined'
&& typeof(sessionStorage) != 'undefined' },
actions: StoreLocalStorageActions,
})
//---------------------------------------------------------------------
// XXX StoreFSJSONSync
// Lookup order:
// - app dir
// - $HOME
//---------------------------------------------------------------------
// XXX StoreFSJSON
/*********************************************************************/
// XXX might be a good idea to add a .configLoaded(..) and .configChanged(..)
@ -305,16 +37,18 @@ var ConfigStoreActions = actions.Actions({
// - 'normal' -- use $HOME
'config-fs-filename': '.ImageGrid.json',
'config-auto-save-interval': null,
'config-auto-save-interval': 1000*5,
},
__base_config: null,
/* XXX
// XXX
storeConfig: ['File/Store configuration',
function(key){
// XXX
}],
// XXX
loadConfig: ['File/Load stored configuration',
function(key){
// XXX
@ -325,8 +59,9 @@ var ConfigStoreActions = actions.Actions({
var base = this.__base_config = this.__base_config || this.config
this.config = Object.create(base)
}],
//*/
/* XXX use timer events...
// XXX use timer events... (???)
// XXX this needs a working .storeConfig(..)
toggleAutoStoreConfig: ['File/Store configuration',
toggler.Toggler(null,
function(_, state){
@ -355,7 +90,6 @@ var ConfigStoreActions = actions.Actions({
}
},
'running')],
//*/
})
var ConfigStore =
@ -398,10 +132,7 @@ module.ConfigStore = core.ImageGridFeatures.Feature({
var base = this.__base_config = this.__base_config || this.config
var config = store.localStorage.config || {}
config.__proto__ = base
// XXX set the config...
// ...disabled for now to avoid conflicts with
// legacy until we are ready to make the move...
//this.config = config
this.config = config
}
// XXX sync fs store...
@ -410,6 +141,11 @@ module.ConfigStore = core.ImageGridFeatures.Feature({
if((store.fsJSONSync || {}).config){
// XXX
}
// auto-start auto-save...
this.config['config-auto-save-interval'] > 0
&& this.toggleAutoStoreConfig('?') == 'off'
&& this.toggleAutoStoreConfig()
}],
],
})
@ -417,6 +153,8 @@ module.ConfigStore = core.ImageGridFeatures.Feature({
/*********************************************************************/
/*/ XXX LEGACY...
//
// XXX might be a good idea to add an external payload mechanism for
// other data to be saved to avoid re-implementing the same logic
// ...like is done in features/history.js
@ -512,7 +250,6 @@ var ConfigActions = actions.Actions({
'running')],
})
var Config =
module.Config = core.ImageGridFeatures.Feature({
title: '',
@ -616,7 +353,6 @@ var ConfigLocalStorageActions = actions.Actions({
}],
})
var ConfigLocalStorage =
module.ConfigLocalStorage = core.ImageGridFeatures.Feature({
title: '',
@ -636,52 +372,7 @@ module.ConfigLocalStorage = core.ImageGridFeatures.Feature({
actions: ConfigLocalStorageActions,
})
//---------------------------------------------------------------------
// XXX store config locations:
// - app
// - home
// XXX config override location/filename to support portable apps...
// XXX comment support in json (preferably both reading and writing...)
var ConfigFSActions = actions.Actions({
config: {
},
})
var ConfigFS =
module.ConfigFS = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'fs-config',
depends: [
'localstorage-config',
'fs',
],
actions: ConfigFSActions,
handlers: [
// NOTE: considering that allot depends on this it must be
// first to run...
['loadConfig',
function(){
}],
['storeConfig',
function(){
}],
],
})
//---------------------------------------------------------------------
//*/
/**********************************************************************

View File

@ -891,7 +891,7 @@ var TimersActions = actions.Actions({
ms: ms,
}
timeouts[id] = setInterval(
intervals[id] = setInterval(
function(){ this.call(action) }.bind(this),
ms || 0)
}],

View File

@ -137,8 +137,8 @@ core.ImageGridFeatures.Feature('imagegrid-testing', [
// XXX testing...
'store-config',
//'config',
'config',
'ui-url-hash',
'fail-safe-devtools',

285
ui (gen4)/features/store.js Executable file
View File

@ -0,0 +1,285 @@
/**********************************************************************
*
*
*
**********************************************************************/
((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define)
(function(require){ var module={} // make module AMD/node compatible...
/*********************************************************************/
var actions = require('lib/actions')
var features = require('lib/features')
var core = require('features/core')
/*********************************************************************/
// XXX should we unify this with the save/load API
var StoreActions = actions.Actions({
config: {
// Storage mode...
//
// This can be:
// 'read-only'
// 'read-write'
// null - ignore store
//
// NOTE: this only affects start/stop/timer event handling, manual
// call to .loadData(..) / .saveData(..) are not affected...
'store-mode': 'read-write',
},
// Store handler dict...
//
// Format:
// {
// <store-tag>: <handler-action>,
// ...
// }
//
// XXX this is almost the same as .collection_handlers...
get store_handlers(){
return this.cache('store_handlers', function(d){
var res = {}
this.actions.forEach(function(action){
var store = this.getActionAttr(action, 'handle_data_store')
res[store]
&& console.warn('Multiple handlers for store:', store)
if(store){
res[store] = action
}
}.bind(this))
return res
}) },
// events...
storeDataLoaded: ['- Store/',
core.doc`Store data loaded event...
This is tirggered as soon per store as soon as data is loaded,
this is sync for sync stores.
NOTE: only one store data set is included per call.`,
core.Event(function(data){
// Store data loaded event...
//
// Not intended for direct use, use .declareReady() to initiate.
return data
})],
// base API...
prepareStoreToSave: ['- Store/',
core.doc`
Modes:
'fast' - fast timer
'full' - full store
Format:
{
// metadata...
mode: <mode>,
data: <timestamp>,
// the actual data...
store: {
<store-type>: {
<data-key>: <data>,
...
},
...
},
}
`,
function(mode, date){
var store = {}
// populate the store...
Object.keys(this.store_handlers)
.forEach(function(key){ store[key] = {} })
return {
mode: mode || 'full',
date: date || Date.timeStamp(),
store: store,
}
}],
prepareStoreToLoad: ['- Store/',
core.doc`
NOTE: this can be called multiple times, once per each store.
NOTE: only one store data set is included per call.`,
function(data){ return data || {} }],
// XXX async???
// XXX we need to be able to save/load specific part of the data...
// ...i.e. query by store and/or key...
saveData: ['- Store/',
function(mode, date){
var handlers = this.store_handlers
var data = this.prepareStoreToSave(mode, date)
Object.keys(data.store).forEach(function(store){
var handler = handlers[store]
handler
&& this[handler].call(this, data.store[store])
}.bind(this))
}],
loadData: ['- Store/',
function(){
var handlers = this.store_handlers
var data = {}
return Promise
.all(Object.keys(handlers)
.map(function(s){
var res = this[handlers[s]]()
return res instanceof Promise ?
// async store...
res.then(function(d){ d
&& (data[s] = d)
&& this.storeDataLoaded(
this.prepareStoreToLoad({[s]: d})) }.bind(this))
// sync store...
: (res
&& (data[s] = res)
&& this.storeDataLoaded(
this.prepareStoreToLoad({[s]: res})))
}.bind(this)))
.then(function(){ return data })}],
// XXX do we need to do a partial clear???
clearData: ['- Store/',
function(target){
var handlers = this.store_handlers
Object.keys(handlers).forEach(function(store){
var handler = handlers[store]
handler
&& this[handler].call(this, null)
}.bind(this))
}],
})
var Store =
module.Store = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'store',
depends: [
'cache',
],
suggested: [
'store-localstorage',
],
isApplicable: function(){ return typeof(localStorage) != 'undefined' },
actions: StoreActions,
handlers: [
['start.pre',
function(){
if(this.config['store-mode'] != null){
this.requestReadyAnnounce()
this
.loadData()
.then(function(){
this.declareReady() }.bind(this))
} }],
['stop',
function(){
this.config['store-mode'] == 'read-write' && this.saveData() }],
// XXX timer???
// XXX
],
})
//---------------------------------------------------------------------
// XXX we should have a separate store config with settings of how to
// load the store... (???)
var StoreLocalStorageActions = actions.Actions({
config: {
'store-root-key': 'ImageGrid.Viewer.main',
},
// XXX get root key from config...
// ...this would require us to store the store config separately...
localStorageDataHandler: ['- Store/',
{handle_data_store: 'localStorage',},
function(data){
// XXX get this from config...
var root = this.config['store-root-key']
// clear...
if(data === null){
delete localStorage[root]
// set...
} else if(data){
localStorage[root] = JSON.stringify(data)
// get...
} else {
var d = localStorage[root]
return d != undefined ? JSON.parse(d) : {}
}
}],
sessionStorageDataHandler: ['- Store/',
{handle_data_store: 'sessionStorage',},
function(data){
// XXX get this from config...
var root = this.config['store-root-key']
// clear...
if(data === null){
delete sessionStorage[root]
// set...
} else if(data){
sessionStorage[root] = JSON.stringify(data)
// get...
} else {
var d = localStorage[root]
return d != undefined ? JSON.parse(d) : {}
}
}],
})
var StoreLocalStorage =
module.StoreLocalStorage = core.ImageGridFeatures.Feature({
title: '',
doc: '',
tag: 'store-localstorage',
depends: [
'store',
],
isApplicable: function(){
return typeof(localStorage) != 'undefined'
&& typeof(sessionStorage) != 'undefined' },
actions: StoreLocalStorageActions,
})
//---------------------------------------------------------------------
// XXX StoreFSJSONSync
// Lookup order:
// - app dir
// - $HOME
//---------------------------------------------------------------------
// XXX StoreFSJSON
/**********************************************************************
* vim:set ts=4 sw=4 : */ return module })

View File

@ -485,7 +485,7 @@ module.SingleImageViewLocalStorage = core.ImageGridFeatures.Feature({
tag: 'ui-single-image-local-storage',
depends: [
'ui-single-image',
'localstorage-config',
//'localstorage-config',
],
handlers:[

View File

@ -1068,9 +1068,9 @@
}
},
"ig-features": {
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/ig-features/-/ig-features-3.3.2.tgz",
"integrity": "sha512-NSvuVkLUI47f1mpG03/fVqJaMYLDUFVcg2FNXUtqvDqQqKhlZuXJfxsGcoFQ1eIZ1pqYcYeYHmjNbgmK6rT5cA==",
"version": "3.3.3",
"resolved": "https://registry.npmjs.org/ig-features/-/ig-features-3.3.3.tgz",
"integrity": "sha512-EiX+ghvyFkgK2g+gXfALDXCBTAb/S99M9se31jMxkud/z5aZQnvXIrBwhDktt4YXUmeZ4ENvuibJYIZrdcCcmA==",
"requires": {
"ig-actions": "3.15.0",
"ig-object": "1.0.2"

View File

@ -27,7 +27,7 @@
"glob": "^4.0.6",
"guarantee-events": "^1.0.0",
"ig-actions": "^3.15.0",
"ig-features": "^3.3.2",
"ig-features": "^3.3.3",
"ig-object": "^1.0.2",
"moment": "^2.20.1",
"openseadragon": "^2.3.1",

View File

@ -72,6 +72,7 @@ $(function(){
} catch(err){
console.error(err)
//throw err
return
}