From 771b9c9be3fc64c653d8b1e361088bd563d4c5f9 Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Sun, 4 Feb 2018 06:23:31 +0300 Subject: [PATCH] working on store api... Signed-off-by: Alex A. Naanou --- ui (gen4)/features/base.js | 6 +- ui (gen4)/features/collections.js | 31 +-- ui (gen4)/features/config.js | 372 ++++++++++++++++++++++++++++++ ui (gen4)/features/filesystem.js | 12 +- ui (gen4)/features/meta.js | 3 + ui (gen4)/features/sort.js | 2 +- 6 files changed, 402 insertions(+), 24 deletions(-) diff --git a/ui (gen4)/features/base.js b/ui (gen4)/features/base.js index 12969881..5b448d84 100755 --- a/ui (gen4)/features/base.js +++ b/ui (gen4)/features/base.js @@ -748,7 +748,7 @@ core.ImageGridFeatures.Feature({ }) } }], - ['prepareJSONForLoad', + ['prepareIndexForLoad', function(res, json, base_path){ // build data and images... // XXX do we actually need to build stuff here, shouldn't @@ -774,7 +774,7 @@ core.ImageGridFeatures.Feature({ // 2) add/remove on load/save (approach below) // + less to do in real time // - more processing on load/save - //console.warn('STUB: setting image .base_path in .prepareJSONForLoad(..)') + //console.warn('STUB: setting image .base_path in .prepareIndexForLoad(..)') img.forEach(function(_, img){ img.base_path = base_path }) } @@ -1402,7 +1402,7 @@ module.TagsEdit = core.ImageGridFeatures.Feature({ delete res.index.data.tags } }], - ['prepareJSONForLoad', + ['prepareIndexForLoad', function(res, json){ res.data.tags = json.tags || {} diff --git a/ui (gen4)/features/collections.js b/ui (gen4)/features/collections.js index 4dbd0c87..ea7ba991 100755 --- a/ui (gen4)/features/collections.js +++ b/ui (gen4)/features/collections.js @@ -199,27 +199,29 @@ var CollectionActions = actions.Actions({ // } // // XXX revise doc... + // XXX this is almost the same as .store_handlers... get collection_handlers(){ - var handlers = this.__collection_handlers = this.__collection_handlers || {} - - if(Object.keys(handlers).length == 0){ + return this.cache('collection_handlers', function(){ var that = this + var handlers = {} + handlers['data'] = null this.actions.forEach(function(action){ var fmt = that.getActionAttr(action, 'collectionFormat') + handlers[fmt] + && console.warn('Multiple handlers for collection format:', store) if(fmt){ handlers[fmt] = action } }) - } - // cleanup... - if(handlers['data'] == null){ - delete handlers['data'] - } + // cleanup... + if(handlers['data'] == null){ + delete handlers['data'] + } - return handlers - }, + return handlers + }) }, // Collection events... @@ -1303,6 +1305,7 @@ module.Collection = core.ImageGridFeatures.Feature({ tag: 'collections', depends: [ + 'cache', 'base', 'location', 'crop', @@ -1732,7 +1735,7 @@ module.Collection = core.ImageGridFeatures.Feature({ // XXX merge multiple collections... // ...this can be called multiple times pre single load, once // per merged index... - ['prepareJSONForLoad', + ['prepareIndexForLoad', function(res, json, base_path){ // collection index... var collections = {} @@ -1813,9 +1816,9 @@ module.Collection = core.ImageGridFeatures.Feature({ // XXX prepare collection data for loading... Object.keys(collection_data) .forEach(function(gid){ - // XXX would be nice to be able to use .prepareJSONForLoad(..) + // XXX would be nice to be able to use .prepareIndexForLoad(..) // to handle collection internals produced by - // .prepareJSONForLoad(..)... + // .prepareIndexForLoad(..)... // ...would need to pass it the local data... // XXX }) @@ -2935,7 +2938,7 @@ var FileSystemCollectionActions = actions.Actions({ .then(function(res){ // load the collection data... that.collections[title].data = - that.prepareJSONForLoad(res[path]).data + that.prepareIndexForLoad(res[path]).data }) })) }], diff --git a/ui (gen4)/features/config.js b/ui (gen4)/features/config.js index fd28fd2b..f76f05e7 100755 --- a/ui (gen4)/features/config.js +++ b/ui (gen4)/features/config.js @@ -24,6 +24,376 @@ var core = require('features/core') +/*********************************************************************/ + +// XXX should we unify this with the save/load API +var StoreActions = actions.Actions({ + config: { + }, + + // 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.notUserCallable(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??? + 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(){ + this.requestReadyAnnounce() + this + .loadData() + .then(function(){ + this.declareReady() }.bind(this)) }], + // XXX timer??? + // XXX + ['stop', + function(){ this.saveData() }], + ], +}) + + +//--------------------------------------------------------------------- + +var StoreLocalStorageActions = actions.Actions({ + // 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 = 'test-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 = 'test-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 + + + +//--------------------------------------------------------------------- + +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', + }, + + __base_config: null, + + /* XXX + // XXX should this also reload??? + resetConfig: ['- Config/', + function(){ + var base = this.__base_config = this.__base_config || this.config + this.config = Object.create(base) + }], + //*/ + /* XXX use timer events... + toggleAutoStoreConfig: ['File/Store configuration', + toggler.Toggler(null, + function(_, state){ + if(state == null){ + return this.__auto_save_config_timer || 'none' + + } else { + var that = this + var interval = this.config['config-auto-save-interval'] + + // no timer interval set... + if(!interval){ + return false + } + + // this cleans up before 'on' and fully handles 'off' action... + if(this.__auto_save_config_timer != null){ + clearTimeout(this.__auto_save_config_timer) + delete this.__auto_save_config_timer + } + + if(state == 'running' + && interval + && this.__auto_save_config_timer == null){ + + var runner = function(){ + clearTimeout(that.__auto_save_config_timer) + + //that.logger && that.logger.emit('config', 'saving to local storage...') + that.storeConfig() + + var interval = that.config['config-auto-save-interval'] + if(!interval){ + delete that.__auto_save_config_timer + return + } + interval *= 1000 + + that.__auto_save_config_timer = setTimeout(runner, interval) + } + + runner() + } + } + }, + 'running')], + //*/ +}) + +var ConfigStore = +module.ConfigStore = core.ImageGridFeatures.Feature({ + title: '', + doc: '', + + tag: 'store-config', + priority: 80, + depends: [ + 'store-localstorage', + ], + suggested: [ + 'store-fs-json-sync', + ], + + actions: ConfigStoreActions, + + handlers: [ + ['prepareStoreToSave', + function(res){ + // localStorage... + // NOTE: we do not need to clone anything here as this + // will be done by the localStorage handler... + res.store.localStorage.config = this.config + + // XXX sync fs store... + // XXX get better tag... + if(res.store.fsJSONSync){ + // XXX should this include path??? + res.store.fsJSONSync[this.config['config-fs-filename'] || '.ImageGrid.json'] = this.config + } + }], + // NOTE: this is sync for sync stores... + ['storeDataLoaded', + function(store){ + if((store.localStorage || {}).config){ + console.log('--- PRE LOAD CONFIG (test)') + 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 + } + + // XXX sync fs store... + // XXX get better tag... + if((store.fsJSONSync || {}).config){ + // XXX + } + }], + ], +}) + + + /*********************************************************************/ // 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 @@ -128,6 +498,7 @@ module.Config = core.ImageGridFeatures.Feature({ tag: 'config', depends: [ + 'store', ], priority: 80, suggested: [ @@ -142,6 +513,7 @@ module.Config = core.ImageGridFeatures.Feature({ // first to run... ['start.pre', function(){ + console.log('--- PRE LOAD CONFIG') this.logger && this.logger .push('Startup') .emit('loaded', 'config') diff --git a/ui (gen4)/features/filesystem.js b/ui (gen4)/features/filesystem.js index c85b37c5..5772fab1 100755 --- a/ui (gen4)/features/filesystem.js +++ b/ui (gen4)/features/filesystem.js @@ -105,7 +105,7 @@ var IndexFormatActions = actions.Actions({ 2) .prepareIndexForWrite(..) action - takes the output of .json(..) and converts to a format ready for writing/serialization... - - compatible with .prepareJSONForLoad(..) + - compatible with .prepareIndexForLoad(..) - this directly affects the index structure (see: file.writeIndex(..)) @@ -164,11 +164,11 @@ var IndexFormatActions = actions.Actions({ } }], // XXX should this return {} or json??? - prepareJSONForLoad: ['- File/Prepare JSON for loading', + prepareIndexForLoad: ['- File/Prepare JSON for loading', core.doc`Prepare JSON for loading... - .prepareJSONForLoad(json) - .prepareJSONForLoad(json, base_path) + .prepareIndexForLoad(json) + .prepareIndexForLoad(json, base_path) -> data Prepare the loaded JSON data to be loaded via the .load(..) action. @@ -333,7 +333,7 @@ var FileSystemLoaderActions = actions.Actions({ } } - var part = that.prepareJSONForLoad(res[k], k) + var part = that.prepareIndexForLoad(res[k], k) // load the first index... if(index == null){ @@ -1064,7 +1064,7 @@ module.Comments = core.ImageGridFeatures.Feature({ // NOTE: this will skip the 'raw' comment field... // NOTE: we do not change the .json() format here, so we do not // need to do anything special to restore, i.e. no need for - // doing anything on .prepareJSONForLoad(..) + // doing anything on .prepareIndexForLoad(..) ['prepareIndexForWrite', function(res){ var changed = res.changes === true diff --git a/ui (gen4)/features/meta.js b/ui (gen4)/features/meta.js index 3fa086cd..4e955af2 100755 --- a/ui (gen4)/features/meta.js +++ b/ui (gen4)/features/meta.js @@ -135,6 +135,9 @@ core.ImageGridFeatures.Feature('imagegrid-testing', [ // ...this is best included by direct feature dependency. 'index-format', + // XXX testing... + 'store-config', + 'config', 'ui-url-hash', diff --git a/ui (gen4)/features/sort.js b/ui (gen4)/features/sort.js index f62920ba..7b98f1f7 100755 --- a/ui (gen4)/features/sort.js +++ b/ui (gen4)/features/sort.js @@ -564,7 +564,7 @@ module.Sort = core.ImageGridFeatures.Feature({ } }) }], - ['prepareJSONForLoad', + ['prepareIndexForLoad', function(res){ ['sort_order', 'sort_cache'] .forEach(function(attr){