diff --git a/ui (gen4)/features/all.js b/ui (gen4)/features/all.js index 3568beb9..a787b905 100755 --- a/ui (gen4)/features/all.js +++ b/ui (gen4)/features/all.js @@ -11,6 +11,7 @@ var core = require('features/core') require('features/base') +require('features/store') require('features/collections') require('features/sort') require('features/tags') diff --git a/ui (gen4)/features/config.js b/ui (gen4)/features/config.js index 6f3bf148..f0136d94 100755 --- a/ui (gen4)/features/config.js +++ b/ui (gen4)/features/config.js @@ -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: - // { - // : , - // ... - // } - // - // 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: , - data: , - - // the actual data... - store: { - : { - : , - ... - }, - ... - }, - } - `, - 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(){ - }], - ], -}) - - - -//--------------------------------------------------------------------- - +//*/ /********************************************************************** diff --git a/ui (gen4)/features/core.js b/ui (gen4)/features/core.js index 5233a774..a45e7c3a 100755 --- a/ui (gen4)/features/core.js +++ b/ui (gen4)/features/core.js @@ -891,7 +891,7 @@ var TimersActions = actions.Actions({ ms: ms, } - timeouts[id] = setInterval( + intervals[id] = setInterval( function(){ this.call(action) }.bind(this), ms || 0) }], diff --git a/ui (gen4)/features/meta.js b/ui (gen4)/features/meta.js index 4e955af2..170c6138 100755 --- a/ui (gen4)/features/meta.js +++ b/ui (gen4)/features/meta.js @@ -137,8 +137,8 @@ core.ImageGridFeatures.Feature('imagegrid-testing', [ // XXX testing... 'store-config', + //'config', - 'config', 'ui-url-hash', 'fail-safe-devtools', diff --git a/ui (gen4)/features/store.js b/ui (gen4)/features/store.js new file mode 100755 index 00000000..1af59e8a --- /dev/null +++ b/ui (gen4)/features/store.js @@ -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: + // { + // : , + // ... + // } + // + // 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: , + data: , + + // the actual data... + store: { + : { + : , + ... + }, + ... + }, + } + `, + 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 }) diff --git a/ui (gen4)/features/ui-single-image.js b/ui (gen4)/features/ui-single-image.js index edb13b26..6d244dd2 100755 --- a/ui (gen4)/features/ui-single-image.js +++ b/ui (gen4)/features/ui-single-image.js @@ -485,7 +485,7 @@ module.SingleImageViewLocalStorage = core.ImageGridFeatures.Feature({ tag: 'ui-single-image-local-storage', depends: [ 'ui-single-image', - 'localstorage-config', + //'localstorage-config', ], handlers:[ diff --git a/ui (gen4)/package-lock.json b/ui (gen4)/package-lock.json index 0b3ffd2d..380a6fb2 100755 --- a/ui (gen4)/package-lock.json +++ b/ui (gen4)/package-lock.json @@ -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" diff --git a/ui (gen4)/package.json b/ui (gen4)/package.json index b77c0a89..38878854 100755 --- a/ui (gen4)/package.json +++ b/ui (gen4)/package.json @@ -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", diff --git a/ui (gen4)/ui.js b/ui (gen4)/ui.js index 96110530..47f48189 100755 --- a/ui (gen4)/ui.js +++ b/ui (gen4)/ui.js @@ -72,6 +72,7 @@ $(function(){ } catch(err){ console.error(err) + //throw err return }