| 
									
										
										
										
											2024-10-27 11:01:12 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * 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 }) |