working on store api...

Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
Alex A. Naanou 2018-02-04 06:23:31 +03:00
parent 1c8a26dfea
commit 771b9c9be3
6 changed files with 402 additions and 24 deletions

View File

@ -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 || {}

View File

@ -199,19 +199,21 @@ 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){
@ -219,7 +221,7 @@ var CollectionActions = actions.Actions({
}
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
})
}))
}],

View File

@ -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:
// {
// <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.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: <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???
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')

View File

@ -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

View File

@ -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',

View File

@ -564,7 +564,7 @@ module.Sort = core.ImageGridFeatures.Feature({
}
})
}],
['prepareJSONForLoad',
['prepareIndexForLoad',
function(res){
['sort_order', 'sort_cache']
.forEach(function(attr){