| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | define(function(require){ var module = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX this should not be imported!!!
 | 
					
						
							|  |  |  | // 		...something wrong with requirejs(..)
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	var fse = requirejs('fs-extra') | 
					
						
							|  |  |  | 	var pathlib = requirejs('path') | 
					
						
							|  |  |  | 	var glob = requirejs('glob') | 
					
						
							| 
									
										
										
										
											2016-05-28 16:29:57 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 16:12:10 +03:00
										 |  |  | 	var file = require('imagegrid/file') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 16:12:10 +03:00
										 |  |  | var data = require('imagegrid/data') | 
					
						
							|  |  |  | var images = require('imagegrid/images') | 
					
						
							| 
									
										
										
										
											2015-12-29 01:40:10 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | var util = require('lib/util') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var features = require('lib/features') | 
					
						
							| 
									
										
										
										
											2016-05-03 01:43:43 +03:00
										 |  |  | var keyboard = require('lib/keyboard') | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var core = require('features/core') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | var widgets = require('features/ui-widgets') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | var overlay = require('lib/widget/overlay') | 
					
						
							|  |  |  | var browse = require('lib/widget/browse') | 
					
						
							| 
									
										
										
										
											2016-01-09 04:59:57 +03:00
										 |  |  | var browseWalk = require('lib/widget/browse-walk') | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | if(typeof(process) != 'undefined'){ | 
					
						
							|  |  |  | 	var copy = file.denodeify(fse.copy) | 
					
						
							|  |  |  | 	var ensureDir = file.denodeify(fse.ensureDir) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var IndexFormat =  | 
					
						
							|  |  |  | module.IndexFormat = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'index-format', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'index-dir': '.ImageGrid', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		'preview-sizes': [ | 
					
						
							|  |  |  | 			75, | 
					
						
							|  |  |  | 			150, | 
					
						
							|  |  |  | 			350, | 
					
						
							|  |  |  | 			900, | 
					
						
							|  |  |  | 			1000, | 
					
						
							|  |  |  | 			1280, | 
					
						
							|  |  |  | 			1920, | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Supported fields:
 | 
					
						
							|  |  |  | 		// 	$INDEX			- index directory name
 | 
					
						
							|  |  |  | 		// 	$RESOLUTION		- preview resolution
 | 
					
						
							|  |  |  | 		// 	$GID			- image GID
 | 
					
						
							|  |  |  | 		// 	$NAME			- image name
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// XXX make this used in loader too...
 | 
					
						
							|  |  |  | 		'preview-path-template': '${INDEX}/${RESOLUTION}px/${GID} - ${NAME}.jpg', | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemInfoActions = actions.Actions({ | 
					
						
							|  |  |  | 	getImagePath: ['- System/', | 
					
						
							|  |  |  | 		function(gid, type){ | 
					
						
							|  |  |  | 			gid = this.data.getImage(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var img = this.images[gid] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return pathlib.join(img.base_path || this.location.path, img.path) | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemInfo =  | 
					
						
							|  |  |  | module.FileSystemInfo = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-info', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'location', | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 		'index-format', | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemInfoActions, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isApplicable: function(){  | 
					
						
							|  |  |  | 		return this.runtime == 'node' || this.runtime == 'nw' }, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // Loader... 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // NOTE: this will also manage .location.from
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | var FileSystemLoaderActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		'image-file-pattern': '*+(jpg|jpeg|png|JPG|JPEG|PNG)', | 
					
						
							| 
									
										
										
										
											2016-03-30 15:24:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 		'image-file-read-stat': true, | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 		'image-file-skip-previews': false, | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-30 15:24:01 +03:00
										 |  |  | 		// XXX if true and multiple indexes found, load only the first 
 | 
					
						
							|  |  |  | 		// 		without merging...
 | 
					
						
							|  |  |  | 		'load-first-index-only': false, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 	// XXX should this be more general???
 | 
					
						
							|  |  |  | 	reloadState: ['File/Reload viewer state...', | 
					
						
							|  |  |  | 		function(){ | 
					
						
							|  |  |  | 			if(this.location  | 
					
						
							|  |  |  | 					&& this.location.method  | 
					
						
							|  |  |  | 					&& this.location.path){ | 
					
						
							|  |  |  | 				return this[this.location.method](this.location.path) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// XXX is this a hack???
 | 
					
						
							|  |  |  | 	// XXX need a more generic form...
 | 
					
						
							|  |  |  | 	checkPath: ['- File/', | 
					
						
							|  |  |  | 		function(path){ return fse.existsSync(path) }], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-07 02:02:42 +03:00
										 |  |  | 	// 
 | 
					
						
							|  |  |  | 	// This maintains:
 | 
					
						
							|  |  |  | 	// 	.location.loaded		- list of loaded URLs...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// NOTE: when passed no path this will not do anything...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 	// NOTE: this will add a .from field to .location, this will indicate
 | 
					
						
							|  |  |  | 	// 		the date starting from which saves are loaded.
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 	// XXX BUG: if no <keyword>.json files exist this will not load 
 | 
					
						
							|  |  |  | 	// 		anything...
 | 
					
						
							|  |  |  | 	// 		To reproduce:
 | 
					
						
							|  |  |  | 	// 			.loadImages(..)
 | 
					
						
							|  |  |  | 	// 			.saveIndex()
 | 
					
						
							|  |  |  | 	// 			.loadIndex(..)
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// XXX add a symmetric equivalent to .prepareIndexForWrite(..) so as 
 | 
					
						
							|  |  |  | 	// 		to enable features to load their data...
 | 
					
						
							|  |  |  | 	// XXX look inside...
 | 
					
						
							|  |  |  | 	loadIndex: ['- File/Load index', | 
					
						
							| 
									
										
										
										
											2016-05-03 19:14:46 +03:00
										 |  |  | 		function(path, from_date, logger){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(path == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-03 19:14:46 +03:00
										 |  |  | 			if(from_date && from_date.emit != null){ | 
					
						
							|  |  |  | 				logger = from_date | 
					
						
							|  |  |  | 				from_date = null | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// XXX get a logger...
 | 
					
						
							|  |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX make this load incrementally (i.e. and EventEmitter
 | 
					
						
							|  |  |  | 			// 		a-la glob)....
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			//file.loadIndex(path, this.config['index-dir'], logger)
 | 
					
						
							| 
									
										
										
										
											2016-05-03 19:14:46 +03:00
										 |  |  | 			return file.loadIndex(path, this.config['index-dir'], from_date, logger) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				.then(function(res){ | 
					
						
							|  |  |  | 					// XXX if res is empty load raw...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// XXX use the logger...
 | 
					
						
							|  |  |  | 					//console.log('FOUND INDEXES:', Object.keys(res).length)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// skip nested paths...
 | 
					
						
							|  |  |  | 					// XXX make this optional...
 | 
					
						
							|  |  |  | 					// XXX this is best done BEFORE we load all the 
 | 
					
						
							|  |  |  | 					// 		indexes, e.g. in .loadIndex(..)
 | 
					
						
							|  |  |  | 					var paths = Object.keys(res) | 
					
						
							|  |  |  | 					var skipped = [] | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 					paths | 
					
						
							|  |  |  | 						.sort() | 
					
						
							|  |  |  | 						.forEach(function(p){ | 
					
						
							|  |  |  | 							// already removed...
 | 
					
						
							|  |  |  | 							if(skipped.indexOf(p) >= 0){ | 
					
						
							|  |  |  | 								return | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 							paths | 
					
						
							|  |  |  | 								// get all paths that fully contain p...
 | 
					
						
							|  |  |  | 								.filter(function(o){ | 
					
						
							|  |  |  | 									return o != p && o.indexOf(p) == 0 | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 								// drop all longer paths...
 | 
					
						
							|  |  |  | 								.forEach(function(e){ | 
					
						
							|  |  |  | 									skipped.push(e) | 
					
						
							|  |  |  | 									delete res[e] | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					//console.log('SKIPPING NESTED:', skipped.length)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					var index | 
					
						
							|  |  |  | 					var base_path | 
					
						
							|  |  |  | 					var loaded = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// NOTE: res may contain multiple indexes...
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 					//for(var k in res){
 | 
					
						
							|  |  |  | 					for(var i=0; i < paths.length; i++){ | 
					
						
							|  |  |  | 						var k = paths[i] | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						// skip empty indexes...
 | 
					
						
							|  |  |  | 						// XXX should we rebuild  or list here???
 | 
					
						
							|  |  |  | 						if(res[k].data == null || res[k].images == null){ | 
					
						
							|  |  |  | 							continue | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						var part = file.buildIndex(res[k], k) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// load the first index...
 | 
					
						
							|  |  |  | 						if(index == null){ | 
					
						
							|  |  |  | 							// XXX use the logger...
 | 
					
						
							|  |  |  | 							//console.log('LOADING:', k, res)
 | 
					
						
							|  |  |  | 							logger && logger.emit('base index', k, res) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							index = part | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// merge indexes...
 | 
					
						
							|  |  |  | 						// XXX need to skip sub-indexes in the same sub-tree...
 | 
					
						
							|  |  |  | 						// 		...skip any path that fully contains an 
 | 
					
						
							|  |  |  | 						// 		already loaded path..
 | 
					
						
							|  |  |  | 						// XXX load data in chunks rather than merge...
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							//console.log('MERGING:', k, part)
 | 
					
						
							|  |  |  | 							logger && logger.emit('merge index', k, res) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// merge...
 | 
					
						
							|  |  |  | 							index.data.join(part.data) | 
					
						
							|  |  |  | 							index.images.join(part.images) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						loaded.push(k) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// XXX do a better merge and remove this...
 | 
					
						
							|  |  |  | 						// 		...we either need to lazy-load clustered indexes
 | 
					
						
							|  |  |  | 						// 		or merge, in both cases base_path should reflet
 | 
					
						
							|  |  |  | 						// 		the fact that we have multiple indexes...
 | 
					
						
							| 
									
										
										
										
											2016-03-30 15:24:01 +03:00
										 |  |  | 						if(that.config['load-first-index-only']){ | 
					
						
							|  |  |  | 							break | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					logger && logger.emit('load index', index) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 02:14:05 +03:00
										 |  |  | 					that.load(index) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					that.__location = { | 
					
						
							| 
									
										
										
										
											2016-05-07 02:02:42 +03:00
										 |  |  | 						path: path, | 
					
						
							|  |  |  | 						loaded: loaded, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 						method: 'loadIndex', | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if(from_date){ | 
					
						
							|  |  |  | 						that.__location.from = from_date | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 	// Get image(s) previews...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Load current image previews...
 | 
					
						
							|  |  |  | 	//	.getPreviews()
 | 
					
						
							|  |  |  | 	//	.getPreviews('current')
 | 
					
						
							|  |  |  | 	//		-> promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Load previews for specific image...
 | 
					
						
							|  |  |  | 	//	.getPreviews(gid)
 | 
					
						
							|  |  |  | 	//		-> promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Load all image previews...
 | 
					
						
							|  |  |  | 	//	.getPreviews('*')
 | 
					
						
							|  |  |  | 	//	.getPreviews('all')
 | 
					
						
							|  |  |  | 	//		-> promise
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Load previews that match glob pattern...
 | 
					
						
							|  |  |  | 	//	.getPreviews(pattern)
 | 
					
						
							|  |  |  | 	//		-> promise
 | 
					
						
							|  |  |  | 	//		NOTE: this is useful for finding previews for example by 
 | 
					
						
							|  |  |  | 	//			image name, e.g. .getPreviews('*' + ig.image[gid].name)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 	// NOTE: this will override image .preview and may change .path and
 | 
					
						
							|  |  |  | 	// 		.base_path...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 	// NOTE: if multiple sets of previews are located this will use the 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 	// 		last found and set image .base_path and .path accordingly...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 	getPreviews: ['- File/', | 
					
						
							|  |  |  | 		function(pattern, path, images){ | 
					
						
							|  |  |  | 			images = images || this.images | 
					
						
							|  |  |  | 			pattern = pattern == 'current' ? this.current + '*' | 
					
						
							|  |  |  | 				: pattern == 'all' ? '*' | 
					
						
							|  |  |  | 				// explicit gid...
 | 
					
						
							|  |  |  | 				: pattern in images ? pattern + '*' | 
					
						
							|  |  |  | 				// other pattern...
 | 
					
						
							|  |  |  | 				: pattern != null ? pattern | 
					
						
							|  |  |  | 				// default...
 | 
					
						
							|  |  |  | 				: this.current + '*' | 
					
						
							|  |  |  | 			path = path || this.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var index_dir = this.config['index-dir'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return file.loadPreviews(path, pattern, null, index_dir) | 
					
						
							|  |  |  | 				.then(function(previews){ | 
					
						
							|  |  |  | 					for(var l in previews){ | 
					
						
							|  |  |  | 						var p = previews[l] | 
					
						
							|  |  |  | 						p && Object.keys(p).forEach(function(gid){ | 
					
						
							|  |  |  | 							if(gid in images){ | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 								var base = pathlib.basename(l) == index_dir ?  | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 									pathlib.dirname(l)  | 
					
						
							|  |  |  | 									: l | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 								// update .path and .base_path if they change...
 | 
					
						
							|  |  |  | 								if(images[gid].base_path != base){ | 
					
						
							|  |  |  | 									// XXX
 | 
					
						
							|  |  |  | 									console.warn('getPreviews(..): changing .base_path of image:', gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									var rel = pathlib.relative(images[gid].base_path, base) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									images[gid].path = pathlib.join(rel, images[gid].path)  | 
					
						
							|  |  |  | 									images[gid].base_path = base | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 								images[gid].preview = p[gid].preview | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					return images | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-31 23:19:24 +03:00
										 |  |  | 	// Get images in path...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 	// This will:
 | 
					
						
							|  |  |  | 	// 	- get images from path
 | 
					
						
							|  |  |  | 	// 	- get basic stat data
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 	// 	- get previews from path if they exist (.getPreviews(..))
 | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-31 23:19:24 +03:00
										 |  |  | 	// Returns: Images object
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 	getImagesInPath: ['- File/', | 
					
						
							|  |  |  | 		function(path, read_stat, skip_preview_search, logger){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			if(path == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 			read_stat = read_stat == null ? | 
					
						
							|  |  |  | 				this.config['image-file-read-stat'] | 
					
						
							|  |  |  | 				: read_stat | 
					
						
							|  |  |  | 			skip_preview_search = skip_preview_search == null ? | 
					
						
							|  |  |  | 				this.config['image-file-skip-previews'] | 
					
						
							|  |  |  | 				: skip_preview_search | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			// XXX get a logger...
 | 
					
						
							|  |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			// get the image list...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 			return new Promise(function(resolve, reject){ | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 				glob(path + '/'+ that.config['image-file-pattern'], {stat: !!read_stat}) | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 					.on('error', function(err){ | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 						console.error(err) | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 						reject(err) | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.on('end', function(lst){  | 
					
						
							| 
									
										
										
										
											2016-05-29 05:27:31 +03:00
										 |  |  | 						// XXX might be a good idea to make image paths relative to path...
 | 
					
						
							|  |  |  | 						//lst = lst.map(function(p){ return pathlib.relative(base, p) })
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 						// XXX do we need to normalize paths after we get them from glob??
 | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 						//lst = lst.map(function(p){ return util.normalizePath(p) }), path)
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 						var imgs = images.Images.fromArray(lst, path) | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 						if(!!read_stat){ | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 							var stats = this.statCache | 
					
						
							|  |  |  | 							var p = pathlib.posix | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 							imgs.forEach(function(gid, img){ | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 								var stat = stats[p.join(img.base_path, img.path)] | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 								img.atime = stat.atime | 
					
						
							|  |  |  | 								img.mtime = stat.mtime | 
					
						
							|  |  |  | 								img.ctime = stat.ctime | 
					
						
							|  |  |  | 								img.birthtime = stat.birthtime | 
					
						
							| 
									
										
										
										
											2016-04-20 16:17:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 								img.size = stat.size | 
					
						
							| 
									
										
										
										
											2016-04-20 03:56:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 								// XXX do we need anything else???
 | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 						// pass on the result...
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 						resolve(imgs) | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			// load previews if they exist...
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 			.then(function(imgs){ | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 				var index_dir = that.config['index-dir'] | 
					
						
							|  |  |  | 				var index_path = path +'/'+ index_dir | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-03 04:46:51 +03:00
										 |  |  | 				return !skip_preview_search ?  | 
					
						
							|  |  |  | 					//that.getPreviews('all', path, imgs)
 | 
					
						
							|  |  |  | 					that.getPreviews('all', index_path, imgs) | 
					
						
							|  |  |  | 					: imgs  | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Load images...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX use the logger...
 | 
					
						
							|  |  |  | 	// XXX add a recursive option...
 | 
					
						
							|  |  |  | 	// 		...might also be nice to add sub-dirs to ribbons...
 | 
					
						
							| 
									
										
										
										
											2016-05-31 23:19:24 +03:00
										 |  |  | 	// XXX add option to preserve/update .data (???)
 | 
					
						
							| 
									
										
										
										
											2016-05-30 02:23:55 +03:00
										 |  |  | 	// XXX make image pattern more generic...
 | 
					
						
							|  |  |  | 	loadImages: ['- File/Load images', | 
					
						
							|  |  |  | 		function(path, logger){ | 
					
						
							|  |  |  | 			if(path == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX get a logger...
 | 
					
						
							|  |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			path = util.normalizePath(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: we set this before we start the load so as to let 
 | 
					
						
							|  |  |  | 			// 		clients know what we are loading and not force them
 | 
					
						
							|  |  |  | 			// 		to wait to find out...
 | 
					
						
							|  |  |  | 			// XXX not sure if this is the way to go...
 | 
					
						
							|  |  |  | 			var location =  | 
					
						
							|  |  |  | 			this.__location = { | 
					
						
							|  |  |  | 				path: path, | 
					
						
							|  |  |  | 				method: 'loadImages', | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get the image list...
 | 
					
						
							|  |  |  | 			return this.getImagesInPath( | 
					
						
							|  |  |  | 					path,  | 
					
						
							|  |  |  | 					that.config['image-file-read-stat'], | 
					
						
							|  |  |  | 					that.config['image-file-skip-previews'], | 
					
						
							|  |  |  | 					logger) | 
					
						
							|  |  |  | 				// load the data...
 | 
					
						
							|  |  |  | 				.then(function(imgs){ | 
					
						
							|  |  |  | 					that.load({ | 
					
						
							|  |  |  | 						images: imgs, | 
					
						
							|  |  |  | 						data: data.Data.fromArray(imgs.keys()), | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// NOTE: we set it again because .load() does a .clear()
 | 
					
						
							|  |  |  | 					// 		before it starts loading which clears the .location
 | 
					
						
							|  |  |  | 					// 		too...
 | 
					
						
							|  |  |  | 					that.__location = location | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX revise logger...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 	// XXX does not work yet...
 | 
					
						
							|  |  |  | 	// 		- load: L:\mnt\Dropbox\Instagram\fav\ALL\
 | 
					
						
							|  |  |  | 	// 		- sort
 | 
					
						
							|  |  |  | 	// 		- .loadNewImages() -> will load one new image (that already existed)
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	loadNewImages: ['File/Load new images', | 
					
						
							|  |  |  | 		function(path, logger){ | 
					
						
							|  |  |  | 			path = path || this.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(path == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 			logger = logger || this.logger | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			// cache the loaded images...
 | 
					
						
							|  |  |  | 			var loaded = this.images.map(function(gid, img){ return img.path }) | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 			//var base_pattern = RegExp('^'+path)
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 			return this.getImagesInPath( | 
					
						
							|  |  |  | 					path,  | 
					
						
							|  |  |  | 					that.config['image-file-read-stat'], | 
					
						
							|  |  |  | 					that.config['image-file-skip-previews'], | 
					
						
							|  |  |  | 					logger) | 
					
						
							|  |  |  | 				// load the data...
 | 
					
						
							|  |  |  | 				.then(function(imgs){ | 
					
						
							|  |  |  | 					// remove the images we already have loaded...
 | 
					
						
							|  |  |  | 					imgs.forEach(function(gid, img){ | 
					
						
							|  |  |  | 						// NOTE: we do not need to normalize anything as
 | 
					
						
							|  |  |  | 						// 		both the current path and loaded paths 
 | 
					
						
							|  |  |  | 						// 		came from the same code...
 | 
					
						
							|  |  |  | 						// XXX is this good enough???
 | 
					
						
							|  |  |  | 						// 		...might be a good idea to compare absolute
 | 
					
						
							|  |  |  | 						// 		paths...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 						if(loaded.indexOf(img.path) > 0){ | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 							delete imgs[gid] | 
					
						
							|  |  |  | 						}	 | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// nothing new...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 					if(imgs.length == 0){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 						// XXX
 | 
					
						
							|  |  |  | 						logger && logger.emit('loaded', []) | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// XXX
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 					logger && logger.emit('queued', imgs) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 					var gids = imgs.keys() | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					var new_data = that.data.constructor.fromArray(gids) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// merge with index...
 | 
					
						
							|  |  |  | 					// NOTE: we are prepending new images to the start...
 | 
					
						
							|  |  |  | 					// NOTE: all ribbon gids will change here...
 | 
					
						
							|  |  |  | 					var cur = that.data.current | 
					
						
							|  |  |  | 					// XXX this does not seem to work...
 | 
					
						
							|  |  |  | 					//that.data = new_data.join(that.data)
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 					that.data = new_data.join('base', that.data) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					that.data.current = cur | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-30 03:15:05 +03:00
										 |  |  | 					that.images.join(imgs) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					that.reload() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// XXX report that we are done...
 | 
					
						
							| 
									
										
										
										
											2016-06-03 05:12:29 +03:00
										 |  |  | 					logger && logger.emit('loaded', imgs) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemLoader =  | 
					
						
							|  |  |  | module.FileSystemLoader = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-loader', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 		'fs-info', | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		'location', | 
					
						
							| 
									
										
										
										
											2016-04-27 08:59:13 +03:00
										 |  |  | 		'tasks', | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-fs-loader', | 
					
						
							|  |  |  | 		'fs-url-history', | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 		'fs-save-history', | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemLoaderActions, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | 	isApplicable: function(){  | 
					
						
							|  |  |  | 		return this.runtime == 'node' || this.runtime == 'nw' }, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // Loader UI...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // XXX would need to delay the original action while the user is 
 | 
					
						
							|  |  |  | // 		browsing...
 | 
					
						
							|  |  |  | var makeBrowseProxy = function(action, callback){ | 
					
						
							| 
									
										
										
										
											2016-04-30 16:58:00 +03:00
										 |  |  | 	return widgets.uiDialog(function(path, logger){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		path = path || this.location.path | 
					
						
							|  |  |  | 		// XXX should we set a start path here to current???
 | 
					
						
							|  |  |  | 		return this.browsePath(path,  | 
					
						
							|  |  |  | 			function(path){  | 
					
						
							|  |  |  | 				var res = that[action](path, logger)  | 
					
						
							|  |  |  | 				callback && callback.call(that, path) | 
					
						
							|  |  |  | 				return res | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-04-30 16:58:00 +03:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | // XXX show list of indexes when more than one are found....
 | 
					
						
							|  |  |  | // 		Ex:
 | 
					
						
							|  |  |  | // 			- <index-1>		x 	- 'x' will strike out the element...
 | 
					
						
							|  |  |  | // 			- <index-2>		x
 | 
					
						
							|  |  |  | // 			- ...
 | 
					
						
							|  |  |  | // 			- load all			- load all non striked out elements
 | 
					
						
							|  |  |  | // 		...would be nice to add either ability to sort manually or some 
 | 
					
						
							|  |  |  | // 		modes of auto-sorting, or both...
 | 
					
						
							|  |  |  | // 		...might be a good idea to add root images with an option to 
 | 
					
						
							|  |  |  | // 		load them...
 | 
					
						
							|  |  |  | // 			...do not think that recursively searching for images is a 
 | 
					
						
							|  |  |  | // 			good idea...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | var FileSystemLoaderUIActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		// list of loaders to complete .browsePath(..) action
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: these will be displayed in the same order as they appear
 | 
					
						
							|  |  |  | 		// 		in the list.
 | 
					
						
							|  |  |  | 		// NOTE: the first one is auto-selected.
 | 
					
						
							|  |  |  | 		'path-loaders': [ | 
					
						
							|  |  |  | 			'loadIndex', | 
					
						
							|  |  |  | 			'loadImages', | 
					
						
							|  |  |  | 			//'loadPath',
 | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		'file-browser-settings': { | 
					
						
							|  |  |  | 			disableFiles: true, | 
					
						
							|  |  |  | 			showNonTraversable: true, | 
					
						
							|  |  |  | 			showDisabled: true, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 	// FS browser...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// XXX should the loader list be nested or open in overlay (as-is now)???
 | 
					
						
							|  |  |  | 	browsePath: ['File/Browse file system...', | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		widgets.makeUIDialog(function(base, callback){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			base = base || this.location.path || '/' | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			base = util.normalizePath(base) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 			var o = browseWalk.makeWalk( | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 						null, base, this.config['image-file-pattern'], | 
					
						
							|  |  |  | 						this.config['file-browser-settings']) | 
					
						
							|  |  |  | 					// path selected...
 | 
					
						
							|  |  |  | 					.open(function(evt, path){  | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 						var item = o.selected | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						// single loader...
 | 
					
						
							|  |  |  | 						if(callback && callback.constructor === Function){ | 
					
						
							|  |  |  | 							// close self and parent...
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 							o.parent.close()  | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							callback(path) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// list of loaders...
 | 
					
						
							|  |  |  | 						} else { | 
					
						
							|  |  |  | 							// user-provided list...
 | 
					
						
							|  |  |  | 							if(callback){ | 
					
						
							|  |  |  | 								var loaders = callback | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// build the loaders list from .config...
 | 
					
						
							|  |  |  | 							} else { | 
					
						
							|  |  |  | 								var loaders = {} | 
					
						
							|  |  |  | 								that.config['path-loaders'].forEach(function(m){ | 
					
						
							|  |  |  | 									loaders[that.getDoc(m)[m][0].split('/').pop()] = function(){  | 
					
						
							|  |  |  | 										return that[m](path)  | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// show user the list...
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 							var so = that.Overlay(browse.makeList(null, loaders) | 
					
						
							| 
									
										
										
										
											2016-05-28 02:47:52 +03:00
										 |  |  | 								.on('update', function(){ | 
					
						
							|  |  |  | 									// select top element...
 | 
					
						
							|  |  |  | 									so.client.select(0) | 
					
						
							|  |  |  | 								}) | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 								// close self and parent...
 | 
					
						
							|  |  |  | 								.open(function(){ | 
					
						
							|  |  |  | 									so.close() | 
					
						
							|  |  |  | 									o.parent.close()  | 
					
						
							|  |  |  | 								})) | 
					
						
							|  |  |  | 								// closed menu...
 | 
					
						
							|  |  |  | 								.close(function(){ | 
					
						
							|  |  |  | 									//o.parent.focus()
 | 
					
						
							|  |  |  | 									o.select(item) | 
					
						
							|  |  |  | 								}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							return so | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					// we closed the browser -- save settings to .config...
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					.on('close', function(){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						var config = that.config['file-browser-settings'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 						config.disableFiles = o.options.disableFiles | 
					
						
							|  |  |  | 						config.showDisabled = o.options.showDisabled | 
					
						
							|  |  |  | 						config.showNonTraversable = o.options.showNonTraversable | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return o | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 	// Browse indexes/images...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// NOTE: if no path is passed (null) these behave just like .browsePath(..)
 | 
					
						
							|  |  |  | 	// 		with the appropriate callback otherwise it will just load 
 | 
					
						
							|  |  |  | 	// 		the given path (no UI) while .browsePath(..) will load the 
 | 
					
						
							|  |  |  | 	// 		UI in all cases but will treat the given path as a base path 
 | 
					
						
							|  |  |  | 	// 		to start from.
 | 
					
						
							| 
									
										
										
										
											2016-04-30 07:02:20 +03:00
										 |  |  | 	browseIndex: ['File/Load index...', makeBrowseProxy('loadIndex')], | 
					
						
							|  |  |  | 	browseImages: ['File/Load images...', makeBrowseProxy('loadImages')], | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 	browseSubIndexes: ['File/List sub-indexes...', | 
					
						
							|  |  |  | 		widgets.makeUIDialog(function(){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			var index_dir = this.config['index-dir'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var o = browse.makeLister(null, function(path, make){ | 
					
						
							|  |  |  | 				var dialog = this | 
					
						
							|  |  |  | 				var path = that.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(that.location.method != 'loadIndex'){ | 
					
						
							|  |  |  | 					make('No indexes loaded...', null, true) | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// indicate that we are working...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 				var spinner = make('...') | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// XXX we do not need to actually read anything....
 | 
					
						
							|  |  |  | 				//file.loadIndex(path, that.config['index-dir'], this.logger)
 | 
					
						
							|  |  |  | 				// XXX we need to prune the indexes -- avoid loading nested indexes...
 | 
					
						
							|  |  |  | 				file.listIndexes(path, index_dir) | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 					.on('error', function(err){ | 
					
						
							|  |  |  | 						console.error(err) | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 					.on('end', function(res){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// we got the data, we can now remove the spinner...
 | 
					
						
							|  |  |  | 						spinner.remove() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						res.forEach(function(p){ | 
					
						
							|  |  |  | 							// trim local paths and keep external paths as-is...
 | 
					
						
							|  |  |  | 							p = p.split(index_dir)[0] | 
					
						
							|  |  |  | 							var txt = p.split(path).pop() | 
					
						
							|  |  |  | 							txt = txt != p ? './'+pathlib.join('.', txt) : txt | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							make(txt) | 
					
						
							|  |  |  | 								.on('open', function(){ | 
					
						
							|  |  |  | 									that.loadIndex(p) | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.on('open', function(){ | 
					
						
							|  |  |  | 				o.parent.close() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return o | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX is this a good name???
 | 
					
						
							|  |  |  | var FileSystemLoaderUI =  | 
					
						
							|  |  |  | module.FileSystemLoaderUI = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-fs-loader', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							|  |  |  | 		'fs-loader' | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemLoaderUIActions, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Save History...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemSaveHistoryActions = actions.Actions({ | 
					
						
							|  |  |  | 	// Save comments...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		// comment staged for next .saveIndex(..)...
 | 
					
						
							|  |  |  | 	// 		'current': <comment>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		<timestamp>: <comment>,
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	savecomments: null, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 	getSaveComment: ['- File/', | 
					
						
							|  |  |  | 		function(save){ | 
					
						
							|  |  |  | 			return this.savecomments && this.savecomments[save || 'current'] || '' }], | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 	// Comment a save...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Comment current save...
 | 
					
						
							|  |  |  | 	// 	.setSaveComment(comment)
 | 
					
						
							|  |  |  | 	// 		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Reset current save comment...
 | 
					
						
							|  |  |  | 	// 	.setSaveComment(null)
 | 
					
						
							|  |  |  | 	// 		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Comment specific save...
 | 
					
						
							|  |  |  | 	// 	.setSaveComment(save, comment)
 | 
					
						
							|  |  |  | 	// 		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Reset specific save comment...
 | 
					
						
							|  |  |  | 	// 	.setSaveComment(save, null)
 | 
					
						
							|  |  |  | 	// 		-> actions
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: "save" is the save format as returned by file.groupByDate(..),
 | 
					
						
							|  |  |  | 	// 		or .loadSaveHistoryList(..)
 | 
					
						
							|  |  |  | 	// 		...normally it is Date.timeStamp() compatible string.
 | 
					
						
							|  |  |  | 	setSaveComment: ['- File/Comment a save', | 
					
						
							|  |  |  | 		function(save, comment){ | 
					
						
							|  |  |  | 			var comments = this.savecomments = this.savecomments || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// no explicit save given -- stage a comment for next save...
 | 
					
						
							|  |  |  | 			if(comment === undefined){ | 
					
						
							|  |  |  | 				comment = save | 
					
						
							|  |  |  | 				save = 'current' | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(comment === undefined){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if(comment == null){ | 
					
						
							|  |  |  | 				delete comments[save] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				comments[save] = comment | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.markChanged('savecomments') | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	loadSaveHistoryList: ['- File/', | 
					
						
							|  |  |  | 		function(path){ | 
					
						
							|  |  |  | 			path = path || this.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return file.loadSaveHistoryList(path) | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemSaveHistory =  | 
					
						
							|  |  |  | module.FileSystemSaveHistory = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-save-history', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'fs-loader' | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-fs-save-history', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemSaveHistoryActions, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 		// save/resore .savecomments
 | 
					
						
							|  |  |  | 		// 
 | 
					
						
							|  |  |  | 		['json', | 
					
						
							|  |  |  | 			function(res){ | 
					
						
							|  |  |  | 				if(this.savecomments != null){ | 
					
						
							|  |  |  | 					res.savecomments = JSON.parse(JSON.stringify(this.savecomments)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		['load', | 
					
						
							|  |  |  | 			function(_, data){ | 
					
						
							|  |  |  | 				if(data.savecomments != null){ | 
					
						
							|  |  |  | 					this.savecomments = data.savecomments | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 		// Prepare comments for writing...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: defining this here enables us to actually post-bind to
 | 
					
						
							|  |  |  | 		// 		an action that is defined later or may not even be 
 | 
					
						
							|  |  |  | 		// 		available.
 | 
					
						
							|  |  |  | 		['prepareIndexForWrite', | 
					
						
							|  |  |  | 			function(res){ | 
					
						
							|  |  |  | 				var changed = this.changes == null  | 
					
						
							|  |  |  | 					|| this.changes.savecomments | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(changed){ | 
					
						
							|  |  |  | 					var comments = res.raw.savecomments || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// set the 'current' comment to the correct date...
 | 
					
						
							|  |  |  | 					if(comments.current){ | 
					
						
							|  |  |  | 						comments[res.date] = comments.current | 
					
						
							|  |  |  | 						delete comments.current | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					res.prepared.savecomments = comments | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// replace .savecomments['current'] with .location.from...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: this will also drop any unsaved changes from browsing 
 | 
					
						
							|  |  |  | 		// 		history...
 | 
					
						
							|  |  |  | 		['saveIndex', | 
					
						
							|  |  |  | 			function(res){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				var comments = this.savecomments | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(comments && comments.current){ | 
					
						
							|  |  |  | 					res | 
					
						
							|  |  |  | 						.then(function(){ | 
					
						
							|  |  |  | 							comments[that.location.from] = comments.current | 
					
						
							|  |  |  | 							delete comments.current | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				delete this.unsaved_index | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // Save History UI...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX add comment editing...
 | 
					
						
							|  |  |  | // XXX should this also list journal stuff or have the ability for extending???
 | 
					
						
							|  |  |  | var FileSystemSaveHistoryUIActions = actions.Actions({ | 
					
						
							|  |  |  | 	// Saved original index state before loading a state from history...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	unsaved_index: null, | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 	// List save history dialog...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 	//	.location.from			- set to timestamp of save state when 
 | 
					
						
							|  |  |  | 	//								selecting a non-top state.
 | 
					
						
							|  |  |  | 	//								NOTE: this may be set to last save 
 | 
					
						
							|  |  |  | 	//									state.
 | 
					
						
							|  |  |  | 	// 	.location.historic		- set to true when at a non-top state.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// For multiple indexes this will show the combined history and 
 | 
					
						
							|  |  |  | 	// selecting a postion will load all the participating indexes to 
 | 
					
						
							|  |  |  | 	// that specific date or closest earlier state.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Unsaved changes will be saved to .unsaved_index when switching 
 | 
					
						
							|  |  |  | 	// from current to a historic state.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will show no history if .location.method is not 'loadIndex'..
 | 
					
						
							|  |  |  | 	// NOTE: this will set changes to all when loading a historic state
 | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 	// 		that the latest and to non otherwise....
 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-05-05 14:40:58 +03:00
										 |  |  | 	// XXX add comment editing...
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 	// XXX might be a good idea to show a diff of some kind or at least
 | 
					
						
							|  |  |  | 	// 		what .changed when writing a save...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 	listSaveHistory: ['File/History...', | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 		widgets.makeUIDialog(function(){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 			var _makeTitle = function(title, date, a){ | 
					
						
							|  |  |  | 				title = [title] | 
					
						
							|  |  |  | 				date = date || 'current' | 
					
						
							|  |  |  | 				a = a || that | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 				var comment = a.savecomments && a.savecomments[date]  | 
					
						
							|  |  |  | 				//title.push(comment || '')
 | 
					
						
							|  |  |  | 				comment && title.push(comment) | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 				// XXX is this the best format???
 | 
					
						
							|  |  |  | 				return title.join(' - ') | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 			var o = browse.makeLister(null, function(path, make){ | 
					
						
							|  |  |  | 				var dialog = this | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 				var from = that.location.from | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 				if(that.changes !== false){ | 
					
						
							|  |  |  | 					make(_makeTitle('Current state (unsaved)', 'current'))	 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 					make('---') | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 				// only search for history if we have an index loaded...
 | 
					
						
							|  |  |  | 				if(that.location.method != 'loadIndex'){ | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 					make('No history...', {disabled: true})	 | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// select the 'Unsaved' item...
 | 
					
						
							|  |  |  | 					dialog.select() | 
					
						
							|  |  |  | 						.addClass('highlighted') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 				// indicate that we are working...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 01:17:18 +03:00
										 |  |  | 				var spinner = make('...') | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 				that.loadSaveHistoryList() | 
					
						
							|  |  |  | 					.catch(function(err){ | 
					
						
							|  |  |  | 						// XXX
 | 
					
						
							|  |  |  | 						console.error(err) | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.then(function(data){ | 
					
						
							|  |  |  | 						var list = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 						// got the data, remove the spinner...
 | 
					
						
							|  |  |  | 						spinner.remove() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 						Object.keys(data).forEach(function(path){ | 
					
						
							|  |  |  | 							Object.keys(data[path]).forEach(function(d){ | 
					
						
							|  |  |  | 								list.push(d) | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						list | 
					
						
							|  |  |  | 							.sort() | 
					
						
							|  |  |  | 							.reverse() | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 						// Special case: unsaved state...
 | 
					
						
							|  |  |  | 						if(that.unsaved_index){ | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 							var unsaved = that.unsaved_index | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 							make(_makeTitle('Original state (unsaved)', 'current', unsaved))	 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 								.on('open', function(){ | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 									that.load(unsaved) | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 									delete that.unsaved_index | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 						// Special case: top save state is the default, 
 | 
					
						
							|  |  |  | 						// no need to mark anything for change, but only
 | 
					
						
							|  |  |  | 						// if nothing changed...
 | 
					
						
							|  |  |  | 						} else if(that.changes === false){ | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 							var first = list.shift() | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 							first && make(_makeTitle(Date.fromTimeStamp(first).toShortDate(), first))	 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 								.on('open', function(){ | 
					
						
							|  |  |  | 									that.loadIndex(that.location.path, first) | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 						} | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						list | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 							.forEach(function(d){ | 
					
						
							|  |  |  | 								var txt = Date.fromTimeStamp(d).toShortDate() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 								make(_makeTitle(Date.fromTimeStamp(d).toShortDate(), d))	 | 
					
						
							| 
									
										
										
										
											2016-05-05 14:40:58 +03:00
										 |  |  | 									.attr('timestamp', d) | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 									.on('open', function(){ | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 										// auto save...
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 										if(that.changes !== false | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 												&& !that.location.historic){ | 
					
						
							|  |  |  | 											that.unsaved_index = that.json() | 
					
						
							|  |  |  | 										} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 										that.loadIndex(that.location.path, d) | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 											.then(function(){ | 
					
						
							|  |  |  | 												that.markChanged('all') | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 19:17:14 +03:00
										 |  |  | 												that.location.historic = true | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 												// remove 'current' comments
 | 
					
						
							|  |  |  | 												// from loaded state...
 | 
					
						
							|  |  |  | 												//
 | 
					
						
							|  |  |  | 												// NOTE: the original 'current'
 | 
					
						
							|  |  |  | 												// 		comment is saved to
 | 
					
						
							|  |  |  | 												// 		.unsaved_index
 | 
					
						
							|  |  |  | 												delete that.savecomments.current | 
					
						
							| 
									
										
										
										
											2016-05-05 01:32:47 +03:00
										 |  |  | 											}) | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 									}) | 
					
						
							|  |  |  | 									// mark the current loaded position...
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 									.addClass(d == from ? 'selected highlighted' : '') | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 							}) | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 19:26:26 +03:00
										 |  |  | 						make.done() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 						// NOTE: here we will select 'Latest' if nothing
 | 
					
						
							|  |  |  | 						// 		was selected...
 | 
					
						
							| 
									
										
										
										
											2016-05-04 21:28:46 +03:00
										 |  |  | 						dialog.select() | 
					
						
							| 
									
										
										
										
											2016-05-04 18:01:19 +03:00
										 |  |  | 							.addClass('highlighted') | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 					}) | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 			.on('open', function(){ | 
					
						
							|  |  |  | 				o.parent.close() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return o | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | var FileSystemSaveHistoryUI =  | 
					
						
							|  |  |  | module.FileSystemSaveHistoryUI = core.ImageGridFeatures.Feature({ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 	tag: 'ui-fs-save-history', | 
					
						
							| 
									
										
										
										
											2016-04-20 00:43:20 +03:00
										 |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 		'fs-save-history', | 
					
						
							| 
									
										
										
										
											2016-04-20 00:43:20 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 	actions: FileSystemSaveHistoryUIActions, | 
					
						
							| 
									
										
										
										
											2016-05-05 18:19:24 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 		['saveIndex', | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 			function(res){ | 
					
						
							|  |  |  | 				delete this.unsaved_index | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2016-05-05 18:19:24 +03:00
										 |  |  | 	] | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // URL History...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var pushToHistory = function(action, to_top, checker){ | 
					
						
							|  |  |  | 	return [action,  | 
					
						
							|  |  |  | 		function(_, path){  | 
					
						
							|  |  |  | 			path = util.normalizePath(path) | 
					
						
							|  |  |  | 			if(path){ | 
					
						
							|  |  |  | 				this.pushURLToHistory( | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 					path,  | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					action,  | 
					
						
							|  |  |  | 					checker || 'checkPath')  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(to_top){ | 
					
						
							|  |  |  | 				this.setTopURLHistory(path) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}] | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemURLHistory =  | 
					
						
							|  |  |  | module.FileSystemLoaderURLHistory = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-url-history', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'fs-loader', | 
					
						
							|  |  |  | 		'url-history', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-fs-url-history', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		pushToHistory('loadImages'),  | 
					
						
							|  |  |  | 		pushToHistory('loadIndex'),  | 
					
						
							|  |  |  | 		pushToHistory('loadPath'),  | 
					
						
							|  |  |  | 		//pushToHistory('loadNewImages'), 
 | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // URL History UI...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Opening the url via .browsePath(..) if url is in history will move 
 | 
					
						
							|  |  |  | // it to top of list...
 | 
					
						
							|  |  |  | var FileSystemURLHistoryUI =  | 
					
						
							|  |  |  | module.FileSystemLoaderURLHistoryUI = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-fs-url-history', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui-fs-loader', | 
					
						
							|  |  |  | 		'fs-url-history', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		['browsePath',  | 
					
						
							|  |  |  | 			function(res){  | 
					
						
							|  |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 				res.open(function(_, path){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					that.setTopURLHistory(path)  | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // Writer...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var FileSystemWriterActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		//'index-filename-template': '${DATE}-${KEYWORD}.${EXT}',
 | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		'export-path': null, | 
					
						
							|  |  |  | 		'export-paths': [], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		'export-preview-name-pattern': '%f', | 
					
						
							|  |  |  | 		'export-preview-name-patterns': [ | 
					
						
							|  |  |  | 			'%f', | 
					
						
							|  |  |  | 			'%n%(-bookmarked)b%e', | 
					
						
							|  |  |  | 			'%n%(-marked)m%e', | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		'export-level-directory-name': 'fav', | 
					
						
							|  |  |  | 		'export-level-directory-names': [ | 
					
						
							|  |  |  | 			'fav', | 
					
						
							|  |  |  | 			'select', | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX add options to indicate:
 | 
					
						
							|  |  |  | 		// 		- long side
 | 
					
						
							|  |  |  | 		// 		- short side
 | 
					
						
							|  |  |  | 		// 		- vertical
 | 
					
						
							|  |  |  | 		// 		- horizontal
 | 
					
						
							|  |  |  | 		// 		- ...
 | 
					
						
							| 
									
										
										
										
											2016-05-23 03:42:53 +03:00
										 |  |  | 		// XXX this repeats sharp.SharpActions.config['preview-sizes']
 | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 		'export-preview-sizes': [ | 
					
						
							| 
									
										
										
										
											2016-04-18 03:05:48 +03:00
										 |  |  | 			'900', | 
					
						
							|  |  |  | 			'1000', | 
					
						
							|  |  |  | 			'1280', | 
					
						
							|  |  |  | 			'1920', | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 		], | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 		'export-preview-size': 1000, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// This can be:
 | 
					
						
							|  |  |  | 	// 	- null/undefined	- write all
 | 
					
						
							|  |  |  | 	// 	- true				- write all
 | 
					
						
							|  |  |  | 	// 	- false				- write nothing
 | 
					
						
							|  |  |  | 	// 	- {
 | 
					
						
							|  |  |  | 	//		// write/skip data...
 | 
					
						
							|  |  |  | 	//		data: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// write/skip images or write a diff including the given 
 | 
					
						
							|  |  |  | 	//		// <gid>s only...
 | 
					
						
							|  |  |  | 	//		images: <bool> | [ <gid>, ... ],
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// write/skip tags...
 | 
					
						
							|  |  |  | 	//		tags: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// write/skip bookmarks...
 | 
					
						
							|  |  |  | 	//		bookmarked: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// write/skip selected...
 | 
					
						
							|  |  |  | 	//		selected: <bool>,
 | 
					
						
							|  |  |  | 	// 	  }
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: in the complex format all fields ar optional; if a field 
 | 
					
						
							|  |  |  | 	// 		is not included it is not written (same as when set to false)
 | 
					
						
							|  |  |  | 	// NOTE: .current is written always.
 | 
					
						
							|  |  |  | 	chages: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	clone: [function(full){ | 
					
						
							|  |  |  | 			return function(res){ | 
					
						
							|  |  |  | 				res.changes = null | 
					
						
							|  |  |  | 				if(full && this.hasOwnProperty('changes') && this.changes){ | 
					
						
							|  |  |  | 					res.changes = JSON.parse(JSON.stringify(this.changes)) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-31 02:14:05 +03:00
										 |  |  | 	// Mark data sections as changed...
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Mark everything changed...
 | 
					
						
							|  |  |  | 	//	.markChanged('all')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Mark nothing changed...
 | 
					
						
							|  |  |  | 	//	.markChanged('none')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Mark a section changed...
 | 
					
						
							|  |  |  | 	//	.markChanged('data')
 | 
					
						
							|  |  |  | 	//	.markChanged('tags')
 | 
					
						
							|  |  |  | 	//	.markChanged('selected')
 | 
					
						
							|  |  |  | 	//	.markChanged('bookmarked')
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Mark image changed...
 | 
					
						
							|  |  |  | 	//	.markChanged(<gid>, ...)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-03-31 02:14:05 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: when .changes is null (i.e. everything changed, marked via
 | 
					
						
							|  |  |  | 	// 		.markChanged('all')) then calling this with anything other 
 | 
					
						
							|  |  |  | 	// 		than 'none' will have no effect.
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 	markChanged: ['- System/', | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 		function(section){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 			var args = util.args2array(arguments) | 
					
						
							|  |  |  | 			//var changes = this.changes = 
 | 
					
						
							|  |  |  | 			var changes =  | 
					
						
							|  |  |  | 				this.hasOwnProperty('changes') ? | 
					
						
							|  |  |  | 					this.changes || {} | 
					
						
							|  |  |  | 					: {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-07 16:09:29 +03:00
										 |  |  | 			//console.log('CHANGED:', args)
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			// all...
 | 
					
						
							|  |  |  | 			if(args.length == 1 && args[0] == 'all'){ | 
					
						
							|  |  |  | 				// NOTE: this is better than delete as it will shadow 
 | 
					
						
							|  |  |  | 				// 		the parent's changes in case we got cloned from
 | 
					
						
							|  |  |  | 				// 		a live instance...
 | 
					
						
							|  |  |  | 				//delete this.changes
 | 
					
						
							|  |  |  | 				this.changes = null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// none...
 | 
					
						
							|  |  |  | 			} else if(args.length == 1 && args[0] == 'none'){ | 
					
						
							|  |  |  | 				this.changes = false  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-30 18:05:56 +03:00
										 |  |  | 			// everything is marked changed, everything will be saved
 | 
					
						
							|  |  |  | 			// anyway...
 | 
					
						
							|  |  |  | 			// NOTE: to reset this use .markChanged('none') and then 
 | 
					
						
							|  |  |  | 			// 		manually add the desired changes...
 | 
					
						
							|  |  |  | 			} else if(this.changes == null){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				var images = (changes.images || []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				args.forEach(function(arg){ | 
					
						
							|  |  |  | 					var gid = that.data.getImage(arg) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// special case: image gid...
 | 
					
						
							|  |  |  | 					if(gid != -1 && gid != null){ | 
					
						
							|  |  |  | 						images.push(gid) | 
					
						
							|  |  |  | 						images = images.unique() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						changes.images = images | 
					
						
							|  |  |  | 						that.changes = changes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// all other keywords...
 | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						changes[arg] = true | 
					
						
							|  |  |  | 						that.changes = changes | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// Convert json index to a format compatible with file.writeIndex(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This is here so as other features can participate in index
 | 
					
						
							|  |  |  | 	// preparation...
 | 
					
						
							|  |  |  | 	// There are several stages features can control the output format:
 | 
					
						
							|  |  |  | 	// 	1) .json() action
 | 
					
						
							|  |  |  | 	// 		- use this for global high level serialization format
 | 
					
						
							|  |  |  | 	// 		- the output of this is .load(..) compatible
 | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 	// 	2) .prepareIndexForWrite(..) action
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// 		- use this for file system write preparation
 | 
					
						
							|  |  |  | 	// 		- this directly affects the index structure
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will get the base index, ignoring the cropped state.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Returns:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 	// 		// Timestamp...
 | 
					
						
							|  |  |  | 	// 		// NOTE: this is the timestamp used to write the index.
 | 
					
						
							|  |  |  | 	// 		date: <timestamp>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// 		// This is the original json object, either the one passed as
 | 
					
						
							|  |  |  | 	// 		// an argument or the one returned by .json('base')
 | 
					
						
							|  |  |  | 	// 		raw: <original-json>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		// this is the prepared object, the one that is going to be
 | 
					
						
							|  |  |  | 	// 		// saved.
 | 
					
						
							|  |  |  | 	// 		prepared: <prepared-json>,
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The format for the <prapared-json> is as follows:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		<keyword>: <data>,
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The <prepared-json> is written out to a fs index in the following
 | 
					
						
							|  |  |  | 	// way:
 | 
					
						
							|  |  |  | 	// 		<index-dir>/<timestamp>-<keyword>.json
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	<index-dir>		- taken from .config['index-dir'] (default: '.ImageGrid')
 | 
					
						
							|  |  |  | 	// 	<timestamp>		- as returned by Date.timeStamp() (see: jli)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// For more info see file.writeIndex(..) and file.loadIndex(..).
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	prepareIndexForWrite: ['- File/Prepare index for writing', | 
					
						
							|  |  |  | 		function(json, full){ | 
					
						
							|  |  |  | 			json = json || this.json('base') | 
					
						
							|  |  |  | 			var changes = full ? null  | 
					
						
							|  |  |  | 				: this.hasOwnProperty('changes') ? this.changes | 
					
						
							|  |  |  | 				: null | 
					
						
							|  |  |  | 			return { | 
					
						
							| 
									
										
										
										
											2016-05-28 18:31:42 +03:00
										 |  |  | 				date: Date.timeStamp(), | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				raw: json, | 
					
						
							|  |  |  | 				prepared: file.prepareIndex(json, changes), | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// NOTE: with no arguments this will save index to .location.path
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 	// XXX should this return a promise??? ...a clean promise???
 | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 	// XXX BUG: after .loadImages(..) and without arguments this produces
 | 
					
						
							|  |  |  | 	// 		a result that is not loaded....
 | 
					
						
							| 
									
										
										
										
											2016-04-19 03:12:57 +03:00
										 |  |  | 	saveIndex: ['- File/', | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		function(path, logger){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2016-05-07 02:02:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			path = path || this.location.loaded | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 			path = path && path.length == 1 ? path[0] : path  | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							| 
									
										
										
										
											2016-05-07 02:02:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 			if(path instanceof Array){ | 
					
						
							|  |  |  | 				console.error('saving to merged indexes not yet supported...') | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 			// XXX
 | 
					
						
							|  |  |  | 			if(path == null && this.location.method != 'loadIndex'){ | 
					
						
							|  |  |  | 				path = this.location.path | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 			// resolve relative paths...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 			if(/^(\.\.?[\\\/]|[^\\\/])/.test(path)  | 
					
						
							|  |  |  | 					// and skip windows drives...
 | 
					
						
							|  |  |  | 					&& !/^[a-z]:[\\\/]/i.test(path)){ | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 				// XXX do we need to normalize???
 | 
					
						
							|  |  |  | 				path = this.location.path +'/'+ path | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			// XXX get a logger...
 | 
					
						
							|  |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX get real base path...
 | 
					
						
							|  |  |  | 			//path = path || this.location.path +'/'+ this.config['index-dir']
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 			var index = this.prepareIndexForWrite() | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			return file.writeIndex( | 
					
						
							| 
									
										
										
										
											2016-05-06 18:32:00 +03:00
										 |  |  | 					index.prepared,  | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					// XXX should we check if index dir is present in path???
 | 
					
						
							|  |  |  | 					//path, 
 | 
					
						
							|  |  |  | 					path +'/'+ this.config['index-dir'],  | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 					index.date, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					this.config['index-filename-template'],  | 
					
						
							|  |  |  | 					logger || this.logger) | 
					
						
							|  |  |  | 				.then(function(){ | 
					
						
							|  |  |  | 					that.location.method = 'loadIndex' | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 					that.location.from = index.date | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX ways to treat a collection:
 | 
					
						
							|  |  |  | 	// 		- crop data
 | 
					
						
							|  |  |  | 	// 		- independent index
 | 
					
						
							|  |  |  | 	// XXX save to: .ImageGrid/collections/<title>/
 | 
					
						
							|  |  |  | 	// XXX move to a feature???
 | 
					
						
							|  |  |  | 	// XXX API: save/load/list/remove
 | 
					
						
							|  |  |  | 	// 		...need to track save location (not the save as the index)...
 | 
					
						
							|  |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	saveCollection: ['- File/Save collection', | 
					
						
							|  |  |  | 		function(title){ | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 	// Export current state as a full loadable index
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 	// XXX resolve env variables in path...
 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 	// XXX what sould happen if no path is given???
 | 
					
						
							| 
									
										
										
										
											2016-04-02 15:58:55 +03:00
										 |  |  | 	// XXX should this return a promise??? ...a clean promise???
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 	// XXX add preview selection...
 | 
					
						
							|  |  |  | 	// XXX handle .image.path and other stack files...
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	// XXX local collections???
 | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 	exportIndex: ['- File/Export/Export index', | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		function(path, logger){ | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 			// XXX is this correct???
 | 
					
						
							|  |  |  | 			path = path || './exported' | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 			// XXX resolve env variables in path...
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 			// resolve relative paths...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 01:52:09 +03:00
										 |  |  | 			if(/^(\.\.?[\\\/]|[^\\\/])/.test(path)  | 
					
						
							|  |  |  | 					// and skip windows drives...
 | 
					
						
							|  |  |  | 					&& !/^[a-z]:[\\\/]/i.test(path)){ | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 				// XXX do we need to normalize???
 | 
					
						
							|  |  |  | 				path = this.location.path +'/'+ path | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			var json = this.json() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get all loaded gids...
 | 
					
						
							|  |  |  | 			var gids = [] | 
					
						
							|  |  |  | 			for(var r in json.data.ribbons){ | 
					
						
							|  |  |  | 				this.data.makeSparseImages(json.data.ribbons[r], gids) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			gids = gids.compact() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// build .images with loaded images...
 | 
					
						
							|  |  |  | 			// XXX list of previews should be configurable (max size)
 | 
					
						
							|  |  |  | 			var images = {} | 
					
						
							|  |  |  | 			gids.forEach(function(gid){ | 
					
						
							|  |  |  | 				var img = json.images[gid] | 
					
						
							|  |  |  | 				if(img){ | 
					
						
							|  |  |  | 					images[gid] = json.images[gid] | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					// remove un-needed previews...
 | 
					
						
							|  |  |  | 					// XXX
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// prepare and save index to target path...
 | 
					
						
							|  |  |  | 			json.data.order = gids | 
					
						
							|  |  |  | 			json.images = images | 
					
						
							|  |  |  | 			// XXX should we check if index dir is present in path???
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 			var index_path = path +'/'+ this.config['index-dir'] | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// copy previews for the loaded images...
 | 
					
						
							|  |  |  | 			// XXX should also optionally populate the base dir and nested favs...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 			var base_dir = this.location.path | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			gids.forEach(function(gid){ | 
					
						
							|  |  |  | 				var img = json.images[gid] | 
					
						
							|  |  |  | 				var img_base = img.base_path | 
					
						
							|  |  |  | 				var previews = img.preview | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 				// NOTE: we are copying everything to one place so no 
 | 
					
						
							|  |  |  | 				// 		need for a base path...
 | 
					
						
							|  |  |  | 				delete img.base_path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX copy img.path -- the main image, especially when no previews present....
 | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 				if(previews || img.path){ | 
					
						
							|  |  |  | 					Object.keys(previews || {}) | 
					
						
							|  |  |  | 						.map(function(res){ return decodeURI(previews[res]) }) | 
					
						
							|  |  |  | 						// XXX should we copy this, especially if it's a hi-res???
 | 
					
						
							|  |  |  | 						.concat([img.path || null]) | 
					
						
							|  |  |  | 						.forEach(function(preview_path){ | 
					
						
							|  |  |  | 							if(preview_path == null){ | 
					
						
							|  |  |  | 								return | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 							var from = (img_base || base_dir) +'/'+ preview_path | 
					
						
							|  |  |  | 							var to = path +'/'+ preview_path | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 							// XXX do we queue these or let the OS handle it???
 | 
					
						
							|  |  |  | 							// 		...needs testing, if node's fs queues the io
 | 
					
						
							|  |  |  | 							// 		internally then we do not need to bother...
 | 
					
						
							|  |  |  | 							// XXX
 | 
					
						
							|  |  |  | 							ensureDir(pathlib.dirname(to)) | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 								.catch(function(err){ | 
					
						
							|  |  |  | 									logger && logger.emit('error', err) }) | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 								.then(function(){ | 
					
						
							|  |  |  | 									return copy(from, to) | 
					
						
							|  |  |  | 										// XXX do we need to have both of this 
 | 
					
						
							|  |  |  | 										// 		and the above .catch(..) or can
 | 
					
						
							|  |  |  | 										// 		we just use the one above (after
 | 
					
						
							|  |  |  | 										// 		.then(..))
 | 
					
						
							|  |  |  | 										.then(function(){ | 
					
						
							|  |  |  | 											logger && logger.emit('done', to) }) | 
					
						
							|  |  |  | 										.catch(function(err){ | 
					
						
							|  |  |  | 											logger && logger.emit('error', err) }) | 
					
						
							|  |  |  | 								}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: if we are to use .saveIndex(..) here, do not forget
 | 
					
						
							|  |  |  | 			// 		to reset .changes
 | 
					
						
							|  |  |  | 			file.writeIndex( | 
					
						
							|  |  |  | 				this.prepareIndexForWrite(json, true).prepared,  | 
					
						
							|  |  |  | 				index_path,  | 
					
						
							|  |  |  | 				this.config['index-filename-template'],  | 
					
						
							|  |  |  | 				logger || this.logger) | 
					
						
							|  |  |  | 			 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 	// XXX might also be good to save/load the export options to .ImageGrid-export.json
 | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 	// XXX resolve env variables in path... (???)
 | 
					
						
							|  |  |  | 	// XXX make custom previews (option)...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 	// 		...should this be a function of .images.getBestPreview(..)???
 | 
					
						
							| 
									
										
										
										
											2016-04-18 17:27:34 +03:00
										 |  |  | 	// XXX report errors...
 | 
					
						
							|  |  |  | 	// XXX stop the process on errors...
 | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 	// XXX use tasks...
 | 
					
						
							|  |  |  | 	exportDirs: ['- File/Export/Export ribbons as directories', | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 		function(path, pattern, level_dir, size, logger){ | 
					
						
							|  |  |  | 			logger = logger || this.logger | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			var base_dir = this.location.path | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-29 23:49:01 +03:00
										 |  |  | 			path = util.normalizePath(path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 			// XXX resolve env variables in path...
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 			// resolve relative paths...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 01:52:09 +03:00
										 |  |  | 			if(/^(\.\.?[\\\/]|[^\\\/])/.test(path)  | 
					
						
							|  |  |  | 					// and skip windows drives...
 | 
					
						
							|  |  |  | 					&& !/^[a-z]:[\\\/]/i.test(path)){ | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 				// XXX do we need to normalize???
 | 
					
						
							| 
									
										
										
										
											2016-04-18 01:52:09 +03:00
										 |  |  | 				path = this.location.path +'/'+ path | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 			var to_dir = path | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// get/set the config data...
 | 
					
						
							|  |  |  | 			// XXX should this store the last set???
 | 
					
						
							|  |  |  | 			level_dir = level_dir || this.config['export-level-directory-name'] || 'fav' | 
					
						
							|  |  |  | 			size = size || this.config['export-preview-size'] || 1000 | 
					
						
							|  |  |  | 			pattern = pattern || this.config['export-preview-name-pattern'] || '%f' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 17:27:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// XXX need to abort on fatal errors...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 			this.data.ribbon_order | 
					
						
							|  |  |  | 				.slice() | 
					
						
							|  |  |  | 				.reverse() | 
					
						
							|  |  |  | 				.forEach(function(ribbon){ | 
					
						
							|  |  |  | 					// NOTE: this is here to keep the specific path local to 
 | 
					
						
							|  |  |  | 					// 		this scope...
 | 
					
						
							|  |  |  | 					var img_dir = to_dir | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					ensureDir(pathlib.dirname(img_dir)) | 
					
						
							|  |  |  | 						.catch(function(err){ | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 							logger && logger.emit('error', err) }) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 						.then(function(){ | 
					
						
							|  |  |  | 							that.data.ribbons[ribbon].forEach(function(gid){ | 
					
						
							|  |  |  | 								var img = that.images[gid] | 
					
						
							| 
									
										
										
										
											2016-04-21 01:42:06 +03:00
										 |  |  | 								var img_name = pathlib.basename(img.path || (img.name + img.ext)) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								// get best preview...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 								var from = decodeURI( | 
					
						
							|  |  |  | 									(img.base_path || base_dir)  | 
					
						
							|  |  |  | 										+'/' | 
					
						
							|  |  |  | 										+ that.images.getBestPreview(gid, size).url) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 								// XXX see if we need to make a preview (sharp)
 | 
					
						
							|  |  |  | 								// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								// XXX get/form image name... 
 | 
					
						
							|  |  |  | 								// XXX might be a good idea to connect this to the info framework...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 								var ext = pathlib.extname(img_name) | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 								var tags = that.data.getTags(gid) | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 								var name = pattern | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 									// file name...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 04:06:37 +03:00
										 |  |  | 									.replace(/%f/, img_name) | 
					
						
							|  |  |  | 									.replace(/%n/, img_name.replace(ext, '')) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 									.replace(/%e/, ext) | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 									// gid...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 									.replace(/%gid/, gid) | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 									// XXX get the correct short gid length...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 									.replace(/%g/, gid.slice(-7, -1)) | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 									// order...
 | 
					
						
							|  |  |  | 									.replace(/%i/, that.data.getImageOrder(gid)) | 
					
						
							|  |  |  | 									.replace(/%I/, that.data.getImageOrder(gid, 'global')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									// tags...
 | 
					
						
							| 
									
										
										
										
											2016-04-18 17:27:34 +03:00
										 |  |  | 									// XXX test: %n%(b)b%(m)m%e
 | 
					
						
							|  |  |  | 									.replace( | 
					
						
							|  |  |  | 										/%\((.*)\)m/, tags.indexOf('selected') >= 0 ? '$1' : '') | 
					
						
							|  |  |  | 									.replace( | 
					
						
							|  |  |  | 										/%\((.*)\)b/, tags.indexOf('bookmark') >= 0 ? '$1' : '') | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 									// metadata...
 | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 									// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 								var to = img_dir +'/'+ name | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 								return copy(from, to) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 									.then(function(){ | 
					
						
							| 
									
										
										
										
											2016-04-18 02:22:12 +03:00
										 |  |  | 										logger && logger.emit('done', to) }) | 
					
						
							|  |  |  | 									.catch(function(err){ | 
					
						
							|  |  |  | 										logger && logger.emit('error', err) }) | 
					
						
							| 
									
										
										
										
											2016-04-15 23:32:33 +03:00
										 |  |  | 							}) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					to_dir += '/'+level_dir | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}] | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemWriter =  | 
					
						
							|  |  |  | module.FileSystemWriter = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-writer', | 
					
						
							|  |  |  | 	// NOTE: this is mostly because of the base path handling...
 | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	depends: [ | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 		'fs-loader', | 
					
						
							|  |  |  | 		'index-format', | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-fs-writer', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemWriterActions, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | 	isApplicable: function(){  | 
					
						
							|  |  |  | 		return this.runtime == 'node' || this.runtime == 'nw' }, | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// monitor changes...
 | 
					
						
							|  |  |  | 	// XXX should we use .load(..) to trigger changes instead of .loadURLs(..)???
 | 
					
						
							|  |  |  | 	// 		...the motivation is that .crop(..) may also trigger loads...
 | 
					
						
							|  |  |  | 	// 		....needs more thought...
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		// clear changes...
 | 
					
						
							|  |  |  | 		// XXX currently if no args are passed then nothing is 
 | 
					
						
							|  |  |  | 		// 		done here, this might change...
 | 
					
						
							|  |  |  | 		['loadIndex', | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			function(res, path){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				if(path){ | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 					//this.markChanged('none')
 | 
					
						
							|  |  |  | 					var that = this | 
					
						
							|  |  |  | 					res.then(function(){ | 
					
						
							|  |  |  | 						that.markChanged('none') | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		['saveIndex', | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			function(res, path){ | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				// NOTE: if saving to a different path than loaded do not
 | 
					
						
							|  |  |  | 				// 		drop the .changes flags...
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 				if(!path || path == this.location.path){ | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 					//this.markChanged('none')
 | 
					
						
							|  |  |  | 					var that = this | 
					
						
							|  |  |  | 					res.then(function(){ | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 						that.markChanged('none') | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// everything changed...
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			'loadURLs', | 
					
						
							|  |  |  | 			'clear', | 
					
						
							|  |  |  | 		],  | 
					
						
							| 
									
										
										
										
											2016-04-01 18:42:45 +03:00
										 |  |  | 			function(){  | 
					
						
							|  |  |  | 				this.markChanged('all')  | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// data...
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			//'clear',
 | 
					
						
							|  |  |  | 			//'load',
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'setBaseRibbon', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'shiftImageTo', | 
					
						
							|  |  |  | 			'shiftImageUp', | 
					
						
							|  |  |  | 			'shiftImageDown', | 
					
						
							|  |  |  | 			'shiftImageLeft', | 
					
						
							|  |  |  | 			'shiftImageRight', | 
					
						
							|  |  |  | 			'shiftRibbonUp', | 
					
						
							|  |  |  | 			'shiftRibbonDown', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'sortImages', | 
					
						
							|  |  |  | 			'reverseImages', | 
					
						
							|  |  |  | 			'reverseRibbons', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'group', | 
					
						
							|  |  |  | 			'ungroup', | 
					
						
							|  |  |  | 			'expandGroup', | 
					
						
							|  |  |  | 			'collapseGroup', | 
					
						
							|  |  |  | 		],  | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			function(_, target){ this.markChanged('data') }], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// image specific...
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			'rotateCW', | 
					
						
							|  |  |  | 			'rotateCCW', | 
					
						
							|  |  |  | 			'flipHorizontal', | 
					
						
							|  |  |  | 			'flipVertical', | 
					
						
							|  |  |  | 		],  | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 			function(_, target){ this.markChanged(target) }], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// tags and images...
 | 
					
						
							|  |  |  | 		// NOTE: tags are also stored in images...
 | 
					
						
							|  |  |  | 		['tag untag', | 
					
						
							|  |  |  | 			function(_, tags, gids){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 				var changes = [] | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				gids = gids || [this.data.getImage()] | 
					
						
							|  |  |  | 				gids = gids.constructor !== Array ? [this.data.getImage(gids)] : gids | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				tags = tags || [] | 
					
						
							|  |  |  | 				tags = tags.constructor !== Array ? [tags] : tags | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// images...
 | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 				changes = changes.concat(gids) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// tags...
 | 
					
						
							|  |  |  | 				if(tags.length > 0){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 					changes.push('tags') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// selected...
 | 
					
						
							|  |  |  | 					if(tags.indexOf('selected') >= 0){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 						changes.push('selected') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// bookmark...
 | 
					
						
							|  |  |  | 					if(tags.indexOf('bookmark') >= 0){ | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 						changes.push('bookmarked') | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2016-01-08 07:30:51 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				this.markChanged.apply(this, changes) | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 	] | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | // Writer UI...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | // XXX add writer UI feature...
 | 
					
						
							|  |  |  | // 		- save as.. (browser)
 | 
					
						
							|  |  |  | // 		- save if not base path present (browser)
 | 
					
						
							|  |  |  | var FileSystemWriterUIActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2016-04-16 04:17:34 +03:00
										 |  |  | 	config: { | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 		'export-dialog-mode': 'Full index', | 
					
						
							| 
									
										
										
										
											2016-04-16 04:17:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		'export-dialog-modes': { | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 			// XXX is this the right title???
 | 
					
						
							|  |  |  | 			// XXX this is not yet working...
 | 
					
						
							|  |  |  | 			'Save index to current location': { | 
					
						
							|  |  |  | 				action: 'saveIndexHere', | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 				data: [ | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 					'comment' | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 				], | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			'Full index': { | 
					
						
							|  |  |  | 				action: 'exportIndex', | 
					
						
							|  |  |  | 				data: [ | 
					
						
							|  |  |  | 					//'size',
 | 
					
						
							|  |  |  | 					'target_dir', | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 					'comment', | 
					
						
							|  |  |  | 				], | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			'Images only': { | 
					
						
							|  |  |  | 				action: 'exportDirs', | 
					
						
							|  |  |  | 				data: [ | 
					
						
							|  |  |  | 					'pattern', | 
					
						
							|  |  |  | 					'size', | 
					
						
							|  |  |  | 					'level_dir', | 
					
						
							|  |  |  | 					'target_dir', | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 				], | 
					
						
							|  |  |  | 			}, | 
					
						
							| 
									
										
										
										
											2016-04-16 04:17:34 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-01 19:02:28 +03:00
										 |  |  | 	// XXX this needs feedback...
 | 
					
						
							| 
									
										
										
										
											2016-04-07 16:09:29 +03:00
										 |  |  | 	// XXX should this return a promise???
 | 
					
						
							| 
									
										
										
										
											2016-04-19 03:12:57 +03:00
										 |  |  | 	saveIndexHere: ['File/Save', | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		function(){  | 
					
						
							|  |  |  | 			if(this.location.path){  | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 				this.saveIndex()  | 
					
						
							| 
									
										
										
										
											2016-04-01 19:02:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				this.browseSaveIndex() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2016-04-19 03:12:57 +03:00
										 |  |  | 	// XXX should this be a UI action???
 | 
					
						
							|  |  |  | 	// 		...at this point this depends on .saveIndexHere(..), thus 
 | 
					
						
							|  |  |  | 	// 		it is here...
 | 
					
						
							| 
									
										
										
										
											2016-04-07 16:09:29 +03:00
										 |  |  | 	// XXX should this return a promise???
 | 
					
						
							| 
									
										
										
										
											2016-04-19 03:12:57 +03:00
										 |  |  | 	saveFullIndex: ['File/Save (full)', | 
					
						
							|  |  |  | 		function(){ | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 				.markChanged('all') | 
					
						
							|  |  |  | 				.saveIndexHere()}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 	// XXX need to be able to make dirs...
 | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 	browseExportIndex: ['File/Export/Export Index to...', | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 		makeBrowseProxy('exportIndex')], | 
					
						
							|  |  |  | 	// XXX need to be able to make dirs...
 | 
					
						
							| 
									
										
										
										
											2016-04-19 02:42:21 +03:00
										 |  |  | 	browseExportDirs: ['File/Export/Export Images to...', | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 		makeBrowseProxy('exportDirs')], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Export dialog...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 	// Export <mode> is set by:
 | 
					
						
							|  |  |  | 	// 		.config['export-mode']
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The fields used and their order is determined by:
 | 
					
						
							|  |  |  | 	// 		.config['export-modes'][<mode>].data	(list)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The action used to export is determined by:
 | 
					
						
							|  |  |  | 	// 		.config['export-modes'][<mode>].action
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Dialog fields...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		// Arguments:
 | 
					
						
							|  |  |  | 	// 		//	actions		- the actions object
 | 
					
						
							|  |  |  | 	// 		//	make		- browse item constructor 
 | 
					
						
							|  |  |  | 	// 		//					(see: browse.Browser.update(..) for more info)
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 	// 		//	parent		- the parent dialog
 | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 	// 		<key>: function(actions, make, overlay){ ... },
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: .__export_dialog_fields__ can be defined both in the feature
 | 
					
						
							|  |  |  | 	// 		as well as in the instance.
 | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 	__export_dialog_fields__: { | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		'pattern': function(actions, make, parent){ | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 			return make(['Filename pattern: ',  | 
					
						
							|  |  |  | 					function(){ | 
					
						
							|  |  |  | 						return actions.config['export-preview-name-pattern'] || '%f' }]) | 
					
						
							|  |  |  | 				.on('open',  | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					widgets.makeNestedConfigListEditor(actions, parent, | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 						'export-preview-name-patterns', | 
					
						
							|  |  |  | 						'export-preview-name-pattern')) | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		'level_dir': function(actions, make, parent){ | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 			return make(['Level directory: ',  | 
					
						
							|  |  |  | 					function(){  | 
					
						
							|  |  |  | 						return actions.config['export-level-directory-name'] || 'fav' }]) | 
					
						
							|  |  |  | 				.on('open',  | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					widgets.makeNestedConfigListEditor(actions, parent, | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 						'export-level-directory-names',  | 
					
						
							|  |  |  | 						'export-level-directory-name')) | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		'size': function(actions, make, parent){ | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 			return make(['Image size: ',  | 
					
						
							|  |  |  | 					function(){  | 
					
						
							|  |  |  | 						return actions.config['export-preview-size'] || 1000 }]) | 
					
						
							|  |  |  | 				// XXX add validation???
 | 
					
						
							|  |  |  | 				.on('open',  | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					widgets.makeNestedConfigListEditor(actions, parent, | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 						'export-preview-sizes', | 
					
						
							| 
									
										
										
										
											2016-04-18 03:05:48 +03:00
										 |  |  | 						'export-preview-size', | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							sort: function(a, b){ return parseInt(a) - parseInt(b) }, | 
					
						
							|  |  |  | 						})) | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 		// XXX BUG: history closing errors -- non-critical...
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		'target_dir': function(actions, make, parent){ | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 			var elem = make(['To: ',  | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 				function(){ return actions.config['export-path'] || './' }],  | 
					
						
							|  |  |  | 				{ buttons: [ | 
					
						
							|  |  |  | 					['browse', function(p){ | 
					
						
							|  |  |  | 						var e = this.filter('"'+p+'"', false) | 
					
						
							|  |  |  | 						var path = e.find('.text').last().text() | 
					
						
							|  |  |  | 						var txt = e.find('.text').first().text() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// XXX add new dir global button...
 | 
					
						
							|  |  |  | 						return actions.browsePath(path,  | 
					
						
							|  |  |  | 							function(path){  | 
					
						
							|  |  |  | 								actions.config['export-path'] = path | 
					
						
							|  |  |  | 								actions.config['export-paths'].splice(0, 0, path) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 								parent.update() | 
					
						
							|  |  |  | 								parent.select(txt) | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 							}) | 
					
						
							| 
									
										
										
										
											2016-04-16 18:06:42 +03:00
										 |  |  | 					}], | 
					
						
							| 
									
										
										
										
											2016-04-17 01:56:52 +03:00
										 |  |  | 					// XXX BUG: closing this breaks on parant.focus()...
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					['histroy', widgets.makeNestedConfigListEditor(actions, parent, | 
					
						
							| 
									
										
										
										
											2016-04-16 18:06:42 +03:00
										 |  |  | 						'export-paths', | 
					
						
							|  |  |  | 						'export-path', | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							new_button: false, | 
					
						
							|  |  |  | 						})], | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 				]}) | 
					
						
							| 
									
										
										
										
											2016-04-16 18:06:42 +03:00
										 |  |  | 				// XXX make this editable???
 | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 				.on('open', function(){ | 
					
						
							|  |  |  | 					event.preventDefault() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					var path = elem.find('.text').last() | 
					
						
							|  |  |  | 						.makeEditable({ | 
					
						
							|  |  |  | 							clear_on_edit: false, | 
					
						
							|  |  |  | 							abort_keys: [ | 
					
						
							|  |  |  | 								'Esc', | 
					
						
							|  |  |  | 							], | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 						.on('edit-done', function(_, path){ | 
					
						
							|  |  |  | 							actions.config['export-path'] = path | 
					
						
							| 
									
										
										
										
											2016-04-18 03:05:48 +03:00
										 |  |  | 							actions.config['export-paths'].indexOf(path) < 0 | 
					
						
							|  |  |  | 								&& actions.config['export-paths'].splice(0, 0, path) | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 						.on('edit-aborted edit-done', function(evt, path){ | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 							parent.update() | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 								.then(function(){ | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 									parent.select(path) | 
					
						
							| 
									
										
										
										
											2016-04-17 00:58:21 +03:00
										 |  |  | 								}) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		'comment': function(actions, make, parent){ | 
					
						
							|  |  |  | 			var elem = make(['Comment: ',  | 
					
						
							|  |  |  | 				// XXX get staged comment???
 | 
					
						
							|  |  |  | 				function(){ return actions.getSaveComment() }]) | 
					
						
							|  |  |  | 				.on('open', function(){ | 
					
						
							|  |  |  | 					event.preventDefault() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// XXX multiline???
 | 
					
						
							|  |  |  | 					var path = elem.find('.text').last() | 
					
						
							|  |  |  | 						.makeEditable({ | 
					
						
							|  |  |  | 							multiline: true, | 
					
						
							|  |  |  | 							clear_on_edit: false, | 
					
						
							|  |  |  | 							abort_keys: [ | 
					
						
							|  |  |  | 								'Esc', | 
					
						
							|  |  |  | 							], | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 						.on('edit-done', function(_, text){ | 
					
						
							|  |  |  | 							actions.setSaveComment(text) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 						.on('edit-aborted edit-done', function(evt, text){ | 
					
						
							|  |  |  | 							parent.update() | 
					
						
							|  |  |  | 								.then(function(){ | 
					
						
							|  |  |  | 									parent.select(text) | 
					
						
							|  |  |  | 								}) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 	// XXX indicate export state: index, crop, image...
 | 
					
						
							| 
									
										
										
										
											2016-04-17 05:22:40 +03:00
										 |  |  | 	exportDialog: ['File/Export/Export optioons...', | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		widgets.makeUIDialog(function(){ | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 			var o = browse.makeLister(null, function(path, make){ | 
					
						
							|  |  |  | 				var dialog = this | 
					
						
							|  |  |  | 				var mode = that.config['export-dialog-mode'] || 'Images only' | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 				// if invalid mode get the first...
 | 
					
						
							|  |  |  | 				mode = !that.config['export-dialog-modes'][mode] ? | 
					
						
							|  |  |  | 					Object.keys(that.config['export-dialog-modes']).shift() | 
					
						
							|  |  |  | 					: mode | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 				var data = that.config['export-dialog-modes'][mode].data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// mode selector...
 | 
					
						
							|  |  |  | 				make(['Export mode: ',  | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 						function(){ return mode }]) | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 					.on('open',  | 
					
						
							|  |  |  | 						widgets.makeNestedConfigListEditor(that, o, | 
					
						
							|  |  |  | 							'export-dialog-modes', | 
					
						
							|  |  |  | 							'export-dialog-mode', | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								new_button: false, | 
					
						
							|  |  |  | 								itemButtons: [], | 
					
						
							|  |  |  | 							})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// get the root and user fields...
 | 
					
						
							|  |  |  | 				var fields = that.__export_dialog_fields__ || {} | 
					
						
							|  |  |  | 				var base_fields = FileSystemWriterUIActions.__export_dialog_fields__ || {} | 
					
						
							|  |  |  | 				// build the fields...
 | 
					
						
							|  |  |  | 				data.forEach(function(k){ | 
					
						
							|  |  |  | 					(fields[k]  | 
					
						
							|  |  |  | 							&& fields[k].call(that, that, make, dialog)) | 
					
						
							|  |  |  | 						|| (base_fields[k]  | 
					
						
							|  |  |  | 								&& base_fields[k].call(that, that, make, dialog)) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2016-04-16 04:17:34 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 				// Start/stop action...
 | 
					
						
							|  |  |  | 				make([function(){ | 
					
						
							|  |  |  | 						// XXX indicate export state: index, crop, image...
 | 
					
						
							|  |  |  | 						return 'Export'}])  | 
					
						
							|  |  |  | 					.on('open', function(){ | 
					
						
							|  |  |  | 						var mode = that.config['export-dialog-modes'][that.config['export-dialog-mode']] | 
					
						
							|  |  |  | 						that[mode.action]( | 
					
						
							| 
									
										
										
										
											2016-05-11 06:59:56 +03:00
										 |  |  | 							that.config['export-path'] || undefined) | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 						dialog.parent.close() | 
					
						
							| 
									
										
										
										
											2016-04-16 05:19:31 +03:00
										 |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2016-05-04 17:25:15 +03:00
										 |  |  | 					.addClass('selected') | 
					
						
							| 
									
										
										
										
											2016-05-04 19:26:26 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				make.done() | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 			o.dom.addClass('metadata-view tail-action') | 
					
						
							| 
									
										
										
										
											2016-04-16 03:41:45 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return o | 
					
						
							| 
									
										
										
										
											2016-04-30 05:25:43 +03:00
										 |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var FileSystemWriterUI =  | 
					
						
							|  |  |  | module.FileSystemWriterUI = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-fs-writer', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'fs-writer',  | 
					
						
							|  |  |  | 		'ui-fs-loader', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: FileSystemWriterUIActions, | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | core.ImageGridFeatures.Feature('fs', [ | 
					
						
							| 
									
										
										
										
											2016-05-26 05:36:28 +03:00
										 |  |  | 	'index-format', | 
					
						
							| 
									
										
										
										
											2016-05-22 21:10:37 +03:00
										 |  |  | 	'fs-info', | 
					
						
							| 
									
										
										
										
											2016-04-02 19:30:48 +03:00
										 |  |  | 	'fs-loader', | 
					
						
							|  |  |  | 	'fs-writer', | 
					
						
							|  |  |  | ]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-06 21:17:54 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 03:34:20 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                                                */ | 
					
						
							|  |  |  | return module }) |