| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | var data = require('imagegrid/data') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | var toggler = require('lib/toggler') | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | var actions = require('lib/actions') | 
					
						
							|  |  |  | var features = require('lib/features') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | var browse = require('lib/widget/browse') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | var core = require('features/core') | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | var widgets = require('features/ui-widgets') | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | // XXX should collections be in the Crop menu????
 | 
					
						
							| 
									
										
										
										
											2017-08-23 19:52:17 +03:00
										 |  |  | // 		...essentially a collection is a saved crop, so this would be 
 | 
					
						
							|  |  |  | // 		logical, would simplify control, etc.
 | 
					
						
							|  |  |  | // 		
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | var MAIN_COLLECTION_TITLE = 'ALL' | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | // XXX things we need to do to collections:
 | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | // 		- auto-collections
 | 
					
						
							|  |  |  | // 			- tags -- adding/removing images adds/removes tags
 | 
					
						
							|  |  |  | // 			- ribbons -- top / bottom / n-m / top+2 / ..
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | // XXX might be a good idea to make collection loading part of the 
 | 
					
						
							|  |  |  | // 		.load(..) protocol...
 | 
					
						
							|  |  |  | // 		...this could be done via a url suffix, as a shorthand.
 | 
					
						
							|  |  |  | // 		something like:
 | 
					
						
							|  |  |  | // 			/path/to/index:collection
 | 
					
						
							|  |  |  | // 				-> /path/to/index/sub/path/.ImageGrid/collections/collection
 | 
					
						
							|  |  |  | // XXX loading collections by direct path would require us to look 
 | 
					
						
							|  |  |  | // 		in the containing index for missing parts (*images.json, ...)
 | 
					
						
							|  |  |  | // XXX saving a local collection would require us to save to two 
 | 
					
						
							|  |  |  | // 		locations:
 | 
					
						
							|  |  |  | // 			- collection specific stuff (data) to collection path
 | 
					
						
							|  |  |  | // 			- global stuff (images, tags, ...) to base index...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | // XXX handle tags here???
 | 
					
						
							|  |  |  | // 		...keep them global or local to collection???
 | 
					
						
							|  |  |  | // 		global sounds better...
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:14:55 +03:00
										 |  |  | // XXX local tags:
 | 
					
						
							|  |  |  | // 		- save -- done, test
 | 
					
						
							|  |  |  | // 		- load
 | 
					
						
							|  |  |  | // 		- save/merge use...
 | 
					
						
							|  |  |  | // XXX selection/tag based .collect()/.uncollect() actions...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | // XXX undo...
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | var CollectionActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2017-08-24 16:00:02 +03:00
										 |  |  | 	config: { | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 		// can be:
 | 
					
						
							|  |  |  | 		// 	'all'		- save crop state for all collections (default)
 | 
					
						
							|  |  |  | 		// 	'main'		- save crop state for main state only
 | 
					
						
							|  |  |  | 		// 	'none'		- do not save crop state
 | 
					
						
							|  |  |  | 		'collection-save-crop-state': 'all', | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 		// List of tags to be stored in a collection, unique to it...
 | 
					
						
							|  |  |  | 		'collection-local-tags': [ | 
					
						
							|  |  |  | 			'bookmark', | 
					
						
							|  |  |  | 			'selected', | 
					
						
							|  |  |  | 		], | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-24 16:00:02 +03:00
										 |  |  | 		// XXX add default collection list to config...
 | 
					
						
							|  |  |  | 		'default-collections': [ | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		<title>: {
 | 
					
						
							|  |  |  | 	// 			title: <title>,
 | 
					
						
							|  |  |  | 	// 			gid: <gid>,
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 	// 			crop_stack: [ .. ],
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	// 			// base collection format -- raw data...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	// 			data: <data>,
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	// 			...
 | 
					
						
							|  |  |  | 	// 		},
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 	collections: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get collection(){ | 
					
						
							|  |  |  | 		return this.location.collection }, | 
					
						
							| 
									
										
										
										
											2017-08-15 16:53:55 +03:00
										 |  |  | 	set collection(value){ | 
					
						
							|  |  |  | 		this.loadCollection(value) }, | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 23:58:52 +03:00
										 |  |  | 	// XXX should this check consistency???
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 	get collection_order(){ | 
					
						
							|  |  |  | 		if(this.collections == null){ | 
					
						
							|  |  |  | 			return null | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var collections = this.collections | 
					
						
							|  |  |  | 		var keys = Object.keys(collections) | 
					
						
							|  |  |  | 		var order = this.__collection_order = this.__collection_order || [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// add unsorted things to the head of the list...
 | 
					
						
							|  |  |  | 		var res = keys | 
					
						
							|  |  |  | 			.concat(order) | 
					
						
							|  |  |  | 			.reverse() | 
					
						
							|  |  |  | 			.unique() | 
					
						
							|  |  |  | 			.reverse() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 		// keep MAIN_COLLECTION_TITLE out of the collection order...
 | 
					
						
							|  |  |  | 		var m = res.indexOf(MAIN_COLLECTION_TITLE) | 
					
						
							|  |  |  | 		m >= 0 | 
					
						
							|  |  |  | 			&& res.splice(m, 1) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 		// remove stuff not present...
 | 
					
						
							|  |  |  | 		if(res.length > keys.length){ | 
					
						
							|  |  |  | 			res = res.filter(function(e){ return e in collections }) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 		this.__collection_order.splice(0, this.__collection_order.length, ...res) | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return this.__collection_order | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	set collection_order(value){ | 
					
						
							|  |  |  | 		this.__collection_order = value }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 	get collections_length(){ | 
					
						
							|  |  |  | 		var c = (this.collections || {}) | 
					
						
							|  |  |  | 		return MAIN_COLLECTION_TITLE in c ?  | 
					
						
							|  |  |  | 			Object.keys(c).length - 1 | 
					
						
							|  |  |  | 			: Object.keys(c).length | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	// 		// NOTE: this is always the first handler...
 | 
					
						
							|  |  |  | 	// 		'data': <action-name>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	// 		<format>: <action-name>,
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should these get auto-sorted???
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	get collection_handlers(){ | 
					
						
							|  |  |  | 		var handlers = this.__collection_handlers || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(Object.keys(handlers).length == 0){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			handlers['data'] = null | 
					
						
							|  |  |  | 			this.actions.forEach(function(action){ | 
					
						
							|  |  |  | 				var fmt = that.getActionAttr(action, 'collectionFormat') | 
					
						
							|  |  |  | 				if(fmt){ | 
					
						
							|  |  |  | 					handlers[fmt] = action | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return handlers | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	collectionDataLoader: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 		core.doc`Collection data loader
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 			.collectionDataLoader(title, data) | 
					
						
							|  |  |  | 				-> promise | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		The resulting promise will resolve to a Data object that will get | 
					
						
							|  |  |  | 		loaded as the collection. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		data is of the .collections item format. | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		This will not clone .data, this all changes made to it are  | 
					
						
							|  |  |  | 		persistent. | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 		{collectionFormat: 'data'}, | 
					
						
							|  |  |  | 		function(title, data){  | 
					
						
							|  |  |  | 			return new Promise(function(resolve){ resolve(data.data) }) }], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 	// XXX load local_tags...
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	loadCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		core.doc`Load collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		This will get collection data and crop into it. | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 		If .data for a collection is not available this will do nothing,  | 
					
						
							|  |  |  | 		this enables extending actions to handle the collection in  | 
					
						
							|  |  |  | 		different ways. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 		Protocol: | 
					
						
							|  |  |  | 		- collection format handlers: .collection_handlers | 
					
						
							|  |  |  | 			- built from actions that define .collectionFormat attr to  | 
					
						
							|  |  |  | 			  contain the target format string. | 
					
						
							|  |  |  | 		- format is determined by matching it to a key in .collections[collection] | 
					
						
							|  |  |  | 			e.g. 'data' is applicable if .collections[collection].data is not null | 
					
						
							|  |  |  | 		- the format key's value is passed to the handler action | 
					
						
							|  |  |  | 		- the handler is expected to return a promise | 
					
						
							|  |  |  | 		- only the first matching handler is called | 
					
						
							|  |  |  | 		- the data handler is always first to get checked | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		For an example handler see: | 
					
						
							|  |  |  | 			.collectionDataLoader(..) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		The .data handler is always first to enable caching, i.e. once some | 
					
						
							|  |  |  | 		non-data handler is done, it can set the .data which will be loaded | 
					
						
							|  |  |  | 		directly the next time. | 
					
						
							|  |  |  | 		To invalidate such a cache .data should simply be deleted. | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: cached collection state is persistent. | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		function(collection){ | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 			if(collection == null  | 
					
						
							|  |  |  | 					|| this.collections == null  | 
					
						
							|  |  |  | 					|| !(collection in this.collections)){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			var crop_mode = this.config['collection-save-crop-state'] || 'all' | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 			var current = this.current | 
					
						
							|  |  |  | 			var ribbon = this.current_ribbon | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			var prev = this.collection | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 			var collection_data = this.collections[collection] | 
					
						
							|  |  |  | 			var handlers = this.collection_handlers | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			// save current collection state...
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			//
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 			// main view...
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			if(this.collection == null){ | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 				var tags = this.data.tags | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 				this.saveCollection( | 
					
						
							|  |  |  | 					MAIN_COLLECTION_TITLE,  | 
					
						
							| 
									
										
										
										
											2017-08-31 15:30:15 +03:00
										 |  |  | 					crop_mode == 'none' ?  'base' : 'crop',  | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 					true) | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 				// keep the tags...
 | 
					
						
							|  |  |  | 				this.collections[MAIN_COLLECTION_TITLE].data.tags = tags | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// collection...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2017-08-31 15:30:15 +03:00
										 |  |  | 				this.saveCollection( | 
					
						
							|  |  |  | 					this.collection,  | 
					
						
							|  |  |  | 					crop_mode == 'all' ? 'crop': null) | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// load collection...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 			for(var format in handlers){ | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 				if(collection_data[format]){ | 
					
						
							|  |  |  | 					return this[handlers[format]](collection, collection_data) | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 						.then(function(data){ | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 							if(!data){ | 
					
						
							|  |  |  | 								return | 
					
						
							|  |  |  | 							} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// current...
 | 
					
						
							|  |  |  | 							data.current = data.getImage(current)  | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 								// current is not in collection -> try and keep 
 | 
					
						
							|  |  |  | 								// the ribbon context...
 | 
					
						
							|  |  |  | 								|| that.data.getImage( | 
					
						
							|  |  |  | 									current,  | 
					
						
							|  |  |  | 									data.getImages(that.data.getImages(ribbon))) | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 								// get closest image from collection...
 | 
					
						
							|  |  |  | 								|| that.data.getImage(current, data.order) | 
					
						
							|  |  |  | 								|| data.current | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 							data.tags = that.data.tags | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 							// XXX load local_tags...
 | 
					
						
							|  |  |  | 							// XXX
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 							// NOTE: tags and other position dependant 
 | 
					
						
							|  |  |  | 							// 		data needs to be updated as collections
 | 
					
						
							|  |  |  | 							// 		may contain different numbers/orders of
 | 
					
						
							|  |  |  | 							// 		images...
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 							// XXX
 | 
					
						
							|  |  |  | 							//data.updateImagePositions()
 | 
					
						
							|  |  |  | 							data.sortTags() | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							that.load({ | 
					
						
							|  |  |  | 								data: data, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 								crop_stack: collection_data.crop_stack | 
					
						
							|  |  |  | 									&& collection_data.crop_stack.slice(), | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 								// NOTE: we do not need to pass collections 
 | 
					
						
							|  |  |  | 								// 		and order here as they stay in from 
 | 
					
						
							|  |  |  | 								// 		the last .load(..) in merge mode...
 | 
					
						
							|  |  |  | 								//collections: that.collections,
 | 
					
						
							|  |  |  | 								//collection_order: that.collection_order,
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 							}, true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// maintain the .collection state...
 | 
					
						
							|  |  |  | 							if(collection == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 								// no need to maintain the main data in two 
 | 
					
						
							|  |  |  | 								// locations...
 | 
					
						
							|  |  |  | 								delete that.collections[MAIN_COLLECTION_TITLE] | 
					
						
							|  |  |  | 								delete this.location.collection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							} else { | 
					
						
							|  |  |  | 								that.data.collection = that.location.collection = collection | 
					
						
							|  |  |  | 								// cleanup...
 | 
					
						
							|  |  |  | 								if(collection == null){ | 
					
						
							|  |  |  | 									delete this.location.collection | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 							// collection events...
 | 
					
						
							|  |  |  | 							that | 
					
						
							|  |  |  | 								.collectionUnloaded(prev || MAIN_COLLECTION_TITLE) | 
					
						
							|  |  |  | 								.collectionLoaded(collection)	 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	// events...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	collectionLoaded: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`This is called by .loadCollection(..) or one of the 
 | 
					
						
							|  |  |  | 		overloading actions when collection load is done... | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		core.notUserCallable(function(collection){ | 
					
						
							|  |  |  | 			// This is the window resize event...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// Not for direct use.
 | 
					
						
							|  |  |  | 		})], | 
					
						
							|  |  |  | 	collectionUnloaded: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`This is called when unloading a collection.
 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		core.notUserCallable(function(collection){ | 
					
						
							|  |  |  | 			// This is the window resize event...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// Not for direct use.
 | 
					
						
							|  |  |  | 		})], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 	// XXX saving into current collection will leave the viewer in an 
 | 
					
						
							|  |  |  | 	// 		inconsistent state:
 | 
					
						
							|  |  |  | 	// 			- collection X is indicated as loaded
 | 
					
						
							|  |  |  | 	// 			- collection X has different state than what is loaded
 | 
					
						
							|  |  |  | 	// 		...not sure how to deal with this yet...
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	saveCollection: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`Save current state to collection
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			Save Current state to current collection | 
					
						
							|  |  |  | 			.saveCollection() | 
					
						
							|  |  |  | 			.saveCollection('current') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 				NOTE: this will do nothing if no collection is loaded. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 			Save Current state as collection | 
					
						
							|  |  |  | 			.saveCollection(collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Save new empty collection | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			.saveCollection(collection, 'empty') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Save current crop state to collection | 
					
						
							|  |  |  | 			.saveCollection(collection, 'crop') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Save top depth crops from current crop stack to collection | 
					
						
							|  |  |  | 			.saveCollection(collection, depth) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Save base crop state to collection | 
					
						
							|  |  |  | 			.saveCollection(collection, 'base') | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 				-> this | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 		function(collection, mode, force){ | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2017-08-15 16:53:55 +03:00
										 |  |  | 			collection = collection || this.collection | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			collection = collection == 'current' ? this.collection : collection | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 			if(!force  | 
					
						
							|  |  |  | 					&& (collection == null  | 
					
						
							|  |  |  | 						|| collection == MAIN_COLLECTION_TITLE)){ | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			var depth = typeof(mode) == typeof(123) ? mode : null | 
					
						
							|  |  |  | 			mode = depth == 0 ? null  | 
					
						
							|  |  |  | 				: depth ? 'crop'  | 
					
						
							|  |  |  | 				: mode | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 			var collections = this.collections = this.collections || {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 			// prepare local lags...
 | 
					
						
							|  |  |  | 			//var local_tags = {}
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 			var local_tags = (collections[collection] || {}).local_tags || {} | 
					
						
							|  |  |  | 			;(this.config['collection-local-tags'] || []) | 
					
						
							|  |  |  | 				.forEach(function(tag){  | 
					
						
							|  |  |  | 					local_tags[tag] = local_tags[tag] || [] }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			var state = collections[collection] = { | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 				title: collection, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 				// NOTE: we do not need to care about tags here as they 
 | 
					
						
							|  |  |  | 				// 		will get overwritten on load...
 | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 				data: (mode == 'empty' ?  | 
					
						
							|  |  |  | 							(new this.data.constructor()) | 
					
						
							|  |  |  | 						: mode == 'base' && this.crop_stack ?  | 
					
						
							|  |  |  | 							(this.crop_stack[0] || this.data.clone()) | 
					
						
							|  |  |  | 						: mode == 'crop' ?  | 
					
						
							|  |  |  | 							this.data.clone() | 
					
						
							|  |  |  | 						: this.data.clone() | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 							.run(function(){ | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 								var d = this | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 								this.collection = collection | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 								// save local tags...
 | 
					
						
							|  |  |  | 								Object.keys(local_tags) | 
					
						
							|  |  |  | 									.forEach(function(tag){  | 
					
						
							|  |  |  | 										local_tags[tag] = (d.tags[tag] || []).slice() }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 								// optimization: 
 | 
					
						
							|  |  |  | 								// 		avoid processing .tags as we'll 
 | 
					
						
							|  |  |  | 								// 		overwrite them anyway later...
 | 
					
						
							|  |  |  | 								delete this.tags  | 
					
						
							|  |  |  | 							}) | 
					
						
							| 
									
										
										
										
											2017-08-30 00:27:43 +03:00
										 |  |  | 							.clear('unloaded')), | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				local_tags: local_tags, | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			if(mode == 'crop' && this.crop_stack && depth != 0){ | 
					
						
							|  |  |  | 				depth = depth || this.crop_stack.length | 
					
						
							|  |  |  | 				depth = this.crop_stack.length - Math.min(depth, this.crop_stack.length) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				state.crop_stack = this.crop_stack.slice(depth) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	newCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 		function(collection){ return this.saveCollection(collection, 'empty') }], | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	// XXX should we do anything special if collection is loaded???
 | 
					
						
							|  |  |  | 	removeCollection: ['- Collections/', | 
					
						
							|  |  |  | 		function(collection){ | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			if(collection == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 			delete this.collections[collection] | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	inCollections: ['- Image/', | 
					
						
							|  |  |  | 		core.doc`Get list of collections containing item`, | 
					
						
							|  |  |  | 		function(gid){ | 
					
						
							| 
									
										
										
										
											2017-08-15 16:53:55 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 			gid = this.data.getImage(gid) | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 			//return Object.keys(this.collections || {})
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			return (this.collection_order || []) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:53:55 +03:00
										 |  |  | 				.filter(function(c){ | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					return c != MAIN_COLLECTION_TITLE | 
					
						
							|  |  |  | 						&& (!gid  | 
					
						
							|  |  |  | 							|| that.collections[c].data.getImage(gid)) }) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	collect: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		core.doc`Add items to collection
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this will not account for item topology.`,
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		function(gids, collection){ | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			collection = collection || this.collection | 
					
						
							|  |  |  | 			if(collection == null || collection == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 			gids = gids == 'loaded' ? this.data.getImages('loaded') | 
					
						
							|  |  |  | 				: gids instanceof Array ? gids  | 
					
						
							|  |  |  | 				: [gids] | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 			gids = gids | 
					
						
							|  |  |  | 				.map(function(gid){  | 
					
						
							|  |  |  | 					return gid in that.data.ribbons ?  | 
					
						
							|  |  |  | 						// when adding a ribbon gid expand to images...
 | 
					
						
							|  |  |  | 						that.data.ribbons[gid].compact() | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 						: [that.data.getImage(gid)] }) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 				.reduce(function(a, b){ return a.concat(b) }, []) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 			// add to collection...
 | 
					
						
							|  |  |  | 			var data = this.data.constructor.fromArray(gids) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return this.joinCollect(null, collection, data) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	joinCollect: ['- Collections/Merge to collection', | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 		core.doc`Merge/Join current state to collection
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			Join current state into collection | 
					
						
							|  |  |  | 			.joinCollect(collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Join current state with specific alignment into collection | 
					
						
							|  |  |  | 			.joinCollect(align, collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 			Join data to collection with specific alignment | 
					
						
							|  |  |  | 			.joinCollect(align, collection, data) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		This is like .collect(..) but will preserve topology. | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		NOTE: for align docs see Data.join(..) | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 		NOTE: if align is set to null or not given then it will be set  | 
					
						
							|  |  |  | 			to default value. | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 		NOTE: this will join to the left (prepend) of the collections, this is  | 
					
						
							|  |  |  | 			different from how basic .join(..) works (appends) | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 		function(align, collection, data){ | 
					
						
							|  |  |  | 			collection = arguments.length == 1 ? align : collection | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			if(collection == null || collection == MAIN_COLLECTION_TITLE){ | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | 			// if only collection is given, reset align to null...
 | 
					
						
							|  |  |  | 			align = align === collection ? null : align | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 			if(this.collections && this.collections[collection]){ | 
					
						
							|  |  |  | 				//this.collections[collection].data.join(align, data || this.data.clone())
 | 
					
						
							|  |  |  | 				this.collections[collection].data = (data || this.data) | 
					
						
							|  |  |  | 					.clone() | 
					
						
							|  |  |  | 					.join(align, this.collections[collection].data) | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				this.saveCollection(collection) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 	uncollect: ['Collections|Image/$Uncollect image', | 
					
						
							|  |  |  | 		{browseMode: function(){ return !this.collection && 'disabled' }}, | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		function(gids, collection){ | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			collection = collection || this.collection | 
					
						
							|  |  |  | 			if(collection == null || collection == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gids = gids == 'loaded' ? this.data.getImages('loaded') | 
					
						
							|  |  |  | 				: gids instanceof Array ? gids  | 
					
						
							|  |  |  | 				: [gids] | 
					
						
							|  |  |  | 			gids = gids | 
					
						
							|  |  |  | 				.map(function(gid){  | 
					
						
							|  |  |  | 					return gid in that.data.ribbons ?  | 
					
						
							|  |  |  | 						// when adding a ribbon gid expand to images...
 | 
					
						
							|  |  |  | 						that.data.ribbons[gid].compact() | 
					
						
							|  |  |  | 						: [that.data.getImage(gid)] }) | 
					
						
							|  |  |  | 				.reduce(function(a, b){ return a.concat(b) }, []) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(this.collection == collection){ | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 				// need to keep this from updating .tags...
 | 
					
						
							|  |  |  | 				// XXX this seems a bit hacky...
 | 
					
						
							|  |  |  | 				var tags = this.data.tags | 
					
						
							|  |  |  | 				delete this.data.tags | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 				this.data | 
					
						
							| 
									
										
										
										
											2017-08-30 00:13:38 +03:00
										 |  |  | 					.clear(gids) | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					.run(function(){ | 
					
						
							|  |  |  | 						this.tags = tags | 
					
						
							|  |  |  | 						this.sortTags() | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			// NOTE: we do both this and the above iff data is cloned...
 | 
					
						
							|  |  |  | 			// NOTE: if tags are saved to the collection it means that 
 | 
					
						
							|  |  |  | 			// 		those tags are local to the collection and we do not 
 | 
					
						
							|  |  |  | 			// 		need to protect them...
 | 
					
						
							|  |  |  | 			if(this.data !== this.collections[collection].data){ | 
					
						
							|  |  |  | 				this.collections[collection].data | 
					
						
							| 
									
										
										
										
											2017-08-30 00:13:38 +03:00
										 |  |  | 					.clear(gids) | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Serialization...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 	// NOTE: this will handle collection title and data only, the rest 
 | 
					
						
							|  |  |  | 	// 		is copied in as-is.
 | 
					
						
							|  |  |  | 	// 		It is the responsibility of the extending features to transform
 | 
					
						
							|  |  |  | 	// 		their data on load as needed.
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX handle local_tags...
 | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 	load: [function(json){ | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 		var collections = {} | 
					
						
							|  |  |  | 		var c = json.collections || {} | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 		var order = json.collection_order || Object.keys(c) | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if((json.location || {}).collection){ | 
					
						
							|  |  |  | 			this.location.collection = json.location.collection | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 		Object.keys(c).forEach(function(title){ | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			// load data...
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			var d = c[title].data instanceof data.Data ? | 
					
						
							|  |  |  | 				c[title].data | 
					
						
							|  |  |  | 				: data.Data | 
					
						
							|  |  |  | 					.fromJSON(c[title].data | 
					
						
							|  |  |  | 					.run(function(){ | 
					
						
							|  |  |  | 						this.tags = this.tags || that.data.tags | 
					
						
							|  |  |  | 					})) | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			var state = collections[title] = { | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 				title: title, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 				data: d, | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			// NOTE: this can be done lazily when loading each collection
 | 
					
						
							|  |  |  | 			// 		but doing so will make the system more complex and 
 | 
					
						
							|  |  |  | 			// 		confuse (or complicate) some code that expects 
 | 
					
						
							|  |  |  | 			// 		.collections[*].crop_stack[*] to be instances of Data.
 | 
					
						
							|  |  |  | 			if(c[title].crop_stack){ | 
					
						
							|  |  |  | 				state.crop_stack = c[title].crop_stack | 
					
						
							|  |  |  | 					.map(function(c){  | 
					
						
							|  |  |  | 						return c instanceof data.Data ?  | 
					
						
							|  |  |  | 							c  | 
					
						
							|  |  |  | 							: data.Data(c) }) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			// copy the rest of collection data as-is...
 | 
					
						
							|  |  |  | 			Object.keys(c[title]) | 
					
						
							|  |  |  | 				.forEach(function(key){ | 
					
						
							|  |  |  | 					if(key in state){ | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					state[key] = c[title][key] | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 		return function(){ | 
					
						
							|  |  |  | 			if(Object.keys(collections).length > 0){ | 
					
						
							|  |  |  | 				this.collection_order = order | 
					
						
							|  |  |  | 				this.collections = collections | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}], | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Supported modes:
 | 
					
						
							|  |  |  | 	// 	current (default) 	- ignore collections
 | 
					
						
							|  |  |  | 	// 	base				- save only base data in each collection and
 | 
					
						
							|  |  |  | 	// 							the main collection is saved as current
 | 
					
						
							|  |  |  | 	// 	full				- full current state.
 | 
					
						
							|  |  |  | 	// 	
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 	// NOTE: we do not store .collection_order here, because we order 
 | 
					
						
							|  |  |  | 	// 		the collections in the object.
 | 
					
						
							|  |  |  | 	// 		...when saving a partial collection set, for example in
 | 
					
						
							|  |  |  | 	// 		.prepareIndexForWrite(..) it would be necessary to add it 
 | 
					
						
							|  |  |  | 	// 		in to maintain the correct order when merging... (XXX)
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 	// NOTE: currently this only stores title and data, it is the 
 | 
					
						
							|  |  |  | 	// 		responsibility of extending features to store their specific 
 | 
					
						
							|  |  |  | 	// 		data in collections...
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX handle local_tags...
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 	json: [function(mode){ return function(res){ | 
					
						
							|  |  |  | 		mode = mode || 'current' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 		var collections = this.collections | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 		// NOTE: if mode is 'current' ignore collections...
 | 
					
						
							|  |  |  | 		if(mode != 'current' && collections){ | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 			var order = this.collection_order | 
					
						
							| 
									
										
										
										
											2017-08-30 17:11:45 +03:00
										 |  |  | 			// NOTE: .collection_order does not return MAIN_COLLECTION_TITLE 
 | 
					
						
							|  |  |  | 			// 		so we have to add it in manually...
 | 
					
						
							|  |  |  | 			order = MAIN_COLLECTION_TITLE in collections ? | 
					
						
							|  |  |  | 				order.concat([MAIN_COLLECTION_TITLE]) | 
					
						
							|  |  |  | 				: order | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			// in base mode save the main view as current...
 | 
					
						
							|  |  |  | 			if(mode == 'base' && this.collection){ | 
					
						
							|  |  |  | 				var main = collections[MAIN_COLLECTION_TITLE] | 
					
						
							|  |  |  | 				res.data =  (main.crop_stack ?  | 
					
						
							|  |  |  | 						(main.crop_stack[0] || main.data) | 
					
						
							|  |  |  | 						: main.data) | 
					
						
							|  |  |  | 					.dumpJSON() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				delete res.location.collection | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 			res.collections = {} | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 			order.forEach(function(title){ | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 				// in base mode skip the main collection...
 | 
					
						
							|  |  |  | 				if(mode == 'base' && title == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var state = collections[title] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var data = ((mode == 'base' && state.crop_stack) ?  | 
					
						
							|  |  |  | 						(state.crop_stack[0] || state.data) | 
					
						
							|  |  |  | 						: state.data) | 
					
						
							|  |  |  | 					.dumpJSON() | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 				delete data.tags | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 				var s = res.collections[title] = { | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 					title: title, | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 					data: data,  | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// handle .crop_stack of collection...
 | 
					
						
							|  |  |  | 				// NOTE: in base mode, crop_stack is ignored...
 | 
					
						
							|  |  |  | 				if(mode != 'base' && state.crop_stack){ | 
					
						
							|  |  |  | 					s.crop_stack = state.crop_stack | 
					
						
							|  |  |  | 						.map(function(d){ return d.dumpJSON() }) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} }], | 
					
						
							| 
									
										
										
										
											2017-08-27 22:17:47 +03:00
										 |  |  | 	clone: [function(full){ | 
					
						
							|  |  |  | 		return function(res){ | 
					
						
							|  |  |  | 			if(this.collections){ | 
					
						
							|  |  |  | 				var cur = this.collections | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(this.collection){ | 
					
						
							|  |  |  | 					res.location.collection = this.collection | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				collections = res.collections = {} | 
					
						
							|  |  |  | 				this.collection_order | 
					
						
							|  |  |  | 					.forEach(function(title){ | 
					
						
							|  |  |  | 						var c = collections[title] = { | 
					
						
							|  |  |  | 							title: title, | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if(cur[title].data){ | 
					
						
							|  |  |  | 							c.data = cur[title].data.clone() | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						if(cur[title].crop_stack){ | 
					
						
							|  |  |  | 							c.crop_stack = cur[title].crop_stack | 
					
						
							|  |  |  | 								.map(function(d){ return d.clone() }) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		} }], | 
					
						
							| 
									
										
										
										
											2017-08-30 13:09:54 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	clear: [function(){ | 
					
						
							|  |  |  | 		this.collection | 
					
						
							|  |  |  | 			&& this.collectionUnloaded('*') | 
					
						
							|  |  |  | 		delete this.collections | 
					
						
							|  |  |  | 		delete this.__collection_order | 
					
						
							|  |  |  | 		delete this.location.collection | 
					
						
							|  |  |  | 	}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Config...
 | 
					
						
							|  |  |  | 	toggleCollectionCropRetention: ['Interface/Collection crop save mode', | 
					
						
							|  |  |  | 		core.makeConfigToggler('collection-save-crop-state', ['all', 'main', 'none'])], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | var Collection =  | 
					
						
							|  |  |  | module.Collection = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'collections', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'base', | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 		'location', | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		'crop', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	suggested: [ | 
					
						
							|  |  |  | 		'ui-collections', | 
					
						
							|  |  |  | 		'fs-collections', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: CollectionActions,  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 		// XXX maintain changes...
 | 
					
						
							|  |  |  | 		// 		- collection-level: mark collections as changed...
 | 
					
						
							|  |  |  | 		// 		- in-collection:
 | 
					
						
							|  |  |  | 		// 			- save/restore parent changes when loading/exiting collections
 | 
					
						
							|  |  |  | 		// 			- move collection chnages to collections
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			'collect', | 
					
						
							|  |  |  | 			'joinCollect', | 
					
						
							|  |  |  | 			'uncollect', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'saveCollection', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			'removeCollection', | 
					
						
							|  |  |  | 		],  | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				// XXX mark changed collections...
 | 
					
						
							|  |  |  | 				// XXX added/removed collection -> mark collection index as changed...
 | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		['prepareIndexForWrite',  | 
					
						
							|  |  |  | 			function(res, _, full){ | 
					
						
							|  |  |  | 				var changed = full == true  | 
					
						
							|  |  |  | 					|| res.changes === true | 
					
						
							|  |  |  | 					|| res.changes.collections | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(changed && res.raw.collections){ | 
					
						
							|  |  |  | 					// select the actual changed collection list...
 | 
					
						
							|  |  |  | 					changed = changed === true ?  | 
					
						
							|  |  |  | 						Object.keys(res.raw.collections) | 
					
						
							|  |  |  | 						: changed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// collection index...
 | 
					
						
							|  |  |  | 					res.index['collection-index'] = Object.keys(this.collections) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					Object.keys(changed) | 
					
						
							|  |  |  | 						// skip the raw field...
 | 
					
						
							|  |  |  | 						.filter(function(k){ return changed.indexOf(k) >= 0 }) | 
					
						
							|  |  |  | 						.forEach(function(k){ | 
					
						
							|  |  |  | 							// XXX use collection gid...
 | 
					
						
							|  |  |  | 							res.index['collections/' + k] = res.raw.collections[k] | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		['prepareJSONForLoad', | 
					
						
							|  |  |  | 			function(res, json, base_path){ | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX show collections in image metadata...
 | 
					
						
							|  |  |  | var UICollectionActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	browseCollections: ['Collections|Crop/$Collec$tions...', | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 		core.doc`Collection list...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: collections are added live and not on dialog close... | 
					
						
							|  |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.makeUIDialog(function(action){ | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 			var to_remove = [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return browse.makeLister(null,  | 
					
						
							|  |  |  | 				function(path, make){ | 
					
						
							|  |  |  | 					var dialog = this | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 						.on('update', function(){ | 
					
						
							|  |  |  | 							that.collection | 
					
						
							|  |  |  | 								&& dialog.filter(JSON.stringify(that.collection)) | 
					
						
							|  |  |  | 									.addClass('highlighted') | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					var openHandler = function(_, title){ | 
					
						
							|  |  |  | 						var gid = that.current | 
					
						
							|  |  |  | 						action ? | 
					
						
							|  |  |  | 							action.call(that, title) | 
					
						
							|  |  |  | 							: that.loadCollection(title) | 
					
						
							|  |  |  | 						that.focusImage(gid) | 
					
						
							|  |  |  | 						dialog.close() | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					var setCroppedState = function(title){ | 
					
						
							|  |  |  | 						// indicate collection crop...
 | 
					
						
							|  |  |  | 						var cs =  | 
					
						
							|  |  |  | 							title == (that.collection || MAIN_COLLECTION_TITLE) ?  | 
					
						
							|  |  |  | 								that.crop_stack | 
					
						
							|  |  |  | 							: (that.collections || {})[title] ? | 
					
						
							|  |  |  | 								that.collections[title].crop_stack | 
					
						
							|  |  |  | 							: null | 
					
						
							|  |  |  | 						cs | 
					
						
							|  |  |  | 							&& this.find('.text').last() | 
					
						
							|  |  |  | 								.attr('cropped', cs.length) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 					//var collections = Object.keys(that.collections || {})
 | 
					
						
							|  |  |  | 					var collections = that.collection_order = that.collection_order || [] | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					// main collection...
 | 
					
						
							|  |  |  | 					!action && collections.indexOf(MAIN_COLLECTION_TITLE) < 0 | 
					
						
							|  |  |  | 						&& make([ | 
					
						
							|  |  |  | 								MAIN_COLLECTION_TITLE, | 
					
						
							|  |  |  | 							],  | 
					
						
							|  |  |  | 							{ events: { | 
					
						
							|  |  |  | 								update: function(_, title){ | 
					
						
							|  |  |  | 									// make this look almost like a list element...
 | 
					
						
							|  |  |  | 									// XXX hack???
 | 
					
						
							|  |  |  | 									$(this).find('.text:first-child') | 
					
						
							|  |  |  | 										.before($('<span>') | 
					
						
							|  |  |  | 											.css('color', 'transparent') | 
					
						
							|  |  |  | 											.addClass('sort-handle') | 
					
						
							|  |  |  | 											.html('☰')) | 
					
						
							|  |  |  | 									setCroppedState | 
					
						
							|  |  |  | 										.call($(this), title) | 
					
						
							|  |  |  | 								}, | 
					
						
							|  |  |  | 								open: openHandler, | 
					
						
							|  |  |  | 							}}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// collection list...
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 					make.EditableList(collections,  | 
					
						
							|  |  |  | 						{ | 
					
						
							|  |  |  | 							unique: true, | 
					
						
							| 
									
										
										
										
											2017-08-25 22:31:46 +03:00
										 |  |  | 							sortable: 'y', | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 							to_remove: to_remove, | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							itemopen: openHandler, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 							normalize: function(title){  | 
					
						
							|  |  |  | 								return title.trim() }, | 
					
						
							|  |  |  | 							check: function(title){  | 
					
						
							|  |  |  | 								return title.length > 0 }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 							each: setCroppedState,  | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 							itemadded: function(title){ | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 								action ? | 
					
						
							|  |  |  | 									that.newCollection(title) | 
					
						
							|  |  |  | 									: that.saveCollection(title) }, | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 							disabled: action ? [MAIN_COLLECTION_TITLE] : false, | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 				}, { | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					cls: 'collection-list', | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 					// focus current collection...
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 					selected: that.collection || MAIN_COLLECTION_TITLE, | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 				.close(function(){ | 
					
						
							|  |  |  | 					to_remove.forEach(function(title){  | 
					
						
							|  |  |  | 						that.removeCollection(title)  | 
					
						
							|  |  |  | 					})  | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 	browseImageCollections: ['Image/$Collections...', | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		{dialogTitle: 'Image Collections...'}, | 
					
						
							|  |  |  | 		widgets.makeUIDialog(function(gid){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			gid = this.data.getImage(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 			var all | 
					
						
							|  |  |  | 			var collections | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var to_remove | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			return browse.makeLister(null,  | 
					
						
							|  |  |  | 				function(path, make){ | 
					
						
							|  |  |  | 					var dialog = this | 
					
						
							| 
									
										
										
										
											2017-08-19 02:01:20 +03:00
										 |  |  | 						.on('update', function(){ | 
					
						
							|  |  |  | 							that.collection | 
					
						
							|  |  |  | 								&& dialog.filter(JSON.stringify(that.collection)) | 
					
						
							|  |  |  | 									.addClass('highlighted') | 
					
						
							|  |  |  | 						}) | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-26 02:57:49 +03:00
										 |  |  | 					//all = Object.keys(that.collections || {})
 | 
					
						
							|  |  |  | 					all = that.collection_order = that.collection_order || [] | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					collections = collections  | 
					
						
							|  |  |  | 						|| that.inCollections(gid || null) | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					// build the disabled list...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 					if(!to_remove){ | 
					
						
							|  |  |  | 						to_remove = [] | 
					
						
							|  |  |  | 						all.forEach(function(title){ | 
					
						
							|  |  |  | 							collections.indexOf(title) < 0 | 
					
						
							|  |  |  | 								&& to_remove.push(title) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 					all.length > 0 ? | 
					
						
							|  |  |  | 						make.EditableList(all,  | 
					
						
							|  |  |  | 							{ | 
					
						
							|  |  |  | 								new_item: false, | 
					
						
							|  |  |  | 								to_remove: to_remove, | 
					
						
							| 
									
										
										
										
											2017-08-29 21:19:13 +03:00
										 |  |  | 								itemopen: function(_, title){ | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 									var i = to_remove.indexOf(title) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									i >= 0 ?  | 
					
						
							|  |  |  | 										to_remove.splice(i, 1)  | 
					
						
							|  |  |  | 										: to_remove.push(title) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 									dialog.update() | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 								}, | 
					
						
							|  |  |  | 							}) | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 						: make.Empty('No collections...') | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 				.close(function(){ | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 					all.forEach(function(title){ | 
					
						
							|  |  |  | 						collections.indexOf(title) < 0 | 
					
						
							|  |  |  | 							&& to_remove.indexOf(title) < 0 | 
					
						
							|  |  |  | 							&& that.collect(gid, title) | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 					to_remove.forEach(function(title){  | 
					
						
							|  |  |  | 						that.uncollect(gid, title) | 
					
						
							|  |  |  | 					})  | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		})], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | 	// Collections actions with collection selection...
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	// XXX should we warn the user when overwriting???
 | 
					
						
							| 
									
										
										
										
											2017-08-23 19:52:17 +03:00
										 |  |  | 	saveAsCollection: ['Collections|Crop/$Save as collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							|  |  |  | 				this.saveCollection(title) }) })], | 
					
						
							| 
									
										
										
										
											2017-08-23 19:52:17 +03:00
										 |  |  | 	addToCollection: ['Collections|Crop|Image/Add $image to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(gids){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							|  |  |  | 				this.collect(gids || this.current, title) }) })], | 
					
						
							| 
									
										
										
										
											2017-08-23 19:52:17 +03:00
										 |  |  | 	addLoadedToCollection: ['Collections|Crop/$Add loaded images to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ return this.addToCollection('loaded') })], | 
					
						
							| 
									
										
										
										
											2017-08-23 19:52:17 +03:00
										 |  |  | 	joinToCollection: ['Collections|Crop/$Merge view to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							|  |  |  | 				this.joinCollect(title) }) })], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	/*/ XXX this is not used by metadata yet... | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	metadataSection: ['- Image/', | 
					
						
							|  |  |  | 		function(gid, make){ | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	//*/
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var UICollection =  | 
					
						
							|  |  |  | module.UICollection = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'ui-collections', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'ui', | 
					
						
							|  |  |  | 		'collections', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: UICollectionActions,  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 		// update view when removing from current collection...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 		['uncollect', | 
					
						
							|  |  |  | 			function(_, gids, collection){ | 
					
						
							|  |  |  | 				(collection == null || this.collection == collection) | 
					
						
							|  |  |  | 					&& this.reload(true) | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// maintain crop viewer state when loading/unloading collections...
 | 
					
						
							| 
									
										
										
										
											2017-08-28 01:14:11 +03:00
										 |  |  | 		['load clear reload collectionLoaded collectionUnloaded', | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			function(){ | 
					
						
							| 
									
										
										
										
											2017-08-28 01:14:11 +03:00
										 |  |  | 				if(!this.dom){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 				this.dom[this.collection ?  | 
					
						
							|  |  |  | 					'addClass'  | 
					
						
							|  |  |  | 					: 'removeClass']('collection-mode') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				this.dom[this.cropped ?  | 
					
						
							|  |  |  | 					'addClass'  | 
					
						
							|  |  |  | 					: 'removeClass']('crop-mode') | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | // XXX Things to try/do:
 | 
					
						
							|  |  |  | // 		- save collection on exit/write (?)
 | 
					
						
							|  |  |  | // 		- lazy load collections (load list, lazy-load data)
 | 
					
						
							| 
									
										
										
										
											2017-08-26 05:29:47 +03:00
										 |  |  | // 			- collection index
 | 
					
						
							|  |  |  | // 		- load directories as collections (auto?)...
 | 
					
						
							| 
									
										
										
										
											2017-08-18 01:19:55 +03:00
										 |  |  | // 		- export collections to directories...
 | 
					
						
							| 
									
										
										
										
											2017-08-26 05:29:47 +03:00
										 |  |  | // 		- auto-export collections (on save)...
 | 
					
						
							|  |  |  | // 			- add new images
 | 
					
						
							|  |  |  | // 			- remove old images...
 | 
					
						
							|  |  |  | // 		- collection history (same as ctrl-shift-h)...
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var FileSystemCollectionActions = actions.Actions({ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	// Format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		path: <string>,
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	collections: null, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	collectionPathLoader: ['- Collections/', | 
					
						
							|  |  |  | 		{collectionFormat: 'path'}, | 
					
						
							|  |  |  | 		function(data, loader){  | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 		}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	importCollectionsFromPath: ['- Collections|File/Import collections from path', | 
					
						
							|  |  |  | 		function(path){ | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 			// XXX
 | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | // XXX manage format...
 | 
					
						
							|  |  |  | // XXX manage changes...
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | var FileSystemCollection =  | 
					
						
							|  |  |  | module.FileSystemCollection = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: '', | 
					
						
							|  |  |  | 	doc: '', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'fs-collections', | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		'index-format', | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		'fs', | 
					
						
							|  |  |  | 		'collections', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 	actions: FileSystemCollectionActions, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | // XXX localstorage-collections (???)
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |