| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-08-21 02:19:24 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var features = require('lib/features') | 
					
						
							| 
									
										
										
										
											2016-11-28 02:25:39 +03:00
										 |  |  | var toggler = require('lib/toggler') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var core = require('features/core') | 
					
						
							| 
									
										
										
										
											2016-04-30 03:38:52 +03:00
										 |  |  | var widgets = require('features/ui-widgets') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var overlay = require('lib/widget/overlay') | 
					
						
							|  |  |  | var browse = require('lib/widget/browse') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | // url history...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var URLHistoryActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'url-history-push-up-on-open': false, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// values:
 | 
					
						
							|  |  |  | 		// 	-1		- no limit.
 | 
					
						
							|  |  |  | 		// 	0		- disabled
 | 
					
						
							|  |  |  | 		// 	1+		- length of history
 | 
					
						
							|  |  |  | 		'url-history-length': 100, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__url_history: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		url: {
 | 
					
						
							|  |  |  | 	// 			open: <action-name> | <function>,
 | 
					
						
							|  |  |  | 	// 			check: <action-name> | <function>,
 | 
					
						
							|  |  |  | 	// 		},
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: last opened url is last...
 | 
					
						
							|  |  |  | 	// NOTE: though functions are supported they are not recommended as
 | 
					
						
							|  |  |  | 	// 		we can not stringify them to JSON...
 | 
					
						
							|  |  |  | 	get url_history(){ | 
					
						
							| 
									
										
										
										
											2017-01-02 01:23:33 +03:00
										 |  |  | 		return this.hasOwnProperty('__url_history') ? this.__url_history : undefined }, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	set url_history(value){ | 
					
						
							| 
									
										
										
										
											2017-01-02 01:23:33 +03:00
										 |  |  | 		this.__url_history = value }, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clone: [function(full){ | 
					
						
							|  |  |  | 		return function(res){ | 
					
						
							|  |  |  | 			res.url_history = null | 
					
						
							|  |  |  | 			if(full && this.url_history){ | 
					
						
							|  |  |  | 				res.url_history = JSON.parse(JSON.stringify(this.url_history)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setTopURLHistory: ['- History/', | 
					
						
							|  |  |  | 		function(url){ | 
					
						
							|  |  |  | 			var data = this.url_history[url] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(data == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			delete this.url_history[url] | 
					
						
							|  |  |  | 			this.url_history[url] = data | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 	// NOTE: if clear is not true then this will update a history item 
 | 
					
						
							|  |  |  | 	// 		rather than fully rewriting it...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	pushURLToHistory: ['- History/', | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 		function(url, open, check, clear){ | 
					
						
							| 
									
										
										
										
											2016-12-11 04:54:28 +03:00
										 |  |  | 			url = url || this.location.path | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var l = this.config['url-history-length'] || -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(l == 0){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.url_history = this.url_history || {} | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 			var item = !clear ? (this.url_history[url] || {}) : {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			open = item.open = open || this.location.method | 
					
						
							|  |  |  | 			check = item.check = check || 'checkPath' | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// remove the old value...
 | 
					
						
							|  |  |  | 			if(url in this.url_history && this.config['url-history-push-up-on-open']){ | 
					
						
							|  |  |  | 				delete this.url_history[url] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// push url to history...
 | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 			this.url_history[url] = item | 
					
						
							|  |  |  | 			/*this.url_history[url] = { | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				open: open, | 
					
						
							|  |  |  | 				check: check, | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 			}*/ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// update history length...
 | 
					
						
							|  |  |  | 			if(l > 0){ | 
					
						
							|  |  |  | 				var k = Object.keys(this.url_history) | 
					
						
							|  |  |  | 				while(k.length > l){ | 
					
						
							|  |  |  | 					// drop first url in order -- last added...
 | 
					
						
							|  |  |  | 					this.dropURLFromHistory(k[0]) | 
					
						
							|  |  |  | 					var k = Object.keys(this.url_history) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 	// NOTE: url can be an index, 0 being the last url added to history;
 | 
					
						
							|  |  |  | 	// 		negative values are also supported.
 | 
					
						
							|  |  |  | 	dropURLFromHistory: ['- History/',  | 
					
						
							|  |  |  | 		function(url){ | 
					
						
							|  |  |  | 			this.url_history = this.url_history || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			url = typeof(url) == typeof(123) ?  | 
					
						
							|  |  |  | 				Object.keys(this.url_history).reverse().slice(url)[0] | 
					
						
							|  |  |  | 				: url | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(url){ | 
					
						
							|  |  |  | 				delete this.url_history[url] | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 	checkURLFromHistory: ['- History/', | 
					
						
							|  |  |  | 		function(url){ | 
					
						
							|  |  |  | 			this.url_history = this.url_history || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			url = typeof(url) == typeof(123) ?  | 
					
						
							|  |  |  | 				Object.keys(this.url_history).reverse().slice(url)[0] | 
					
						
							|  |  |  | 				: url | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// if we have a check action then use it...
 | 
					
						
							|  |  |  | 			if(url && this.url_history[url] && this.url_history[url].check){ | 
					
						
							|  |  |  | 				var check = this.url_history[url].check | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(typeof(check) == typeof('str')){ | 
					
						
							|  |  |  | 					return this[check](url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					return check(url) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// no way to check so we do not know...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2016-02-17 20:10:31 +03:00
										 |  |  | 				return null | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-11-28 02:25:39 +03:00
										 |  |  | 	toggleURLPinned: ['History/', | 
					
						
							|  |  |  | 		toggler.Toggler( | 
					
						
							|  |  |  | 			function(){ return this.location.path }, | 
					
						
							|  |  |  | 			function(url, action){ | 
					
						
							|  |  |  | 				var e = this.url_history[url] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// get state...
 | 
					
						
							|  |  |  | 				if(action == null){ | 
					
						
							|  |  |  | 					return e && e.pinned ? 'on' : 'off' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// change state -> 'on'...
 | 
					
						
							|  |  |  | 				} else if(action == 'on'){ | 
					
						
							|  |  |  | 					e.pinned = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// change state -> 'off'...
 | 
					
						
							|  |  |  | 				} else if(action == 'off'){ | 
					
						
							|  |  |  | 					delete e.pinned | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			},  | 
					
						
							|  |  |  | 			['off', 'on'])], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	openURLFromHistory: ['- History/', | 
					
						
							|  |  |  | 		function(url, open){ | 
					
						
							|  |  |  | 			this.url_history = this.url_history || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			url = typeof(url) == typeof(123) ?  | 
					
						
							|  |  |  | 				Object.keys(this.url_history).reverse().slice(url)[0] | 
					
						
							|  |  |  | 				: url | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(url && !open && this.url_history[url] && this.url_history[url].open){ | 
					
						
							|  |  |  | 				open = this.url_history[url].open | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(url && open){ | 
					
						
							|  |  |  | 				if(open instanceof Function){ | 
					
						
							|  |  |  | 					return open(url) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					return this[open](url) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 	clearURLHistory: ['History/',  | 
					
						
							|  |  |  | 		function(){ this.url_history = null }], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var URLHistory =  | 
					
						
							|  |  |  | module.URLHistory = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'url-history', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'location', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-url-history', | 
					
						
							|  |  |  | 		'url-history-local-storage', | 
					
						
							|  |  |  | 		'url-history-fs-writer', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: URLHistoryActions, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX should this be responsible for saving and loading of .location???
 | 
					
						
							|  |  |  | // 		...on one hand it's part of the history, on the other it's part 
 | 
					
						
							|  |  |  | // 		of file loader...
 | 
					
						
							|  |  |  | var URLHistoryLocalStorageActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'url-history-local-storage-key': 'url-history', | 
					
						
							|  |  |  | 		'url-history-loaded-local-storage-key': 'url-history-loaded', | 
					
						
							| 
									
										
										
										
											2015-12-29 01:02:57 +03:00
										 |  |  | 		'url-history-load-current': true, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	__url_history: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// load url history...
 | 
					
						
							|  |  |  | 	get url_history(){ | 
					
						
							|  |  |  | 		// get the attr value...
 | 
					
						
							|  |  |  | 		if(this.hasOwnProperty('__url_history') && this.__url_history){ | 
					
						
							|  |  |  | 			return this.__url_history | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var key = this.config['url-history-local-storage-key'] | 
					
						
							|  |  |  | 		if(key){ | 
					
						
							|  |  |  | 			// get the storage value...
 | 
					
						
							|  |  |  | 			// if not local __url_history and we are configured, load from storage...
 | 
					
						
							|  |  |  | 			if(this.config && key){ | 
					
						
							|  |  |  | 				var history = localStorage[key] | 
					
						
							|  |  |  | 				if(history){ | 
					
						
							|  |  |  | 					try{ | 
					
						
							|  |  |  | 						this.__url_history = JSON.parse(history) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					} catch(e) { | 
					
						
							|  |  |  | 						delete localStorage[key] | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return this.hasOwnProperty('__url_history') ? this.__url_history : null | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	set url_history(value){ | 
					
						
							|  |  |  | 		this.__url_history = value | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var key = this.config['url-history-local-storage-key'] | 
					
						
							|  |  |  | 		if(key){ | 
					
						
							|  |  |  | 			localStorage[key] = JSON.stringify(value)  | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Disable localStorage in child...
 | 
					
						
							|  |  |  | 	clone: [function(){ | 
					
						
							|  |  |  | 		return function(res){ | 
					
						
							|  |  |  | 			res.config['url-history-local-storage-key'] = null | 
					
						
							|  |  |  | 			res.config['url-history-loaded-local-storage-key'] = null | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	saveURLHistory: ['History/', | 
					
						
							|  |  |  | 		function(){ | 
					
						
							|  |  |  | 			var history = this.config['url-history-local-storage-key'] | 
					
						
							|  |  |  | 			if(history != null){ | 
					
						
							|  |  |  | 				localStorage[history] =  | 
					
						
							|  |  |  | 					JSON.stringify(this.url_history)  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.saveLocation() | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 	saveLocation: ['History/', | 
					
						
							|  |  |  | 		function(){ | 
					
						
							|  |  |  | 			var loaded = this.config['url-history-loaded-local-storage-key'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(loaded != null){ | 
					
						
							|  |  |  | 				localStorage[loaded] = JSON.stringify(this.location || {}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 	loadLastSavedBasePath: ['- History/', | 
					
						
							|  |  |  | 		function(){ | 
					
						
							|  |  |  | 			var loaded = this.config['url-history-loaded-local-storage-key'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(loaded && localStorage[loaded]){ | 
					
						
							|  |  |  | 				var l = JSON.parse(localStorage[loaded]) | 
					
						
							| 
									
										
										
										
											2015-12-29 01:02:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if(l.current != null && this.config['url-history-load-current']){ | 
					
						
							|  |  |  | 					this.one('load', function(){ | 
					
						
							|  |  |  | 						this.current = l.current | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				this.openURLFromHistory(l.path, l.method) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.openURLFromHistory(0) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var URLHistoryLocalStorage =  | 
					
						
							|  |  |  | module.URLHistoryLocalStorage = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'url-history-local-storage', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							|  |  |  | 		'url-history', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | 	isApplicable: function(){  | 
					
						
							|  |  |  | 		return typeof(localStorage) != 'undefined'  | 
					
						
							|  |  |  | 			&& localStorage != null }, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: URLHistoryLocalStorageActions, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// NOTE: loading is done by the .url_history prop...
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		['start', | 
					
						
							|  |  |  | 			function(){ this.loadLastSavedBasePath() }],  | 
					
						
							|  |  |  | 		['stop.pre', | 
					
						
							|  |  |  | 			function(){ this.saveURLHistory() }],  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// save base_path...
 | 
					
						
							| 
									
										
										
										
											2015-12-29 01:02:57 +03:00
										 |  |  | 		['load',  | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			function(){ this.location && this.location.path && this.saveLocation() }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// save...
 | 
					
						
							|  |  |  | 		['pushURLToHistory dropURLFromHistory setTopURLHistory',  | 
					
						
							|  |  |  | 			function(){  | 
					
						
							|  |  |  | 				this.saveURLHistory() | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// clear...
 | 
					
						
							|  |  |  | 		['clearURLHistory.pre', | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				delete this.__url_history | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var history = this.config['url-history-local-storage-key'] | 
					
						
							|  |  |  | 				if(history){ | 
					
						
							|  |  |  | 					delete localStorage[history] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var loaded = this.config['url-history-loaded-local-storage-key'] | 
					
						
							|  |  |  | 				if(loaded){ | 
					
						
							|  |  |  | 					delete localStorage[loaded] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 18:43:29 +03:00
										 |  |  | // XXX
 | 
					
						
							|  |  |  | var URLHistoryFSWriter =  | 
					
						
							|  |  |  | module.URLHistoryFSWriter = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'url-history-fs-writer', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'fs-writer', | 
					
						
							|  |  |  | 		'url-history-local-storage', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config: { | 
					
						
							| 
									
										
										
										
											2016-03-12 02:16:32 +03:00
										 |  |  | 		// XXX should we add a toggler action to toggle this?
 | 
					
						
							| 
									
										
										
										
											2016-03-08 18:43:29 +03:00
										 |  |  | 		'url-history-push-to-top-on-save': false, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		['saveIndex', | 
					
						
							| 
									
										
										
										
											2016-06-04 20:50:37 +03:00
										 |  |  | 			function(res){  | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				res.then(function(l){ | 
					
						
							|  |  |  | 					// push saved to top...
 | 
					
						
							|  |  |  | 					if(that.config['url-history-push-to-top-on-save']){ | 
					
						
							|  |  |  | 						that.pushURLToHistory(l.path, l.method) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// update...
 | 
					
						
							| 
									
										
										
										
											2016-03-08 18:43:29 +03:00
										 |  |  | 					} else { | 
					
						
							| 
									
										
										
										
											2016-06-04 20:50:37 +03:00
										 |  |  | 						var e = that.url_history[l.path] | 
					
						
							|  |  |  | 						if(e != null){ | 
					
						
							|  |  |  | 							e.open = l.method | 
					
						
							|  |  |  | 							that.saveURLHistory() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							that.pushURLToHistory(l.path, l.method) | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-03-08 18:43:29 +03:00
										 |  |  | 					} | 
					
						
							| 
									
										
										
										
											2016-06-04 20:50:37 +03:00
										 |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2016-03-08 18:43:29 +03:00
										 |  |  | 			}],  | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var URLHistoryUIActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		// Indicate when to remove striked items from url history list
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// Supported values:
 | 
					
						
							|  |  |  | 		// 	- true | undefined		- always remove
 | 
					
						
							|  |  |  | 		// 	- flase					- never remove
 | 
					
						
							|  |  |  | 		// 	- [ 'open', 'close' ]	- explicitly select event
 | 
					
						
							|  |  |  | 		'url-history-list-clear': ['open', 'close'], | 
					
						
							| 
									
										
										
										
											2017-01-04 05:15:56 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// If true pushing the pin item button will also focus the item
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: Both settings have their pluses and minuses:
 | 
					
						
							|  |  |  | 		// 		enabled (true)
 | 
					
						
							|  |  |  | 		// 			+ will keep the item on screen
 | 
					
						
							|  |  |  | 		// 			- will lose context
 | 
					
						
							|  |  |  | 		// 		disabled (false)
 | 
					
						
							|  |  |  | 		// 			+ will keep context
 | 
					
						
							|  |  |  | 		// 			- will lose the item from view if list is long
 | 
					
						
							|  |  |  | 		'url-history-focus-on-pin': false, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// XXX use svg icons for buttons...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 	listURLHistory: ['History|File/Location history...', | 
					
						
							| 
									
										
										
										
											2016-04-30 03:38:52 +03:00
										 |  |  | 		widgets.makeUIDialog(function(){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 			var parent = this.preventClosing ? this.preventClosing() : null | 
					
						
							|  |  |  | 			var cur = this.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 			// caches...
 | 
					
						
							|  |  |  | 			var fs_state = {} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var to_remove = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// remove stirked out elements...
 | 
					
						
							|  |  |  | 			var removeStriked = function(evt){ | 
					
						
							|  |  |  | 				var rem = that.config['url-history-list-clear'] | 
					
						
							|  |  |  | 				if(rem == false || rem != null && rem.indexOf(evt) < 0){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				to_remove.forEach(function(e){ | 
					
						
							|  |  |  | 					that.dropURLFromHistory(e) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				to_remove = [] | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 			var makeHistoryList = function(fs_state){ | 
					
						
							|  |  |  | 				fs_state = fs_state || {} | 
					
						
							|  |  |  | 				var history = Object.keys(that.url_history).reverse() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// pinned items...
 | 
					
						
							|  |  |  | 				var list = history | 
					
						
							|  |  |  | 					.filter(function(p){ | 
					
						
							|  |  |  | 						// NOTE: yes direct access is faster, but 
 | 
					
						
							|  |  |  | 						// 		calling the toggler (common API) here
 | 
					
						
							|  |  |  | 						// 		will isolate the level knowledge to a
 | 
					
						
							|  |  |  | 						// 		single point which will simplify things
 | 
					
						
							|  |  |  | 						// 		if anything changes...
 | 
					
						
							|  |  |  | 						//return that.url_history[p].pinned 
 | 
					
						
							|  |  |  | 						return that.toggleURLPinned(p, '?') == 'on' | 
					
						
							|  |  |  | 					})  | 
					
						
							|  |  |  | 					.map(function(p){ | 
					
						
							|  |  |  | 						// prevent from drawing again...
 | 
					
						
							|  |  |  | 						history.splice(history.indexOf(p), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// see of we need a full refresh or use the 
 | 
					
						
							|  |  |  | 						// last fs_state...
 | 
					
						
							|  |  |  | 						if(p in fs_state){ | 
					
						
							|  |  |  | 							// XXX need to make this faster...
 | 
					
						
							|  |  |  | 							var d = fs_state[p] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							var d = !that.checkURLFromHistory(p) | 
					
						
							|  |  |  | 							fs_state[p] = d | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return [p, | 
					
						
							|  |  |  | 							[p == cur ? 'highlighted selected': '', 'pinned'].join(' '), | 
					
						
							|  |  |  | 							{ disabled: d } | 
					
						
							|  |  |  | 						] | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// separator...
 | 
					
						
							|  |  |  | 				list.push([ '---', 'pinned-separator', {}]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// history...
 | 
					
						
							|  |  |  | 				list = list.concat(history  | 
					
						
							|  |  |  | 					// NOTE: this might get a little slow for 
 | 
					
						
							|  |  |  | 					// 		very large sets...
 | 
					
						
							|  |  |  | 					.map(function(p){ | 
					
						
							|  |  |  | 						// see of we need a full refresh or use the 
 | 
					
						
							|  |  |  | 						// last fs_state...
 | 
					
						
							|  |  |  | 						if(p in fs_state){ | 
					
						
							|  |  |  | 							// XXX need to make this faster...
 | 
					
						
							|  |  |  | 							var d = fs_state[p] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							var d = !that.checkURLFromHistory(p) | 
					
						
							|  |  |  | 							fs_state[p] = d | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						return [p,  | 
					
						
							|  |  |  | 							p == cur ? 'highlighted selected': '', | 
					
						
							|  |  |  | 							{disabled: d}, | 
					
						
							|  |  |  | 						] | 
					
						
							|  |  |  | 					})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// history is empty...
 | 
					
						
							| 
									
										
										
										
											2017-01-12 05:26:09 +03:00
										 |  |  | 				// NOTE: the length here is 1 because we need to account
 | 
					
						
							|  |  |  | 				// 		for the separator...
 | 
					
						
							|  |  |  | 				if(list.length == 1){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 					list.push([ | 
					
						
							|  |  |  | 						'No history...',  | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							disabled: true,  | 
					
						
							|  |  |  | 							buttons: [], | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return list | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-01-23 20:49:05 +03:00
										 |  |  | 			// this will take care of any number of child dialogs...
 | 
					
						
							|  |  |  | 			// XXX should this be generic???
 | 
					
						
							|  |  |  | 			var onOpen = function(){ | 
					
						
							|  |  |  | 				// we are the top dialog --> close...
 | 
					
						
							|  |  |  | 				if(that.modal.client === o){ | 
					
						
							|  |  |  | 					o.close()  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// child dialog, ask to close us when opening...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					that.modal.client.open(onOpen) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 			var o = browse.makeLister(null,  | 
					
						
							|  |  |  | 				function(path, make){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 					makeHistoryList() | 
					
						
							|  |  |  | 						.forEach(function(elem){ | 
					
						
							|  |  |  | 							var e = elem.slice() | 
					
						
							|  |  |  | 							var path = e.shift() | 
					
						
							|  |  |  | 							var cfg = e.pop() | 
					
						
							|  |  |  | 							var cls = e.pop() || '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							make(path, cfg) | 
					
						
							|  |  |  | 								.attr('path', path) | 
					
						
							|  |  |  | 								.addClass(cls) | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 				// add item buttons...
 | 
					
						
							|  |  |  | 				{ itemButtons: [ | 
					
						
							| 
									
										
										
										
											2017-01-23 20:49:05 +03:00
										 |  |  | 						['<span class="show-on-hover">↗</span>',  | 
					
						
							|  |  |  | 							function(p){ o.browsePath(p) }], | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 						// move to top...
 | 
					
						
							|  |  |  | 						['♦',  | 
					
						
							|  |  |  | 							function(p){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:41:46 +03:00
										 |  |  | 								that.setTopURLHistory(p) | 
					
						
							|  |  |  | 								o.redraw(p) | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:41:46 +03:00
										 |  |  | 								/* XXX this is a tad faster, is the added  | 
					
						
							|  |  |  | 								// 		complexity worth it??
 | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 								var cur = this.filter('"'+p+'"', false) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 								var top = cur.hasClass('pinned') ? | 
					
						
							|  |  |  | 									this.filter('*', false).first() | 
					
						
							|  |  |  | 									: this.filter('*', false) | 
					
						
							|  |  |  | 										.filter(':not(.pinned)').first() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 								if(!top.is(cur)){ | 
					
						
							|  |  |  | 									top.before(cur) | 
					
						
							|  |  |  | 									that.setTopURLHistory(p) | 
					
						
							|  |  |  | 								} | 
					
						
							| 
									
										
										
										
											2017-01-04 16:41:46 +03:00
										 |  |  | 								//*/
 | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 							}], | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 						// pin to top...
 | 
					
						
							|  |  |  | 						// XXX should this be standard functionality???
 | 
					
						
							|  |  |  | 						['<span class="pin-set">●</span>' | 
					
						
							|  |  |  | 						+'<span class="pin-unset">○</span>',  | 
					
						
							| 
									
										
										
										
											2017-01-13 08:42:47 +03:00
										 |  |  | 							function(p, cur){ | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 								// change state...
 | 
					
						
							|  |  |  | 								// pinned...
 | 
					
						
							|  |  |  | 								if(cur.hasClass('pinned')){ | 
					
						
							|  |  |  | 									cur.removeClass('pinned') | 
					
						
							| 
									
										
										
										
											2016-11-28 02:25:39 +03:00
										 |  |  | 									that.toggleURLPinned(p, 'off') | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 								// not pinned...
 | 
					
						
							|  |  |  | 								} else { | 
					
						
							|  |  |  | 									cur.addClass('pinned') | 
					
						
							| 
									
										
										
										
											2016-11-28 02:25:39 +03:00
										 |  |  | 									that.toggleURLPinned(p, 'on') | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 								} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 05:15:56 +03:00
										 |  |  | 								// focus...
 | 
					
						
							|  |  |  | 								that.config['url-history-focus-on-pin'] | 
					
						
							|  |  |  | 									&& o.select(cur) | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 05:15:56 +03:00
										 |  |  | 								// place...
 | 
					
						
							| 
									
										
										
										
											2017-01-04 05:50:00 +03:00
										 |  |  | 								o.redraw() | 
					
						
							| 
									
										
										
										
											2016-11-26 20:42:47 +03:00
										 |  |  | 							}], | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 						// mark for removal...
 | 
					
						
							| 
									
										
										
										
											2017-01-15 04:36:48 +03:00
										 |  |  | 						browse.buttons.markForRemoval(to_remove) | 
					
						
							| 
									
										
										
										
											2016-04-30 19:59:29 +03:00
										 |  |  | 					], | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2016-04-30 03:38:52 +03:00
										 |  |  | 				.open(function(evt, path){  | 
					
						
							|  |  |  | 					removeStriked('open') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					o.parent.close()  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// close the parent ui...
 | 
					
						
							|  |  |  | 					parent  | 
					
						
							|  |  |  | 						&& parent.close  | 
					
						
							|  |  |  | 						&& parent.close() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					that.openURLFromHistory(path) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.on('close', function(){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					removeStriked('close') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					parent  | 
					
						
							|  |  |  | 						&& parent.focus  | 
					
						
							|  |  |  | 						&& parent.focus() | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 			// Monkey-patch: fast redraw...
 | 
					
						
							| 
									
										
										
										
											2017-01-04 05:50:00 +03:00
										 |  |  | 			//
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 			// NOTE: this is substantially faster than calling .update()
 | 
					
						
							|  |  |  | 			// 		because this will only change positions of a view dom 
 | 
					
						
							|  |  |  | 			// 		elements while .update(..) will redraw the while thing...
 | 
					
						
							|  |  |  | 			// NOTE: this also uses fs_state for caching...
 | 
					
						
							| 
									
										
										
										
											2017-01-04 16:41:46 +03:00
										 |  |  | 			o.redraw = function(path){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 				var list = o.dom.find('.list') | 
					
						
							|  |  |  | 				makeHistoryList(fs_state) | 
					
						
							|  |  |  | 					.forEach(function(elem, i){ | 
					
						
							| 
									
										
										
										
											2017-01-04 16:41:46 +03:00
										 |  |  | 						if(path && path != elem[0]){ | 
					
						
							|  |  |  | 							return | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2017-01-04 16:25:00 +03:00
										 |  |  | 						// move...
 | 
					
						
							|  |  |  | 						if(list.children().eq(i).attr('path') != elem[0]){ | 
					
						
							|  |  |  | 							list.children().eq(i) | 
					
						
							|  |  |  | 								.before(list | 
					
						
							|  |  |  | 									.find('[path="'+elem[0]+'"]')) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 		   		return this | 
					
						
							| 
									
										
										
										
											2017-01-04 05:50:00 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-23 20:49:05 +03:00
										 |  |  | 			// handle 'O' button to browse path...
 | 
					
						
							|  |  |  | 			o.browsePath = function(p){ | 
					
						
							|  |  |  | 				that.browsePath(p || this.selected).open(onOpen) } | 
					
						
							|  |  |  | 			// clone the bindings so as not to mess up the global browser...
 | 
					
						
							|  |  |  | 			o.keybindings = JSON.parse(JSON.stringify(o.keybindings)) | 
					
						
							|  |  |  | 			o.keyboard.handler('General', 'O', 'browsePath') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			return o | 
					
						
							| 
									
										
										
										
											2016-04-30 03:38:52 +03:00
										 |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var URLHistoryUI =  | 
					
						
							|  |  |  | module.URLHistoryUI = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-url-history', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							|  |  |  | 		'url-history', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 	actions: URLHistoryUIActions, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |