| 
									
										
										
										
											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-09-09 16:35:18 +03:00
										 |  |  | // 
 | 
					
						
							| 
									
										
										
										
											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-30 17:14:55 +03:00
										 |  |  | // XXX local tags:
 | 
					
						
							| 
									
										
										
										
											2017-09-01 19:36:51 +03:00
										 |  |  | // 		- save		- done
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | // 		- load		- done
 | 
					
						
							| 
									
										
										
										
											2017-08-30 17:14:55 +03:00
										 |  |  | // 		- save/merge use...
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | // XXX merge data -- collection/crop/all
 | 
					
						
							|  |  |  | // 		- vertical only
 | 
					
						
							|  |  |  | // 		- horizontal only
 | 
					
						
							|  |  |  | // 		- both
 | 
					
						
							|  |  |  | // XXX external / linked collections (.location)...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-24 02:17:44 +03:00
										 |  |  | var MAIN_COLLECTION_TITLE = '$ALL' | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | var MAIN_COLLECTION_GID = '0' | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-09-21 01:20:08 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX should this be in config???
 | 
					
						
							|  |  |  | 		// 		...technically no, but we need shit to resolve correctly 
 | 
					
						
							|  |  |  | 		// 		to a relevant feature...
 | 
					
						
							|  |  |  | 		'collection-transfer-changes': ['data'], | 
					
						
							| 
									
										
										
										
											2017-08-24 16:00:02 +03:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											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, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 	get collectionGIDs(){ | 
					
						
							|  |  |  | 		var res = {} | 
					
						
							|  |  |  | 		var c = this.collections || {} | 
					
						
							|  |  |  | 		Object.keys(c) | 
					
						
							|  |  |  | 			.forEach(function(title){ | 
					
						
							|  |  |  | 				res[c[title].gid || title] = title | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		return res | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 	get collection(){ | 
					
						
							|  |  |  | 		return this.location.collection }, | 
					
						
							| 
									
										
										
										
											2017-08-15 16:53:55 +03:00
										 |  |  | 	set collection(value){ | 
					
						
							|  |  |  | 		this.loadCollection(value) }, | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 	get collectionGID(){ | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 		return ((this.collections || {})[this.collection] || {}).gid  | 
					
						
							|  |  |  | 			|| MAIN_COLLECTION_GID }, | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 	set collectionGID(value){ | 
					
						
							|  |  |  | 		this.collection = 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-09-17 04:11:58 +03:00
										 |  |  | 	// 		'gid': <gid>,
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	// 		<format>: <action-name>,
 | 
					
						
							|  |  |  | 	// 		...
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 	get collection_handlers(){ | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		var handlers = this.__collection_handlers = this.__collection_handlers || {} | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		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 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		// cleanup...
 | 
					
						
							|  |  |  | 		if(handlers['data'] == null){ | 
					
						
							|  |  |  | 			delete handlers['data'] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 		return handlers | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Collection events...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	collectionLoading: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`This is called by .loadCollection(..) or one of the 
 | 
					
						
							|  |  |  | 		overloading actions when collection load is done... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		The .pre phase is called just before the load and the .post phase  | 
					
						
							|  |  |  | 		just after. | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		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-09-19 01:37:31 +03:00
										 |  |  | 	collectionCreated: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`This is called when a collection is created.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this is not triggered for the "${MAIN_COLLECTION_TITLE}" collection... | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		core.notUserCallable(function(collection){ | 
					
						
							|  |  |  | 			// This is the window resize event...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// Not for direct use.
 | 
					
						
							|  |  |  | 		})], | 
					
						
							|  |  |  | 	collectionRemoved: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`This is called when a collection is removed.
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this is not triggered for the "${MAIN_COLLECTION_TITLE}" collection... | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		core.notUserCallable(function(collection){ | 
					
						
							|  |  |  | 			// This is the window resize event...
 | 
					
						
							|  |  |  | 			//
 | 
					
						
							|  |  |  | 			// Not for direct use.
 | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Collection life-cycle...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	loadCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		core.doc`Load collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 			Load collection... | 
					
						
							|  |  |  | 			.loadCollection(collection) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 			.loadCollection(gid) | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 				-> this | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 			 | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 			Force reload current collection... | 
					
						
							|  |  |  | 			.loadCollection('!') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 				NOTE: this will not call .saveCollection(..) before  | 
					
						
							|  |  |  | 					reloading, thus potentially losing some state that  | 
					
						
							|  |  |  | 					was not explicitly saved. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		When loading a collection, previous state is saved. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 16:12:47 +03:00
										 |  |  | 		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 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 21:27:17 +03:00
										 |  |  | 		Example loader action: | 
					
						
							|  |  |  | 			collectionXLoader: [ | 
					
						
							|  |  |  | 				// handle .x
 | 
					
						
							|  |  |  | 				{collectionFormat: 'x'} | 
					
						
							|  |  |  | 				function(title, state){ | 
					
						
							|  |  |  | 					return new Promise(function(resolve){  | 
					
						
							|  |  |  | 						var x = state.x | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 						// do stuff with .x
 | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 						resolve()  | 
					
						
							|  |  |  | 					}) }], | 
					
						
							| 
									
										
										
										
											2017-08-22 18:13:41 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-27 16:09:09 +03:00
										 |  |  | 		NOTE: cached collection state is persistent. | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		NOTE: when current collection is removed from .collections this  | 
					
						
							|  |  |  | 			will not save state when loading another collection... | 
					
						
							| 
									
										
										
										
											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-09-05 05:36:35 +03:00
										 |  |  | 			var force = collection == '!' | 
					
						
							|  |  |  | 			collection = collection == '!' ?  | 
					
						
							|  |  |  | 				this.collection  | 
					
						
							|  |  |  | 				: collection | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 			// if collection is a gid, get the title...
 | 
					
						
							|  |  |  | 			collection = this.collectionGIDs[collection] || collection  | 
					
						
							| 
									
										
										
										
											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-09-02 20:58:49 +03:00
										 |  |  | 			// NOTE: we save here unconditionally because MAIN_COLLECTION_TITLE
 | 
					
						
							|  |  |  | 			// 		is stored ONLY when we load some other collection...
 | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 			if(this.collection == null){ | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 			// collection...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			// NOTE: we only save if the current collection exists, it 
 | 
					
						
							|  |  |  | 			// 		may not exist if it was just removed...
 | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 			} else if(this.collection in this.collections | 
					
						
							|  |  |  | 					// prevent saving over changed current state...
 | 
					
						
							|  |  |  | 					&& !force){ | 
					
						
							| 
									
										
										
										
											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-09-02 20:58:49 +03:00
										 |  |  | 			Promise | 
					
						
							|  |  |  | 				.all(Object.keys(handlers) | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					// filter relevant handlers...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 					.filter(function(format){  | 
					
						
							|  |  |  | 						return format == '*' || collection_data[format] }) | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					// run handlers...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 					.map(function(format){ | 
					
						
							|  |  |  | 						return that[handlers[format]](collection, collection_data) })) | 
					
						
							|  |  |  | 				.then(function(){ | 
					
						
							|  |  |  | 					var data = collection_data.data | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if(!data){ | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// current...
 | 
					
						
							|  |  |  | 					data.current = data.getImage(current)  | 
					
						
							|  |  |  | 						// current is not in collection -> try and keep 
 | 
					
						
							|  |  |  | 						// the ribbon context...
 | 
					
						
							|  |  |  | 						|| that.data.getImage( | 
					
						
							|  |  |  | 							current,  | 
					
						
							|  |  |  | 							data.getImages(that.data.getImages(ribbon))) | 
					
						
							|  |  |  | 						// get closest image from collection...
 | 
					
						
							|  |  |  | 						|| that.data.getImage(current, data.order) | 
					
						
							|  |  |  | 						|| data.current | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					that | 
					
						
							|  |  |  | 						.collectionLoading.chainCall(that,  | 
					
						
							|  |  |  | 							function(){ | 
					
						
							|  |  |  | 								// do the actual load...
 | 
					
						
							|  |  |  | 								that.load.chainCall(that,  | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 									function(){ | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 										that.collectionUnloaded( | 
					
						
							|  |  |  | 											prev || MAIN_COLLECTION_TITLE) | 
					
						
							|  |  |  | 									}, { | 
					
						
							| 
									
										
										
										
											2017-09-18 14:50:15 +03:00
										 |  |  | 										location: that.location, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 										data: data, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 										crop_stack: collection_data.crop_stack | 
					
						
							|  |  |  | 											&& collection_data.crop_stack.slice(), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 										// 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,
 | 
					
						
							|  |  |  | 									}, 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 | 
					
						
							|  |  |  | 									} | 
					
						
							|  |  |  | 								} | 
					
						
							|  |  |  | 							},  | 
					
						
							|  |  |  | 							collection) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 	// XXX should this call .loadCollection('!') when saving to current
 | 
					
						
							|  |  |  | 	// 		collection???
 | 
					
						
							| 
									
										
										
										
											2017-09-06 06:15:43 +03:00
										 |  |  | 	// 		This would reaload the view to a consistent (just saved) 
 | 
					
						
							|  |  |  | 	// 		state...
 | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 	// 		...see comments inside...
 | 
					
						
							| 
									
										
										
										
											2017-09-06 06:15:43 +03:00
										 |  |  | 	// XXX it feels like we need two levels of actions, low-level that 
 | 
					
						
							|  |  |  | 	// 		just do their job and user actions that take care of 
 | 
					
						
							|  |  |  | 	// 		consistent state and the like...
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 	// XXX do we need to handle collection gids here???
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	saveCollection: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`Save current state to collection
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			Save current state to current collection | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			.saveCollection() | 
					
						
							|  |  |  | 			.saveCollection('current') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 				NOTE: this will do nothing if no collection is loaded. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			Save state as collection... | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 			.saveCollection(collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 				NOTE: if saving to self the default mode is 'crop' else | 
					
						
							|  |  |  | 					it is 'current' (see below for info on respective  | 
					
						
							|  |  |  | 					modes)... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Save current state as collection ignoring crop stack | 
					
						
							|  |  |  | 			.saveCollection(collection, 0) | 
					
						
							|  |  |  | 			.saveCollection(collection, 'current') | 
					
						
							|  |  |  | 				-> this | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			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-09-17 04:11:58 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		NOTE: this will overwrite collection .data and .crop_stack only,  | 
					
						
							|  |  |  | 			the rest of the data is untouched... | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 		NOTE: when saving to current collection and maintain consistent  | 
					
						
							|  |  |  | 			state it may be necessary to .loadCollection('!') | 
					
						
							| 
									
										
										
										
											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  | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 					&& (collection == null || collection == MAIN_COLLECTION_TITLE)){ | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			var collections = this.collections = this.collections || {} | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			var depth = typeof(mode) == typeof(123) ? mode : null | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			mode = depth == 0 ? 'current'  | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 				: depth ? 'crop'  | 
					
						
							|  |  |  | 				: mode | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			// default mode -- if saving to self then 'crop' else 'current'
 | 
					
						
							|  |  |  | 			if(!mode){ | 
					
						
							|  |  |  | 				mode = ((collection in collections  | 
					
						
							|  |  |  | 							&& collection == this.collection)  | 
					
						
							|  |  |  | 						|| collection == MAIN_COLLECTION_TITLE) ?  | 
					
						
							|  |  |  | 					'crop'  | 
					
						
							|  |  |  | 					: 'current' | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 			var new_collection =  | 
					
						
							|  |  |  | 				!collections[collection]  | 
					
						
							|  |  |  | 				&& collection != MAIN_COLLECTION_TITLE | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			// save the data...
 | 
					
						
							|  |  |  | 			var state = collections[collection] = collections[collection] || {} | 
					
						
							|  |  |  | 			state.title = state.title || collection | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 			state.gid = state.gid  | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 				// maintain the GID of MAIN_COLLECTION_TITLE as MAIN_COLLECTION_GID...
 | 
					
						
							|  |  |  | 				|| (collection == MAIN_COLLECTION_TITLE ?  | 
					
						
							|  |  |  | 					MAIN_COLLECTION_GID  | 
					
						
							|  |  |  | 					: this.data.newGID()) | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			// NOTE: we do not need to care about tags here as they 
 | 
					
						
							|  |  |  | 			// 		will get overwritten on load...
 | 
					
						
							|  |  |  | 			state.data = (mode == 'empty' ?  | 
					
						
							| 
									
										
										
										
											2017-09-06 06:37:40 +03:00
										 |  |  | 					(new this.data.constructor()) | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 				: mode == 'base' && this.crop_stack ?  | 
					
						
							|  |  |  | 					(this.crop_stack[0] || this.data.clone()) | 
					
						
							|  |  |  | 				: mode == 'crop' ?  | 
					
						
							|  |  |  | 					this.data.clone() | 
					
						
							|  |  |  | 				// current...
 | 
					
						
							|  |  |  | 				: this.data.clone() | 
					
						
							|  |  |  | 					.run(function(){ | 
					
						
							|  |  |  | 						var d = this | 
					
						
							|  |  |  | 						this.collection = collection | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					.clear('unloaded')) | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			// crop mode -> handle crop stack...
 | 
					
						
							| 
									
										
										
										
											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-09-02 20:58:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// other modes...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				delete state.crop_stack | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX this leads to recursion????
 | 
					
						
							|  |  |  | 			// 		.loadCollection('X')
 | 
					
						
							|  |  |  | 			// 			-> .saveCollection('current')
 | 
					
						
							|  |  |  | 			// 				-> .loadCollection('!')
 | 
					
						
							|  |  |  | 			// XXX should we be doing this here or on case by case basis externally...
 | 
					
						
							|  |  |  | 			//collection == this.collection
 | 
					
						
							|  |  |  | 			//	&& this.loadCollection('!')
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			new_collection | 
					
						
							|  |  |  | 				&& this.collectionCreated(collection) | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	newCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		core.doc` Shorthand to .saveCollection(collection, 'empty')`, | 
					
						
							| 
									
										
										
										
											2017-08-28 00:50:37 +03:00
										 |  |  | 		function(collection){ return this.saveCollection(collection, 'empty') }], | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 	removeCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		core.doc`
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			.removeCollection(collection) | 
					
						
							|  |  |  | 			.removeCollection(gid) | 
					
						
							|  |  |  | 				-> this | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		NOTE: when removing the currently loaded collection this will  | 
					
						
							|  |  |  | 			just remove it from .collections and do nothing...`,
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 		function(collection){ | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 			if(!this.collections || collection == MAIN_COLLECTION_TITLE){ | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 			collection = this.collectionGIDs[collection] || collection | 
					
						
							|  |  |  | 			if(collection in this.collections){ | 
					
						
							|  |  |  | 				delete this.collections[collection] | 
					
						
							|  |  |  | 				this.collectionRemoved(collection) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Introspection...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Collection editing....
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	collect: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		core.doc`Add items to collection
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 			Add current image to collection... | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			.collect('current', collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 			Add current ribbon to collection... | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			.collect('ribbon', collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 			Add loaded images to collection... | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			.collect('loaded', collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 			 | 
					
						
							|  |  |  | 			Add gid(s) to collection... | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			.collect(gid, collection) | 
					
						
							|  |  |  | 			.collect([gid, ,. ], collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 		NOTE: this will not account for item topology. To merge accounting | 
					
						
							|  |  |  | 			for topology use .joinCollect(..) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		NOTE: if an image gid is not found locally it will be searched in | 
					
						
							|  |  |  | 			base data... | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 		function(gids, collection){ | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			var that = this | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			collection = collection || this.collection | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 			collection = this.collectionGIDs[collection] || collection  | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 			if(collection == null || collection == MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			// create collection if needed...
 | 
					
						
							|  |  |  | 			(!this.collections  | 
					
						
							|  |  |  | 					|| !(collection in this.collections)) | 
					
						
							|  |  |  | 				&& this.newCollection(collection) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			gids = gids == 'loaded' ?  | 
					
						
							|  |  |  | 					this.data.getImages('loaded') | 
					
						
							|  |  |  | 				: gids == 'ribbon' ? | 
					
						
							|  |  |  | 					[this.current_ribbon] | 
					
						
							|  |  |  | 				: gids instanceof Array ?  | 
					
						
							|  |  |  | 					gids  | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 				: [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-09-19 01:37:31 +03:00
										 |  |  | 						: [ that.data.getImage(gid)  | 
					
						
							|  |  |  | 							// check base data for image gid...
 | 
					
						
							|  |  |  | 							|| that.collections[MAIN_COLLECTION_TITLE].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-09-18 18:32:34 +03:00
										 |  |  | 			collection = this.collectionGIDs[collection] || 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-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 			(!this.collections  | 
					
						
							|  |  |  | 					|| !(collection in this.collections)) | 
					
						
							|  |  |  | 				&& this.newCollection(collection) | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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())
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 				var res = this.collections[collection].data = (data || this.data) | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 					.clone() | 
					
						
							|  |  |  | 					.join(align, this.collections[collection].data) | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 				// joining into the current collection...
 | 
					
						
							|  |  |  | 				if(collection == this.collection){ | 
					
						
							|  |  |  | 					var cur = this.current | 
					
						
							|  |  |  | 					this.data = res  | 
					
						
							|  |  |  | 					this.data.current = cur | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-23 01:38:46 +03:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				this.saveCollection(collection) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-09-08 22:29:45 +03:00
										 |  |  | 	uncollect: ['Collections|Image/Remove from collection', | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 		core.doc`Remove gid(s) from collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove current image from current collection... | 
					
						
							|  |  |  | 			.uncollect() | 
					
						
							|  |  |  | 			.uncollect('current') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove gid(s) from current collection... | 
					
						
							|  |  |  | 			.uncollect(gid) | 
					
						
							|  |  |  | 			.uncollect([gid, ..]) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove gid(s) from collection... | 
					
						
							|  |  |  | 			.uncollect(gid, collection) | 
					
						
							|  |  |  | 			.uncollect([gid, ..], collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this will remove any gid, be it image or ribbon. | 
					
						
							|  |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 		{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 | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 			collection = this.collectionGIDs[collection] || collection  | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 			if(collection == null  | 
					
						
							|  |  |  | 					|| collection == MAIN_COLLECTION_TITLE | 
					
						
							|  |  |  | 					|| !this.collections  | 
					
						
							|  |  |  | 					|| !(collection in this.collections)){ | 
					
						
							| 
									
										
										
										
											2017-08-28 05:43:37 +03:00
										 |  |  | 				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) }, []) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 			// remove from the loaded state...
 | 
					
						
							|  |  |  | 			this.collection == collection | 
					
						
							|  |  |  | 				&& this.data.clear(gids) | 
					
						
							| 
									
										
										
										
											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-09-17 04:11:58 +03:00
										 |  |  | 	uncollectRibbon: ['Collections|Ribbon/Remove ribbon from collection', | 
					
						
							|  |  |  | 		core.doc`Remove ribbons from collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove current ribbon from current collection... | 
					
						
							|  |  |  | 			.uncollectRibbon() | 
					
						
							|  |  |  | 			.uncollectRibbon('current') | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove gid(s) from current collection... | 
					
						
							|  |  |  | 			.uncollectRibbon(gid) | 
					
						
							|  |  |  | 			.uncollectRibbon([gid, .. ]) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Remove gid(s) from collection... | 
					
						
							|  |  |  | 			.uncollectRibbon(gid, collection) | 
					
						
							|  |  |  | 			.uncollectRibbon([gid, .. ], collection) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this is the same as .uncollect(..) but removes whole ribbons,  | 
					
						
							|  |  |  | 			i.e. each gid given will be resolved to a ribbon which will be | 
					
						
							|  |  |  | 			removed. | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		{browseMode: function(){ return !this.collection && 'disabled' }}, | 
					
						
							|  |  |  | 		function(gids, collection){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			gids = gids || 'current' | 
					
						
							|  |  |  | 			gids = gids instanceof Array ? gids : [gids] | 
					
						
							|  |  |  | 			gids = gids.map(function(gid){ return that.data.getRibbon(gid) }) | 
					
						
							|  |  |  | 			return this.uncollect(gids, collection)  | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											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-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-09-02 21:15:57 +03:00
										 |  |  | 			var state = collections[title] = { title: title } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 			// load data...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 			var d = c[title].data == null ? | 
					
						
							|  |  |  | 					null | 
					
						
							|  |  |  | 				: c[title].data instanceof data.Data ? | 
					
						
							|  |  |  | 					c[title].data | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 				: data.Data.fromJSON(c[title].data) | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 			if(d){ | 
					
						
							|  |  |  | 				state.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-09-05 01:37:19 +03:00
										 |  |  | 	// 		XXX is this the right way to go???
 | 
					
						
							| 
									
										
										
										
											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] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-16 21:17:50 +03:00
										 |  |  | 				// build the JSON...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 21:27:17 +03:00
										 |  |  | 				var s = res.collections[title] = { title: title } | 
					
						
							| 
									
										
										
										
											2017-09-16 21:17:50 +03:00
										 |  |  | 				if(state.gid){ | 
					
						
							|  |  |  | 					s.gid = state.gid | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-08-27 21:28:02 +03:00
										 |  |  | 				var data = ((mode == 'base' && state.crop_stack) ?  | 
					
						
							|  |  |  | 						(state.crop_stack[0] || state.data) | 
					
						
							|  |  |  | 						: state.data) | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 				if(data){ | 
					
						
							|  |  |  | 					s.data = data.dumpJSON() | 
					
						
							| 
									
										
										
										
											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 | 
					
						
							|  |  |  | 	}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 	// Config and interface stuff...
 | 
					
						
							| 
									
										
										
										
											2017-09-09 16:35:18 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-30 13:09:54 +03:00
										 |  |  | 	toggleCollectionCropRetention: ['Interface/Collection crop save mode', | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 		core.makeConfigToggler( | 
					
						
							|  |  |  | 			'collection-save-crop-state',  | 
					
						
							|  |  |  | 			[ | 
					
						
							|  |  |  | 				'all', | 
					
						
							|  |  |  | 				'main',  | 
					
						
							|  |  |  | 				'none', | 
					
						
							|  |  |  | 			])], | 
					
						
							|  |  |  | 	toggleCollections: ['- Collections/Collections', | 
					
						
							|  |  |  | 		toggler.Toggler(null, | 
					
						
							|  |  |  | 			function(_, state){ | 
					
						
							|  |  |  | 				return state == null ? | 
					
						
							|  |  |  | 					// cur state...
 | 
					
						
							|  |  |  | 					(this.collection  | 
					
						
							|  |  |  | 						|| MAIN_COLLECTION_TITLE) | 
					
						
							|  |  |  | 					// new state...
 | 
					
						
							|  |  |  | 					: (this.loadCollection(state)  | 
					
						
							|  |  |  | 						&& state) }, | 
					
						
							|  |  |  | 			function(){  | 
					
						
							|  |  |  | 				return [MAIN_COLLECTION_TITLE].concat(this.collection_order || []) })], | 
					
						
							| 
									
										
										
										
											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: [ | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 		'collection-tags', | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 		'auto-collections', | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		'ui-collections', | 
					
						
							|  |  |  | 		'fs-collections', | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	actions: CollectionActions,  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 		// XXX do we need this???
 | 
					
						
							|  |  |  | 		['json.pre', | 
					
						
							|  |  |  | 			function(){ this.saveCollection() }], | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// changes...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// format:
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		// 	'collections'		- collection list changes
 | 
					
						
							|  |  |  | 		// 	'collection: <gid>'	- holds collection-specific changes
 | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 		//
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		// collection-list...
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			'collectionCreated', | 
					
						
							|  |  |  | 			'collectionRemoved', | 
					
						
							|  |  |  | 		], | 
					
						
							|  |  |  | 			function(_, collection){ | 
					
						
							|  |  |  | 				// collection list changed...
 | 
					
						
							|  |  |  | 				this.markChanged('collections') | 
					
						
							|  |  |  | 				// collection changed...
 | 
					
						
							|  |  |  | 				collection in this.collections | 
					
						
							|  |  |  | 					&& this.markChanged( | 
					
						
							|  |  |  | 						'collection: ' | 
					
						
							|  |  |  | 							+JSON.stringify(this.collections[collection].gid || collection)) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// basic collection edits...
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 		[[ | 
					
						
							|  |  |  | 			'collect', | 
					
						
							|  |  |  | 			'joinCollect', | 
					
						
							|  |  |  | 			'uncollect', | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		],  | 
					
						
							|  |  |  | 			function(_, collection){ | 
					
						
							|  |  |  | 				this.markChanged( | 
					
						
							|  |  |  | 					'collection: ' | 
					
						
							|  |  |  | 						+JSON.stringify( | 
					
						
							|  |  |  | 							this.collections[collection || this.collection].gid || collection), | 
					
						
							|  |  |  | 					['data']) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// transfer changes on load/unload collection...
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 		['collectionLoading.pre', | 
					
						
							|  |  |  | 			function(to){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 				var from = this.collection || MAIN_COLLECTION_TITLE | 
					
						
							|  |  |  | 				if(from == to || this.changes === undefined || this.changes === true){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 				// XXX this should not be in config...
 | 
					
						
							|  |  |  | 				var change_tags = this.config['collection-transfer-changes'] || ['data'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var from_changes = change_tags | 
					
						
							|  |  |  | 					.filter(function(item){ | 
					
						
							|  |  |  | 						return that.changes === true || (that.changes || {})[item] }) | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 				return function(){ | 
					
						
							|  |  |  | 					if(to == from){ | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					var gid = (this.collections[to] || {}).gid || to | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 					var changes = this.changes !== false ?  | 
					
						
							|  |  |  | 						this.changes['collection: '+JSON.stringify(gid)]  | 
					
						
							|  |  |  | 						: [] | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					var from_id = 'collection: ' | 
					
						
							|  |  |  | 						+JSON.stringify(from == MAIN_COLLECTION_TITLE ? | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 							MAIN_COLLECTION_GID | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 							: this.collections[from].gid || from) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					// everything has changed, no need to bother with details...
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 					if(changes === true){ | 
					
						
							|  |  |  | 						return | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					// save changes to 'from'...
 | 
					
						
							|  |  |  | 					from_changes.length > 0 | 
					
						
							|  |  |  | 						&& this.markChanged(from_id, from_changes) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 					// load changes from 'to'..
 | 
					
						
							|  |  |  | 					change_tags.forEach(function(item){ | 
					
						
							|  |  |  | 						if(changes && changes.indexOf(item) >= 0){ | 
					
						
							|  |  |  | 							that.markChanged(item) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 						} else if(that.changes && that.changes[item]){ | 
					
						
							|  |  |  | 							delete that.changes[item] | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 		// XXX account for 'base' mode changes...
 | 
					
						
							|  |  |  | 		// 		use : .config['collection-transfer-changes']
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 		['prepareIndexForWrite',  | 
					
						
							|  |  |  | 			function(res, _, full){ | 
					
						
							|  |  |  | 				var changed = full == true  | 
					
						
							|  |  |  | 					|| res.changes === true | 
					
						
							|  |  |  | 					|| res.changes.collections | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 				var collections = this.collections | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				if(changed && res.raw.collections){ | 
					
						
							|  |  |  | 					// select the actual changed collection list...
 | 
					
						
							|  |  |  | 					changed = changed === true ?  | 
					
						
							|  |  |  | 						Object.keys(res.raw.collections) | 
					
						
							|  |  |  | 						: changed | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// collection index...
 | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 					// XXX should this be at root or in collections/???
 | 
					
						
							|  |  |  | 					// 		...root seems better as it will let us lazy-load
 | 
					
						
							|  |  |  | 					// 		collection list without any extra effort...
 | 
					
						
							|  |  |  | 					//var index = res.index['collections/index'] = {}
 | 
					
						
							|  |  |  | 					var index = res.index['collection-index'] = {} | 
					
						
							|  |  |  | 					Object.keys(collections) | 
					
						
							|  |  |  | 						.forEach(function(title){  | 
					
						
							|  |  |  | 							index[collections[title].gid || title] = title  }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					changed | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 						// skip the raw field...
 | 
					
						
							|  |  |  | 						.filter(function(k){ return changed.indexOf(k) >= 0 }) | 
					
						
							|  |  |  | 						.forEach(function(k){ | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 							var gid = res.raw.collections[k].gid || k | 
					
						
							|  |  |  | 							var path = 'collections/'+ gid | 
					
						
							|  |  |  | 							var raw = res.raw.collections[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// collections/<gid>/metadata
 | 
					
						
							|  |  |  | 							var metadata = res.index[path +'/metadata'] = {} | 
					
						
							|  |  |  | 							Object.keys(raw) | 
					
						
							|  |  |  | 								.forEach(function(key){ metadata[key] = raw[key] }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// collections/<gid>/data
 | 
					
						
							|  |  |  | 							if(metadata.data){ | 
					
						
							|  |  |  | 								res.index[path +'/data'] = metadata.data | 
					
						
							|  |  |  | 								delete metadata.data | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 						}) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 		// XXX
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 		['prepareJSONForLoad', | 
					
						
							|  |  |  | 			function(res, json, base_path){ | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | var CollectionTagsActions = actions.Actions({ | 
					
						
							|  |  |  | 	config: { | 
					
						
							|  |  |  | 		// List of tags to be stored in a collection, unique to it...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: the rest of the tags are shared between all collections
 | 
					
						
							|  |  |  | 		// NOTE: to disable local tags either delete this, set it to null
 | 
					
						
							|  |  |  | 		// 		or to an empty list.
 | 
					
						
							|  |  |  | 		'collection-local-tags': [ | 
					
						
							|  |  |  | 			'bookmark', | 
					
						
							|  |  |  | 			'selected', | 
					
						
							|  |  |  | 		], | 
					
						
							| 
									
										
										
										
											2017-09-21 01:20:08 +03:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		// XXX this should not be in config -- see CollectionActions.config for details...
 | 
					
						
							|  |  |  | 		'collection-transfer-changes': CollectionActions.config['collection-transfer-changes'] | 
					
						
							|  |  |  | 			.concat([ | 
					
						
							|  |  |  | 				'bookmarked',  | 
					
						
							|  |  |  | 				'selected', | 
					
						
							|  |  |  | 			]), | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	collectTagged: ['- Collections|Tag/', | 
					
						
							|  |  |  | 		function(tags, collection){ | 
					
						
							|  |  |  | 			return this.collect(this.data.getTaggedByAll(tags), collection) }], | 
					
						
							|  |  |  | 	uncollectTagged: ['- Collections|Tag/', | 
					
						
							|  |  |  | 		function(tags, collection){ | 
					
						
							|  |  |  | 			return this.uncollect(this.data.getTaggedByAll(tags), collection) }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// marked...
 | 
					
						
							|  |  |  | 	collectMarked: ['- Collections|Mark/', | 
					
						
							|  |  |  | 		function(collection){ | 
					
						
							|  |  |  | 			return this.collectTagged('selected', collection) }], | 
					
						
							|  |  |  | 	uncollectMarked: ['Collections|Mark/Remove marked from collection', | 
					
						
							| 
									
										
										
										
											2017-09-06 07:59:28 +03:00
										 |  |  | 		{browseMode: function(){  | 
					
						
							|  |  |  | 			return (!this.collection || this.marked.length == 0) && 'disabled' }}, | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 		function(collection){ | 
					
						
							|  |  |  | 			return this.uncollectTagged('selected', collection) }], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// bookmarked...
 | 
					
						
							|  |  |  | 	collectBookmarked: ['- Collections|Bookmark/', | 
					
						
							|  |  |  | 		function(collection){ | 
					
						
							|  |  |  | 			return this.collectTagged('bookmark', collection) }], | 
					
						
							|  |  |  | 	uncollectBookmarked: ['Collections|Bookmark/Remove bookmarked from collection', | 
					
						
							| 
									
										
										
										
											2017-09-06 07:59:28 +03:00
										 |  |  | 		{browseMode: function(){  | 
					
						
							|  |  |  | 			return (!this.collection || this.bookmarked.length == 0) && 'disabled' }}, | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 		function(collection){ | 
					
						
							|  |  |  | 			return this.uncollectTagged('bookmark', collection) }], | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | var CollectionTags =  | 
					
						
							|  |  |  | module.CollectionTags = core.ImageGridFeatures.Feature({ | 
					
						
							| 
									
										
										
										
											2017-09-01 17:05:51 +03:00
										 |  |  | 	title: 'Collection tag handling', | 
					
						
							| 
									
										
										
										
											2017-09-03 03:44:09 +03:00
										 |  |  | 	doc: core.doc`
 | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 	What this does: | 
					
						
							|  |  |  | 	- Makes tags global through all collections | 
					
						
							|  |  |  | 	- Handles local tags per collection | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Global tags: | 
					
						
							|  |  |  | 	------------ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Global tags are shared through all the collections, this helps keep | 
					
						
							|  |  |  | 	image-specific tags, keywords and meta-information stored in tags  | 
					
						
							|  |  |  | 	global, i.e. connected to specific image and not collection.  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 19:36:51 +03:00
										 |  |  | 	Global tags are stored in .data.tags and cleared out of from the  | 
					
						
							|  |  |  | 	collection's:  | 
					
						
							|  |  |  | 		.collections[<title>].data | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Collection local tags: | 
					
						
							|  |  |  | 	---------------------- | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Local tags are listed in .config['collection-local-tags'], this makes | 
					
						
							|  |  |  | 	selection, bookmarking and other process related tags local to each  | 
					
						
							|  |  |  | 	collection. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Collection-local tags are stored in .collections[<title>].local_tags | 
					
						
							|  |  |  | 	and overwrite the corresponding tags in .data.tags on collection load. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	`,
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tag: 'collection-tags', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'collections', | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 		'tags', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX
 | 
					
						
							|  |  |  | 		'image-marks', | 
					
						
							|  |  |  | 		'image-bookmarks', | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	actions: CollectionTagsActions, | 
					
						
							| 
									
										
										
										
											2017-09-01 16:43:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 		// move tags between collections...
 | 
					
						
							|  |  |  | 		['collectionLoading.pre', | 
					
						
							|  |  |  | 			function(title){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							|  |  |  | 				var local_tag_names = this.config['collection-local-tags'] || [] | 
					
						
							|  |  |  | 				var tags = this.data.tags | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// NOTE: this is done at the .pre stage as we need to grab 
 | 
					
						
							|  |  |  | 				// 		the tags BEFORE the data gets cleared (in the case 
 | 
					
						
							|  |  |  | 				// 		of MAIN_COLLECTION_TITLE)...
 | 
					
						
							|  |  |  | 				var local_tags = (this.collections[title] || {}).local_tags || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return function(){ | 
					
						
							|  |  |  | 					// load local_tags...
 | 
					
						
							|  |  |  | 					local_tag_names | 
					
						
							|  |  |  | 						.forEach(function(tag){  | 
					
						
							|  |  |  | 							tags[tag] = local_tags[tag] || []  | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 					;(this.crop_stack || []) | 
					
						
							|  |  |  | 						.forEach(function(d){ d.tags = tags }) | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 					this.data.tags = tags | 
					
						
							|  |  |  | 					this.data.sortTags() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 		// remove tags from unloaded collections...
 | 
					
						
							| 
									
										
										
										
											2017-08-31 18:24:01 +03:00
										 |  |  | 		['collectionUnloaded', | 
					
						
							|  |  |  | 			function(_, title){ | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 				if(title in this.collections  | 
					
						
							| 
									
										
										
										
											2017-08-31 18:24:01 +03:00
										 |  |  | 						&& 'data' in this.collections[title]){ | 
					
						
							|  |  |  | 					delete this.collections[title].data.tags | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 		// remove tags when saving...
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 		['saveCollection.pre', | 
					
						
							|  |  |  | 			function(title, mode, force){ | 
					
						
							|  |  |  | 				var that = this | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 				title = title || this.collection || MAIN_COLLECTION_TITLE | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 				var local_tag_names = this.config['collection-local-tags'] || [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 17:05:51 +03:00
										 |  |  | 				// do not do anything for main collection unless force is true...
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 				if(title == MAIN_COLLECTION_TITLE && !force){ | 
					
						
							|  |  |  | 					return | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// we need this to prevent copy of tags on first save...
 | 
					
						
							|  |  |  | 				var new_set = !(title in (this.collections || {})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return function(){ | 
					
						
							|  |  |  | 					// save local tags...
 | 
					
						
							|  |  |  | 					var local_tags = this.collections[title].local_tags = {} | 
					
						
							|  |  |  | 					local_tag_names | 
					
						
							|  |  |  | 						.forEach(function(tag){  | 
					
						
							|  |  |  | 							local_tags[tag] = (!new_set || title == MAIN_COLLECTION_TITLE) ?  | 
					
						
							|  |  |  | 								(that.data.tags[tag] || [])  | 
					
						
							|  |  |  | 								: [] | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 					delete (this.collections[title].data || {}).tags | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// prevent .uncollect(..) from removing global tags...
 | 
					
						
							|  |  |  | 		// XXX this seems a bit hacky (???)
 | 
					
						
							|  |  |  | 		['uncollect.pre', | 
					
						
							|  |  |  | 			function(_, gids, title){ | 
					
						
							| 
									
										
										
										
											2017-09-01 17:05:51 +03:00
										 |  |  | 				var that = this | 
					
						
							|  |  |  | 				var local_tag_names = this.config['collection-local-tags'] || [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// prevent global tag removal...
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 				var tags = this.data.tags | 
					
						
							|  |  |  | 				delete this.data.tags | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				return function(){ | 
					
						
							| 
									
										
										
										
											2017-09-01 17:05:51 +03:00
										 |  |  | 					// update local tags...
 | 
					
						
							|  |  |  | 					local_tag_names.forEach(function(tag){ | 
					
						
							|  |  |  | 						tags[tag] = that.data.makeSparseImages(tags[tag], true) }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 					this.data.tags = tags | 
					
						
							|  |  |  | 					this.data.sortTags() | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// save .local_tags to json...
 | 
					
						
							|  |  |  | 		// NOTE: we do not need to explicitly load anything as .load() 
 | 
					
						
							|  |  |  | 		// 		will load everything we need and .collectionLoading(..)
 | 
					
						
							|  |  |  | 		// 		will .sortTags() for us...
 | 
					
						
							|  |  |  | 		['json', | 
					
						
							|  |  |  | 			function(res, mode){ | 
					
						
							|  |  |  | 				var c = this.collections | 
					
						
							|  |  |  | 				var rc = res.collections | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 				// in 'base' mode set .data.tags and .local_tags to 
 | 
					
						
							|  |  |  | 				// the base collection data...
 | 
					
						
							|  |  |  | 				if(mode == 'base'  | 
					
						
							|  |  |  | 						&& this.collection != null | 
					
						
							|  |  |  | 						&& this.collection != MAIN_COLLECTION_TITLE){ | 
					
						
							|  |  |  | 					// NOTE: at this point .crop_stack is handled, so we 
 | 
					
						
							|  |  |  | 					// 		do not need to care about it...
 | 
					
						
							|  |  |  | 					var tags = c[MAIN_COLLECTION_TITLE].local_tags || {} | 
					
						
							|  |  |  | 					var rtags =  | 
					
						
							|  |  |  | 						res.data.tags =  | 
					
						
							|  |  |  | 						res.collections[this.collection].data.tags || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// compact and overwrite the local tags for the base...
 | 
					
						
							|  |  |  | 					Object.keys(tags) | 
					
						
							|  |  |  | 						.forEach(function(tag){ | 
					
						
							|  |  |  | 							rtags[tag] = tags[tag].compact() }) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// clear and compact tags for all collections...
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 				rc | 
					
						
							|  |  |  | 					&& Object.keys(rc || {}) | 
					
						
							|  |  |  | 						.forEach(function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 							var tags = c[title].local_tags || {} | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 							var rtags = rc[title].local_tags = {} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 							// compact the local tags...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 							Object.keys(tags) | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 								.forEach(function(tag){ | 
					
						
							| 
									
										
										
										
											2017-09-01 05:35:45 +03:00
										 |  |  | 									rtags[tag] = tags[tag].compact() }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 							// no need to save the tags in more than the
 | 
					
						
							|  |  |  | 							// root .data...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 							if(rc[title].data){ | 
					
						
							|  |  |  | 								delete rc[title].data.tags | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 						}) | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// XXX should we be a bit more atomic and save tags iff
 | 
					
						
							|  |  |  | 		// 		they were changed only???
 | 
					
						
							|  |  |  | 		['prepareIndexForWrite',  | 
					
						
							|  |  |  | 			function(res, _, full){ | 
					
						
							|  |  |  | 				var raw = res.raw.collections | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// NOTE: we are cheating here, we do not need to check 
 | 
					
						
							|  |  |  | 				// 		for changes as this is already taken care off by
 | 
					
						
							|  |  |  | 				// 		the main collections feature, here we just update 
 | 
					
						
							|  |  |  | 				// 		the stuff it created...
 | 
					
						
							|  |  |  | 				// XXX should we be a bit more atomic and save tags iff
 | 
					
						
							|  |  |  | 				// 		they were changed only???
 | 
					
						
							| 
									
										
										
										
											2017-09-18 14:07:30 +03:00
										 |  |  | 				Object.keys(this.collections || {}).forEach(function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-17 04:11:58 +03:00
										 |  |  | 					var path = 'collections/'+ raw[title].gid | 
					
						
							|  |  |  | 					var metadata = res.index[path + '/metadata'] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					if(metadata && 'local_tags' in metadata){ | 
					
						
							|  |  |  | 						res.index[path +'/tags'] = metadata.local_tags | 
					
						
							|  |  |  | 						delete metadata.local_tags | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 		// XXX
 | 
					
						
							|  |  |  | 		['prepareJSONForLoad', | 
					
						
							|  |  |  | 			function(res, json, base_path){ | 
					
						
							|  |  |  | 				// XXX
 | 
					
						
							|  |  |  | 			}], | 
					
						
							| 
									
										
										
										
											2017-08-18 04:15:42 +03:00
										 |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-08-15 16:45:42 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | // XXX add UI...
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | // XXX removing items from auto-collection has no effect as it will be 
 | 
					
						
							|  |  |  | // 		reconstructed on next load -- is this the right way to go???
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | var AutoCollectionsActions = actions.Actions({ | 
					
						
							|  |  |  | 	collectionAutoLevelLoader: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		{collectionFormat: 'level_query'}, | 
					
						
							|  |  |  | 		function(title, state){  | 
					
						
							|  |  |  | 			return new Promise((function(resolve){ | 
					
						
							|  |  |  | 				var source = state.source || MAIN_COLLECTION_TITLE | 
					
						
							|  |  |  | 				source = source == MAIN_COLLECTION_TITLE ?  | 
					
						
							|  |  |  | 					((this.crop_stack || [])[0]  | 
					
						
							|  |  |  | 						|| this.data) | 
					
						
							|  |  |  | 					// XXX need a way to preload collection data...
 | 
					
						
							|  |  |  | 					: ((this.collection[source].crop_stack || [])[0]  | 
					
						
							|  |  |  | 						|| this.collections[source].data) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var query = state.level_query | 
					
						
							|  |  |  | 				query = query == 'top' ?  | 
					
						
							|  |  |  | 						[0, 1] | 
					
						
							|  |  |  | 					: query == 'bottom' ? | 
					
						
							|  |  |  | 						[-1] | 
					
						
							|  |  |  | 					: query instanceof Array ?  | 
					
						
							|  |  |  | 						query | 
					
						
							|  |  |  | 					: typeof(query) == typeof('str') ?  | 
					
						
							|  |  |  | 						query.split('+').map(function(e){ return e.trim() }) | 
					
						
							|  |  |  | 					: query > 0 ?  | 
					
						
							|  |  |  | 						[0, query] | 
					
						
							|  |  |  | 					: [query] | 
					
						
							|  |  |  | 				query = query[0] == 'top' ? | 
					
						
							|  |  |  | 						[0, parseInt(query[1])+1] | 
					
						
							|  |  |  | 					: query[0] == 'bottom' ? | 
					
						
							|  |  |  | 						[-parseInt(query[1])-1] | 
					
						
							|  |  |  | 					: query | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var levels = source.ribbon_order.slice.apply(source.ribbon_order, query) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var gids = [] | 
					
						
							|  |  |  | 				levels.forEach(function(gid){ | 
					
						
							|  |  |  | 					source.makeSparseImages(source.ribbons[gid], gids) }) | 
					
						
							|  |  |  | 				gids = gids.compact() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// get items that topped matching the query...
 | 
					
						
							|  |  |  | 				var remove = state.data ? | 
					
						
							|  |  |  | 					state.data.order | 
					
						
							|  |  |  | 						.filter(function(gid){ return gids.indexOf(gid) < 0 }) | 
					
						
							|  |  |  | 					: [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// build data...
 | 
					
						
							|  |  |  | 				state.data = data.Data.fromArray(gids) | 
					
						
							|  |  |  | 					// join with saved state...
 | 
					
						
							|  |  |  | 					.join(state.data || data.Data()) | 
					
						
							|  |  |  | 					// remove unmatching...
 | 
					
						
							|  |  |  | 					.clear(remove) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				resolve() | 
					
						
							|  |  |  | 			}).bind(this)) }], | 
					
						
							|  |  |  | 	makeAutoLevelCollection: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`Make level auto-collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		function(title, source, a, b){ | 
					
						
							|  |  |  | 			// XXX query 
 | 
					
						
							|  |  |  | 			var query = b != null ? [a, b] : a | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.saveCollection(title, 'empty') | 
					
						
							| 
									
										
										
										
											2017-09-04 22:53:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 			this.collections[title].level_query = query | 
					
						
							|  |  |  | 			this.collections[title].source = source | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-09-04 22:53:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 	// XXX do we need real tag queries???
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 	collectionAutoTagsLoader: ['- Collections/', | 
					
						
							|  |  |  | 		core.doc`
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: this will ignore local tags. | 
					
						
							|  |  |  | 		NOTE: this will prepend new matching items to the saved state. | 
					
						
							|  |  |  | 		`,
 | 
					
						
							|  |  |  | 		{collectionFormat: 'tag_query'}, | 
					
						
							|  |  |  | 		function(title, state){  | 
					
						
							|  |  |  | 			return new Promise((function(resolve){ | 
					
						
							|  |  |  | 				var local_tag_names = this.config['collection-local-tags'] || [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var tags = (state.tag_query || []) | 
					
						
							| 
									
										
										
										
											2017-09-04 22:53:29 +03:00
										 |  |  | 					.filter(function(tag){  | 
					
						
							|  |  |  | 						return local_tag_names.indexOf(tag) < 0 }) | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// XXX should this be a real tag query???
 | 
					
						
							|  |  |  | 				var gids = this.data.getTaggedByAll(tags) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-04 22:53:29 +03:00
										 |  |  | 				// get items that topped matching the query...
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 				var remove = state.data ? | 
					
						
							|  |  |  | 					state.data.order | 
					
						
							|  |  |  | 						.filter(function(gid){ return gids.indexOf(gid) < 0 }) | 
					
						
							|  |  |  | 					: [] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// build data...
 | 
					
						
							|  |  |  | 				state.data = data.Data.fromArray(gids) | 
					
						
							|  |  |  | 					// join with saved state...
 | 
					
						
							|  |  |  | 					.join(state.data || data.Data()) | 
					
						
							|  |  |  | 					// remove unmatching...
 | 
					
						
							|  |  |  | 					.clear(remove) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-02 21:27:17 +03:00
										 |  |  | 				resolve() | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 			}).bind(this)) }], | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 	makeAutoTagCollection: ['- Collections/', | 
					
						
							| 
									
										
										
										
											2017-09-03 03:07:51 +03:00
										 |  |  | 		core.doc`Make tag auto-collection...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			Make a tag auto-collection... | 
					
						
							|  |  |  | 			.makeAutoTagCollection(title, tag) | 
					
						
							|  |  |  | 			.makeAutoTagCollection(title, tag, tag, ..) | 
					
						
							|  |  |  | 			.makeAutoTagCollection(title, [tag, tag, ..]) | 
					
						
							|  |  |  | 				-> this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		NOTE: at least one tag must be supplied... | 
					
						
							|  |  |  | 		`,
 | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 		function(title, tags){ | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 			tags = arguments.length > 2 ? [].slice.call(arguments, 1) : tags | 
					
						
							| 
									
										
										
										
											2017-09-03 03:04:38 +03:00
										 |  |  | 			tags = tags instanceof Array ? tags : [tags] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if(tags.length == 0){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.saveCollection(title, 'empty') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			this.collections[title].tag_query = tags | 
					
						
							|  |  |  | 		}], | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | var AutoCollections = | 
					
						
							|  |  |  | module.AutoCollections = core.ImageGridFeatures.Feature({ | 
					
						
							|  |  |  | 	title: 'Auto collections', | 
					
						
							| 
									
										
										
										
											2017-09-03 03:44:09 +03:00
										 |  |  | 	doc: core.doc`
 | 
					
						
							| 
									
										
										
										
											2017-09-03 03:37:11 +03:00
										 |  |  | 	A collection is different from a crop in that it: | 
					
						
							|  |  |  | 		- preserves ribbon state | 
					
						
							|  |  |  | 		- preserves order | 
					
						
							|  |  |  | 		- preserves local tags | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Tag changes are handled by removing images that were untagged (no  | 
					
						
							|  |  |  | 	longer matching) from the collection and adding newly tagged/matching  | 
					
						
							|  |  |  | 	images to collection. | 
					
						
							|  |  |  | 	`,
 | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 	tag: 'auto-collections', | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | 	depends: [ | 
					
						
							|  |  |  | 		'collections', | 
					
						
							|  |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 	actions: AutoCollectionsActions, | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	handlers: [ | 
					
						
							|  |  |  | 		['json', | 
					
						
							|  |  |  | 			function(res){ | 
					
						
							|  |  |  | 				var c = this.collections || {} | 
					
						
							|  |  |  | 				var rc = res.collections || {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				Object.keys(rc) | 
					
						
							|  |  |  | 					.forEach(function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-05 01:37:19 +03:00
										 |  |  | 						var cur = c[title] | 
					
						
							|  |  |  | 						var r = rc[title] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// XXX is this the right way to go???
 | 
					
						
							|  |  |  | 						if('tag_query' in cur){ | 
					
						
							|  |  |  | 							r.tag_query = cur.tag_query | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						} else if('level_query' in cur){ | 
					
						
							|  |  |  | 							r.level_query = cur.level_query | 
					
						
							|  |  |  | 							if(cur.source){ | 
					
						
							|  |  |  | 								r.source = cur.source | 
					
						
							|  |  |  | 							} | 
					
						
							| 
									
										
										
										
											2017-09-02 21:15:57 +03:00
										 |  |  | 						} | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 	], | 
					
						
							| 
									
										
										
										
											2017-09-02 20:58:49 +03:00
										 |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | // XXX show collections in image metadata... (???)
 | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | var UICollectionActions = actions.Actions({ | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 	config: { | 
					
						
							| 
									
										
										
										
											2017-09-09 01:40:31 +03:00
										 |  |  | 		// Global default collections...
 | 
					
						
							|  |  |  | 		//
 | 
					
						
							|  |  |  | 		// NOTE: delete or set to null for none...
 | 
					
						
							|  |  |  | 		//'default-collections': null,
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	editDefaultCollections: ['Interface/Edit default collections...', | 
					
						
							| 
									
										
										
										
											2017-09-09 04:46:59 +03:00
										 |  |  | 		widgets.makeConfigListEditorDialog( | 
					
						
							|  |  |  | 			'default-collections',  | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				cls: 'collection-list', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				unique: true, | 
					
						
							|  |  |  | 				sortable: 'y', | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				normalize: function(title){  | 
					
						
							|  |  |  | 					return title.trim() }, | 
					
						
							|  |  |  | 				check: function(title){  | 
					
						
							|  |  |  | 					return title.length > 0  | 
					
						
							|  |  |  | 						&& title != MAIN_COLLECTION_TITLE }, | 
					
						
							|  |  |  | 			})], | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 	// XXX edit collection title here???
 | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	browseCollections: ['Collections/$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 = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-24 02:17:44 +03:00
										 |  |  | 			var collections = that.collection_order =  | 
					
						
							|  |  |  | 				(that.collection_order || []).slice() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 			var defaults = this.config['default-collections'] | 
					
						
							| 
									
										
										
										
											2017-09-24 02:17:44 +03:00
										 |  |  | 			if(defaults){ | 
					
						
							|  |  |  | 				collections = collections.concat(defaults).unique() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-29 20:59:00 +03:00
										 |  |  | 					var openHandler = function(_, title){ | 
					
						
							| 
									
										
										
										
											2017-09-24 02:17:44 +03:00
										 |  |  | 						var title = $(this).find('.text').attr('text') || title | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 						// create collection if it does not exist...
 | 
					
						
							|  |  |  | 						if(!that.collections  | 
					
						
							|  |  |  | 								|| !(title in that.collections)){ | 
					
						
							|  |  |  | 							that.newCollection(title) | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 						var gid = that.current | 
					
						
							|  |  |  | 						action ? | 
					
						
							|  |  |  | 							action.call(that, title) | 
					
						
							|  |  |  | 							: that.loadCollection(title) | 
					
						
							|  |  |  | 						that.focusImage(gid) | 
					
						
							|  |  |  | 						dialog.close() | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 					var setItemState = function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 						var gid = ((that.collections || {})[title] || {}).gid || title | 
					
						
							|  |  |  | 						// handle main collection changes...
 | 
					
						
							|  |  |  | 						gid = title == MAIN_COLLECTION_TITLE ?  | 
					
						
							|  |  |  | 							MAIN_COLLECTION_GID  | 
					
						
							|  |  |  | 							: gid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 						var text = this.find('.text').last() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 						// saved state...
 | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 						var unsaved = that.changes === true  | 
					
						
							|  |  |  | 							|| (that.changes || {})['collection: '+ JSON.stringify(gid)] | 
					
						
							|  |  |  | 							|| (that.collectionGID == gid  | 
					
						
							|  |  |  | 								&& (that.config['collection-transfer-changes'] || []) | 
					
						
							|  |  |  | 									.filter(function(a){  | 
					
						
							|  |  |  | 										return !!(that.changes || {})[a] }).length > 0) | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 						unsaved | 
					
						
							|  |  |  | 							&& text.attr('unsaved', true) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 						// indicate collection crop...
 | 
					
						
							|  |  |  | 						var cs =  | 
					
						
							|  |  |  | 							title == (that.collection || MAIN_COLLECTION_TITLE) ?  | 
					
						
							|  |  |  | 								that.crop_stack | 
					
						
							|  |  |  | 							: (that.collections || {})[title] ? | 
					
						
							|  |  |  | 								that.collections[title].crop_stack | 
					
						
							|  |  |  | 							: null | 
					
						
							|  |  |  | 						cs | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 							&& text.attr('cropped', cs.length) | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 					// update collection list if changed externally...
 | 
					
						
							|  |  |  | 					// XXX do we need this???
 | 
					
						
							|  |  |  | 					collections.splice.apply(collections, [0, collections.length].concat( | 
					
						
							|  |  |  | 						collections | 
					
						
							|  |  |  | 							.concat(this.collection_order || []) | 
					
						
							|  |  |  | 							.unique())) | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 					// main collection...
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 					!action  | 
					
						
							|  |  |  | 						&& collections.indexOf(MAIN_COLLECTION_TITLE) < 0 | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 						&& 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('☰')) | 
					
						
							| 
									
										
										
										
											2017-09-18 18:32:34 +03:00
										 |  |  | 									setItemState | 
					
						
							| 
									
										
										
										
											2017-09-24 04:26:37 +03:00
										 |  |  | 										//.call($(this), title)
 | 
					
						
							|  |  |  | 										.call($(this), $(this).find('.text').attr('text')) | 
					
						
							| 
									
										
										
										
											2017-08-29 20:59:00 +03:00
										 |  |  | 								}, | 
					
						
							|  |  |  | 								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-09-18 18:32:34 +03:00
										 |  |  | 							each: setItemState,  | 
					
						
							| 
									
										
										
										
											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-09-24 04:26:37 +03:00
										 |  |  | 					selected: JSON.stringify( | 
					
						
							|  |  |  | 						(that.collection || MAIN_COLLECTION_TITLE) | 
					
						
							|  |  |  | 							// XXX not sure it is good that we have to do this...
 | 
					
						
							|  |  |  | 							.replace(/\$/g, '')), | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 				.close(function(){ | 
					
						
							| 
									
										
										
										
											2017-09-24 02:17:44 +03:00
										 |  |  | 					that.collection_order = collections | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					to_remove | 
					
						
							|  |  |  | 						.forEach(function(title){ that.removeCollection(title) })  | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 		})], | 
					
						
							| 
									
										
										
										
											2017-09-08 18:52:51 +03:00
										 |  |  | 	browseImageCollections: ['Collections|Image/Image $collections...', | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 		widgets.makeUIDialog(function(gid){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			gid = this.data.getImage(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 			var defaults = this.config['default-collections'] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-09 01:22:30 +03:00
										 |  |  | 					if(defaults){ | 
					
						
							|  |  |  | 						all = all.concat(defaults).unique() | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											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-09-09 16:35:18 +03:00
										 |  |  | 	// Collection actions with collection selection...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 	// XXX should we warn the user when overwriting???
 | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	saveAsCollection: ['Collections/$Save as collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-05 05:36:35 +03:00
										 |  |  | 				this.saveCollection(title, 'current')  | 
					
						
							|  |  |  | 				// XXX should we be doing this manually here or in .saveCollection(..)
 | 
					
						
							|  |  |  | 				title == this.collection | 
					
						
							|  |  |  | 					&& this.loadCollection('!') | 
					
						
							|  |  |  | 			}) })], | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	addToCollection: ['Collections|Image/Add $image to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(gids){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							| 
									
										
										
										
											2017-09-09 13:47:33 +03:00
										 |  |  | 				this.collect(gids || 'current', title) }) })], | 
					
						
							|  |  |  | 	addRibbonToCollection: ['Collections|Ribbon/Add $ribbon to collection...', | 
					
						
							|  |  |  | 		widgets.uiDialog(function(){ return this.addToCollection('ribbon') })], | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	addLoadedToCollection: ['Collections/$Add loaded images to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ return this.addToCollection('loaded') })], | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	joinToCollection: ['Collections/$Merge view to collection...', | 
					
						
							| 
									
										
										
										
											2017-08-17 19:53:39 +03:00
										 |  |  | 		widgets.uiDialog(function(){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							|  |  |  | 				this.joinCollect(title) }) })], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 	// XXX should this be here???
 | 
					
						
							|  |  |  | 	addMarkedToCollection: ['Collections|Mark/Add marked to $collection...', | 
					
						
							| 
									
										
										
										
											2017-09-06 07:59:28 +03:00
										 |  |  | 		{browseMode: function(){  | 
					
						
							|  |  |  | 			return this.marked.length == 0 && 'disabled' }}, | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 		widgets.uiDialog(function(gids){ | 
					
						
							|  |  |  | 			return this.browseCollections(function(title){ | 
					
						
							|  |  |  | 				this.collectMarked(gids || this.current, 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', | 
					
						
							| 
									
										
										
										
											2017-09-06 07:20:31 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// XXX needed only for .addMarkedToCollection(..)
 | 
					
						
							|  |  |  | 		'collection-tags', | 
					
						
							| 
									
										
										
										
											2017-08-16 05:41:49 +03:00
										 |  |  | 	], | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	actions: UICollectionActions,  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 	handlers: [ | 
					
						
							| 
									
										
										
										
											2017-09-01 05:04:38 +03:00
										 |  |  | 		// we need to do this as we transfer tags after everything is 
 | 
					
						
							|  |  |  | 		// loaded...
 | 
					
						
							|  |  |  | 		['collectionLoading', | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				this.reload()  | 
					
						
							|  |  |  | 			}], | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-09-19 01:37:31 +03:00
										 |  |  | 		// update view when editing current collection...
 | 
					
						
							|  |  |  | 		[[ | 
					
						
							|  |  |  | 			'uncollect',  | 
					
						
							|  |  |  | 			'joinCollect', | 
					
						
							|  |  |  | 		], | 
					
						
							| 
									
										
										
										
											2017-08-22 02:11:23 +03:00
										 |  |  | 			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-09-01 05:04:38 +03:00
										 |  |  | 		['load clear reload collectionLoading 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-09-09 16:35:18 +03:00
										 |  |  | // XXX collection id...
 | 
					
						
							| 
									
										
										
										
											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 }) |