mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 11:20:09 +00:00 
			
		
		
		
	refactoring + a several util methods in tags.js
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									158da70086
								
							
						
					
					
						commit
						1667632227
					
				| @ -132,9 +132,8 @@ if(typeof(sha1) != 'undefined'){ | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*********************************************************************/ | /*********************************************************************/ | ||||||
|  | // Data...
 | ||||||
| 
 | 
 | ||||||
| // Data class methods and API...
 |  | ||||||
| //
 |  | ||||||
| var DataClassPrototype = { | var DataClassPrototype = { | ||||||
| 	// NOTE: we consider the input list sorted...
 | 	// NOTE: we consider the input list sorted...
 | ||||||
| 	fromArray: function(list){ | 	fromArray: function(list){ | ||||||
| @ -157,12 +156,6 @@ var DataClassPrototype = { | |||||||
| 	}, | 	}, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /*********************************************************************/ |  | ||||||
| 
 |  | ||||||
| // Data object methods and API...
 |  | ||||||
| //
 |  | ||||||
| var DataPrototype = { | var DataPrototype = { | ||||||
| 
 | 
 | ||||||
| 	get version(){  | 	get version(){  | ||||||
| @ -231,6 +224,9 @@ var DataPrototype = { | |||||||
| 	//
 | 	//
 | ||||||
| 	/*****************************************************************/ | 	/*****************************************************************/ | ||||||
| 
 | 
 | ||||||
|  | 	ribbon_order: null, | ||||||
|  | 	ribbons: null, | ||||||
|  | 
 | ||||||
| 	get current(){ | 	get current(){ | ||||||
| 		return this.__current = this.__current  | 		return this.__current = this.__current  | ||||||
| 			|| this.getImages(this.ribbon_order[0])[0] | 			|| this.getImages(this.ribbon_order[0])[0] | ||||||
| @ -238,11 +234,12 @@ var DataPrototype = { | |||||||
| 	set current(value){ | 	set current(value){ | ||||||
| 		this.focusImage(value) }, | 		this.focusImage(value) }, | ||||||
| 
 | 
 | ||||||
| 	// XXX should this default to top or bottom ribbon???
 |  | ||||||
| 	get base(){ | 	get base(){ | ||||||
| 		return this.__base || this.ribbon_order[0] }, | 		return this.__base || this.ribbon_order[0] }, | ||||||
| 	set base(value){ | 	set base(value){ | ||||||
| 		this.__base = value }, | 		this.__base = value in this.ribbons ? | ||||||
|  | 			this.getRibbon(value) | ||||||
|  | 			: value }, | ||||||
| 
 | 
 | ||||||
| 	get order(){ | 	get order(){ | ||||||
| 		return this.__order }, | 		return this.__order }, | ||||||
| @ -427,7 +424,6 @@ var DataPrototype = { | |||||||
| 		return res | 		return res | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| 	// Remove duplicate items from list in-place...
 | 	// Remove duplicate items from list in-place...
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// NOTE: only the first occurrence is kept...
 | 	// NOTE: only the first occurrence is kept...
 | ||||||
| @ -1554,10 +1550,7 @@ var DataPrototype = { | |||||||
| 	// This is signature compatible with .getRibbon(..), see it for more
 | 	// This is signature compatible with .getRibbon(..), see it for more
 | ||||||
| 	// info...
 | 	// info...
 | ||||||
| 	setBase: function(target, offset){ | 	setBase: function(target, offset){ | ||||||
| 		var base = this.getRibbon(target, offset) | 		this.base = this.getRibbon(target, offset) | ||||||
| 		if(base in this.ribbons){ |  | ||||||
| 			this.base = base |  | ||||||
| 		} |  | ||||||
| 		return this | 		return this | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
| @ -2858,7 +2851,6 @@ var DataPrototype = { | |||||||
| 		var that = this | 		var that = this | ||||||
| 		data = typeof(data) == typeof('str') ? JSON.parse(data) : data | 		data = typeof(data) == typeof('str') ? JSON.parse(data) : data | ||||||
| 		data = formats.updateData(data, DATA_VERSION) | 		data = formats.updateData(data, DATA_VERSION) | ||||||
| 		this.base = data.base |  | ||||||
| 		this.order = data.order.slice() | 		this.order = data.order.slice() | ||||||
| 		this.ribbon_order = data.ribbon_order.slice() | 		this.ribbon_order = data.ribbon_order.slice() | ||||||
| 
 | 
 | ||||||
| @ -2876,6 +2868,7 @@ var DataPrototype = { | |||||||
| 		}) | 		}) | ||||||
| 
 | 
 | ||||||
| 		this.current = data.current | 		this.current = data.current | ||||||
|  | 		this.base = data.base | ||||||
| 
 | 
 | ||||||
| 		// extra data...
 | 		// extra data...
 | ||||||
| 		!clean | 		!clean | ||||||
| @ -2926,8 +2919,17 @@ var DataPrototype = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | ||||||
| 
 | 
 | ||||||
| /*********************************************************************/ | var BaseData =  | ||||||
|  | module.BaseData =  | ||||||
|  | object.makeConstructor('BaseData',  | ||||||
|  | 		DataClassPrototype,  | ||||||
|  | 		DataPrototype) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // XXX make a API compatible replacement to the above -- to access 
 | // XXX make a API compatible replacement to the above -- to access 
 | ||||||
| // 		compatibility and performance...
 | // 		compatibility and performance...
 | ||||||
| @ -3220,7 +3222,17 @@ var DataWithTagsPrototype = { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*********************************************************************/ | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | ||||||
|  | 
 | ||||||
|  | var DataWithTags =  | ||||||
|  | module.DataWithTags =  | ||||||
|  | object.makeConstructor('DataWithTags',  | ||||||
|  | 		DataClassPrototype,  | ||||||
|  | 		DataWithTagsPrototype) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| // Proxy Data API to one of the target data objects...
 | // Proxy Data API to one of the target data objects...
 | ||||||
| var DataProxyPrototype = { | var DataProxyPrototype = { | ||||||
| @ -3236,28 +3248,13 @@ var DataProxyPrototype = { | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /*********************************************************************/ |  | ||||||
| 
 |  | ||||||
| // Main Data object...
 |  | ||||||
| var BaseData =  |  | ||||||
| module.BaseData =  |  | ||||||
| object.makeConstructor('BaseData',  |  | ||||||
| 		DataClassPrototype,  |  | ||||||
| 		DataPrototype) |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| var DataWithTags =  |  | ||||||
| module.DataWithTags =  |  | ||||||
| object.makeConstructor('DataWithTags',  |  | ||||||
| 		DataClassPrototype,  |  | ||||||
| 		DataWithTagsPrototype) |  | ||||||
| 
 | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
| 
 | 
 | ||||||
| var Data = | var Data = | ||||||
| module.Data = DataWithTags | module.Data = DataWithTags | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
| /********************************************************************** | /********************************************************************** | ||||||
| * vim:set ts=4 sw=4 :                               */ return module }) | * vim:set ts=4 sw=4 :                               */ return module }) | ||||||
|  | |||||||
| @ -49,7 +49,7 @@ var normalizeSplit = function(args){ | |||||||
| 
 | 
 | ||||||
| /*********************************************************************/ | /*********************************************************************/ | ||||||
| 
 | 
 | ||||||
| var TagsClassPrototype = { | var BaseTagsClassPrototype = { | ||||||
| 	// Utils...
 | 	// Utils...
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// 	.normalize(tag)
 | 	// 	.normalize(tag)
 | ||||||
| @ -207,74 +207,42 @@ var TagsClassPrototype = { | |||||||
| // 		...there are two ways to think of this:
 | // 		...there are two ways to think of this:
 | ||||||
| // 			1) both (a-la flickr) -- keep both, use normalized internally
 | // 			1) both (a-la flickr) -- keep both, use normalized internally
 | ||||||
| // 			2) only normalized -- simpler but may surprise the user and not be as pretty...
 | // 			2) only normalized -- simpler but may surprise the user and not be as pretty...
 | ||||||
| var TagsPrototype = { | // XXX should we split out the non-basic stuff???
 | ||||||
|  | // 		like:
 | ||||||
|  | // 			.makePathsPersistent()
 | ||||||
|  | // 			.optimizeTags()
 | ||||||
|  | // 			...
 | ||||||
|  | var BaseTagsPrototype = { | ||||||
| 	config: { | 	config: { | ||||||
| 		tagRemovedChars: '[\\s-_]', | 		tagRemovedChars: '[\\s-_]', | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
| 	// data...
 | 	// Tag index...
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// Format:
 |  | ||||||
| 	// 	Set([ <tag>, ... ])
 |  | ||||||
| 	//
 |  | ||||||
| 	// XXX Q: should these be normalized???
 |  | ||||||
| 	__persistent_tags: null, |  | ||||||
| 
 |  | ||||||
| 	// Format:
 |  | ||||||
| 	// 	{
 |  | ||||||
| 	// 		<alias>: <normalized-tag>,
 |  | ||||||
| 	// 	}
 |  | ||||||
| 	//
 |  | ||||||
| 	// XXX need introspection for this...
 |  | ||||||
| 	// 		...should this be .aliases ???
 |  | ||||||
| 	__aliases: null, |  | ||||||
| 
 |  | ||||||
| 	// Format:
 | 	// Format:
 | ||||||
| 	// 	{
 | 	// 	{
 | ||||||
| 	// 		<tag>: [ <item>, ... ],
 | 	// 		<tag>: [ <item>, ... ],
 | ||||||
| 	// 		...
 | 	// 		...
 | ||||||
| 	// 	}
 | 	// 	}
 | ||||||
|  | 	//
 | ||||||
| 	__index: null, | 	__index: null, | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | 	// Persistent tags...
 | ||||||
|  | 	//
 | ||||||
|  | 	// Format:
 | ||||||
|  | 	// 	Set([ <tag>, ... ])
 | ||||||
|  | 	//
 | ||||||
|  | 	persistent: null, | ||||||
| 
 | 
 | ||||||
| 	// XXX EXPERIMENTAL...
 | 	// Tag aliases...
 | ||||||
| 	// XXX need a way to edit the compound tag...
 | 	//
 | ||||||
| 	__special_tag_handlers__: { | 	// Format:
 | ||||||
| 		'*persistent*': function(action, tag, value){ | 	// 	{
 | ||||||
| 			// XXX remove the tag...
 | 	// 		<alias>: <normalized-tag>,
 | ||||||
| 			// XXX add the tag to .__persistent_tags
 | 	// 	}
 | ||||||
| 			// XXX return the new tag for normal handling...
 | 	//
 | ||||||
| 		}, | 	aliases: null, | ||||||
| 	}, |  | ||||||
| 	handleSpecialTag: function(action, tag, value){ |  | ||||||
| 		var that = this |  | ||||||
| 		var handlers = this.__special_tag_handlers__ || {} |  | ||||||
| 
 |  | ||||||
| 		// get the matching handler key...
 |  | ||||||
| 		var key = Object.keys(handlers) |  | ||||||
| 			.filter(function(k){  |  | ||||||
| 				return that.match(k, tag) }) |  | ||||||
| 			// XXX should we handle multiple matches???
 |  | ||||||
| 			.shift() |  | ||||||
| 
 |  | ||||||
| 		// resolve handler aliases...
 |  | ||||||
| 		var match = key |  | ||||||
| 		do { |  | ||||||
| 			match = handlers[match]	 |  | ||||||
| 		} while(!(match instanceof Function) && match in handlers) |  | ||||||
| 
 |  | ||||||
| 		// no handler...
 |  | ||||||
| 		if(!(match instanceof Function)){ |  | ||||||
| 			// XXX
 |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 
 |  | ||||||
| 		// XXX remove key from tag...
 |  | ||||||
| 
 |  | ||||||
| 		return match.call(this, action, tag, value) |  | ||||||
| 	}, |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 	// Utils...
 | 	// Utils...
 | ||||||
| @ -569,6 +537,41 @@ var TagsPrototype = { | |||||||
| 				//return that.directMatch(query, t, cmp) }) },
 | 				//return that.directMatch(query, t, cmp) }) },
 | ||||||
| 				return that.match(query, t, cmp) }) }, | 				return that.match(query, t, cmp) }) }, | ||||||
| 
 | 
 | ||||||
|  | 	// Keep only the longest matching paths...
 | ||||||
|  | 	//
 | ||||||
|  | 	// 	.uniquePaths(path, ..)
 | ||||||
|  | 	// 	.uniquePaths([path, ..])
 | ||||||
|  | 	// 		-> paths
 | ||||||
|  | 	//
 | ||||||
|  | 	// Algorithm:
 | ||||||
|  | 	// 	- sort by path length descending
 | ||||||
|  | 	// 	- take top path (head)
 | ||||||
|  | 	// 	- remove all paths that match it after it (tail)
 | ||||||
|  | 	// 	- next path
 | ||||||
|  | 	//
 | ||||||
|  | 	uniquePaths: function(...list){ | ||||||
|  | 		var that = this | ||||||
|  | 		return that.normalize(normalizeSplit(list)) | ||||||
|  | 			// sort by number of path elements (longest first)...
 | ||||||
|  | 			.map(function(p){ return p.split(/[\\\/]/g) }) | ||||||
|  | 				.sort(function(a, b){ return b.length - a.length }) | ||||||
|  | 				.map(function(p){ return p.join('/') }) | ||||||
|  | 			// remove all paths in tail that match the current...
 | ||||||
|  | 			.map(function(p, i, list){ | ||||||
|  | 				// skip []...
 | ||||||
|  | 				!(p instanceof Array) | ||||||
|  | 					&& list | ||||||
|  | 						// only handle the tail...
 | ||||||
|  | 						.slice(i+1) | ||||||
|  | 						.forEach(function(o, j){ | ||||||
|  | 							// skip []...
 | ||||||
|  | 							!(p instanceof Array) | ||||||
|  | 								&& that.directMatch(o, p) | ||||||
|  | 								// match -> replace the matching elem with []
 | ||||||
|  | 								&& (list[i+j+1] = []) }) | ||||||
|  | 				return p }) | ||||||
|  | 			.flat() }, | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| 	// Introspection and Access API...
 | 	// Introspection and Access API...
 | ||||||
| 	//
 | 	//
 | ||||||
| @ -611,7 +614,7 @@ var TagsPrototype = { | |||||||
| 	//		-> bool
 | 	//		-> bool
 | ||||||
| 	//
 | 	//
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// NOTE: this includes all the .persistent tags as well as all the 
 | 	// NOTE: this includes all the persistent tags as well as all the 
 | ||||||
| 	// 		tags actually used.
 | 	// 		tags actually used.
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// XXX should this return split values???
 | 	// XXX should this return split values???
 | ||||||
| @ -641,7 +644,7 @@ var TagsPrototype = { | |||||||
| 		// get all tags...
 | 		// get all tags...
 | ||||||
| 		} else { | 		} else { | ||||||
| 			return Object.keys(this.__index || {}) | 			return Object.keys(this.__index || {}) | ||||||
| 				.concat([...(this.__persistent_tags || [])] | 				.concat([...(this.persistent || [])] | ||||||
| 					.map(function(t){  | 					.map(function(t){  | ||||||
| 						return that.normalize(t) })) | 						return that.normalize(t) })) | ||||||
| 				.unique() | 				.unique() | ||||||
| @ -700,7 +703,7 @@ var TagsPrototype = { | |||||||
| 	// 		-> this
 | 	// 		-> this
 | ||||||
| 	//
 | 	//
 | ||||||
| 	alias: function(tag, value){ | 	alias: function(tag, value){ | ||||||
| 		var aliases = this.__aliases = this.__aliases || {} | 		var aliases = this.aliases = this.aliases || {} | ||||||
| 		// XXX this seems a bit ugly...
 | 		// XXX this seems a bit ugly...
 | ||||||
| 		var resolve = function(tag, seen){ | 		var resolve = function(tag, seen){ | ||||||
| 			seen = seen || [] | 			seen = seen || [] | ||||||
| @ -903,8 +906,8 @@ var TagsPrototype = { | |||||||
| 		tags = normalizeSplit(tags) | 		tags = normalizeSplit(tags) | ||||||
| 
 | 
 | ||||||
| 		var persistent =  | 		var persistent =  | ||||||
| 			this.__persistent_tags =  | 			this.persistent =  | ||||||
| 				this.__persistent_tags || new Set() | 				this.persistent || new Set() | ||||||
| 
 | 
 | ||||||
| 		return this.normalize(tags) | 		return this.normalize(tags) | ||||||
| 			.map(function(tag){ | 			.map(function(tag){ | ||||||
| @ -1004,9 +1007,9 @@ var TagsPrototype = { | |||||||
| 
 | 
 | ||||||
| 		// rename actual data...
 | 		// rename actual data...
 | ||||||
| 		} else { | 		} else { | ||||||
| 			patchSet(this.__persistent_tags || []) | 			patchSet(this.persistent || []) | ||||||
| 			patchObj(this.__index || {}) | 			patchObj(this.__index || {}) | ||||||
| 			patchObj(this.__aliases || {}, true) | 			patchObj(this.aliases || {}, true) | ||||||
| 		} | 		} | ||||||
| 		 | 		 | ||||||
| 		return this | 		return this | ||||||
| @ -1051,8 +1054,45 @@ var TagsPrototype = { | |||||||
| 		return res | 		return res | ||||||
| 	}, | 	}, | ||||||
| 
 | 
 | ||||||
|  | 	// Keep only the longest tag paths per value...
 | ||||||
|  | 	//
 | ||||||
|  | 	// 	Optimize tags for all values...
 | ||||||
|  | 	// 	.optimizeTags()
 | ||||||
|  | 	// 		-> values
 | ||||||
|  | 	//
 | ||||||
|  | 	// 	Optimize tags for specific values...
 | ||||||
|  | 	// 	.optimizeTags(value, ..)
 | ||||||
|  | 	// 	.optimizeTags([value, ..])
 | ||||||
|  | 	// 		-> values
 | ||||||
|  | 	//
 | ||||||
|  | 	//
 | ||||||
|  | 	// Example:
 | ||||||
|  | 	// 		var ts = new Tags()
 | ||||||
|  | 	// 		ts.tag(['a/b/c', 'a/c'], x)
 | ||||||
|  | 	//
 | ||||||
|  | 	// 		ts.optimizeTags()	// will remove 'a/c' form x as it is fully 
 | ||||||
|  | 	// 							// contained within 'a/b/c'...
 | ||||||
|  | 	//
 | ||||||
|  | 	// XXX should this be done on .tag(..) and friends???
 | ||||||
|  | 	optimizeTags: function(...values){ | ||||||
|  | 		var that = this | ||||||
|  | 		return (normalizeSplit(values) || this.values()) | ||||||
|  | 			.filter(function(value){ | ||||||
|  | 				var tags = new Set(that.paths(value)) | ||||||
|  | 				tags = [...tags.subtract(that.uniquePaths(...tags))] | ||||||
|  | 				tags.length > 0 | ||||||
|  | 					&& that.untag(tags, value)  | ||||||
|  | 				return tags.length > 0 }) }, | ||||||
| 
 | 
 | ||||||
| 	// Tags - Tags API...
 | 	// Make all paths persistent...
 | ||||||
|  | 	//
 | ||||||
|  | 	// NOTE: this will add only longest unique paths (see: .uniquePaths(..))
 | ||||||
|  | 	makePathsPersistent: function(){ | ||||||
|  | 		this.persistent = new Set(this.uniquePaths(this.paths())) | ||||||
|  | 		return this }, | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 	// Tags-Tags API...
 | ||||||
| 	//
 | 	//
 | ||||||
| 	// Join 1 or more Tags objects...
 | 	// Join 1 or more Tags objects...
 | ||||||
| 	//
 | 	//
 | ||||||
| @ -1379,12 +1419,12 @@ var TagsPrototype = { | |||||||
| 		var res = {} | 		var res = {} | ||||||
| 
 | 
 | ||||||
| 		// aliases...
 | 		// aliases...
 | ||||||
| 		this.__aliases && Object.keys(this.__aliases).length > 0 | 		this.aliases && Object.keys(this.aliases).length > 0 | ||||||
| 			&& (res.aliases = Object.assign({}, this.__aliases)) | 			&& (res.aliases = Object.assign({}, this.aliases)) | ||||||
| 
 | 
 | ||||||
| 		// persistent tags...
 | 		// persistent tags...
 | ||||||
| 		this.__persistent_tags && this.__persistent_tags.size > 0 | 		this.persistent && this.persistent.size > 0 | ||||||
| 			&& (res.persistent = [...this.__persistent_tags]) | 			&& (res.persistent = [...this.persistent]) | ||||||
| 
 | 
 | ||||||
| 		// tags...
 | 		// tags...
 | ||||||
| 		res.tags = {} | 		res.tags = {} | ||||||
| @ -1400,11 +1440,11 @@ var TagsPrototype = { | |||||||
| 
 | 
 | ||||||
| 		// aliases...
 | 		// aliases...
 | ||||||
| 		json.aliases | 		json.aliases | ||||||
| 			&& (this.__aliases = Object.assign({}, json.aliases)) | 			&& (this.aliases = Object.assign({}, json.aliases)) | ||||||
| 
 | 
 | ||||||
| 		// persistent tags...
 | 		// persistent tags...
 | ||||||
| 		json.persistent | 		json.persistent | ||||||
| 			&& (this.__persistent_tags = new Set(json.persistent)) | 			&& (this.persistent = new Set(json.persistent)) | ||||||
| 
 | 
 | ||||||
| 		// tags...
 | 		// tags...
 | ||||||
| 		json.tags | 		json.tags | ||||||
| @ -1424,11 +1464,90 @@ var TagsPrototype = { | |||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | ||||||
|  | var BaseTags =  | ||||||
|  | module.BaseTags =  | ||||||
|  | object.makeConstructor('BaseTags',  | ||||||
|  | 		BaseTagsClassPrototype,  | ||||||
|  | 		BaseTagsPrototype) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
|  | // XXX EXPERIMENTAL...
 | ||||||
|  | var TagsWithHandlersPrototype = { | ||||||
|  | 	__proto__: BaseTagsPrototype, | ||||||
|  | 
 | ||||||
|  | 	// XXX docs...
 | ||||||
|  | 	__special_tag_handlers__: { | ||||||
|  | 		// print and remove tag...
 | ||||||
|  | 		'test': function(tag, action, value){ | ||||||
|  | 			console.log('TEST TAG:', tag, action, value) | ||||||
|  | 			return this.removeTag('test', tag)[0] | ||||||
|  | 		}, | ||||||
|  | 		// terminate handling...
 | ||||||
|  | 		'stop': function(tag, action, value){ | ||||||
|  | 			console.log('STOP:', tag, action, value) | ||||||
|  | 			return false  | ||||||
|  | 		}, | ||||||
|  | 		// print the tag...
 | ||||||
|  | 		'*': function(tag, action, value){ | ||||||
|  | 			console.log('TAG:', tag, action, value) | ||||||
|  | 			return tag  | ||||||
|  | 		}, | ||||||
|  | 	}, | ||||||
|  | 
 | ||||||
|  | 	// NOTE: handlers are called in order of handler occurrence and not 
 | ||||||
|  | 	// 		in the order the tags are in the given chain/path...
 | ||||||
|  | 	handleSpecialTag: function(tag, ...args){ | ||||||
|  | 		var that = this | ||||||
|  | 		var handlers = this.__special_tag_handlers__ | ||||||
|  | 		tag = this.normalize(tag) | ||||||
|  | 		return Object.keys(handlers) | ||||||
|  | 				.filter(function(p){ | ||||||
|  | 					// keep only valid tag patterns...
 | ||||||
|  | 					// NOTE: this enables us to create special handlers 
 | ||||||
|  | 					// 		that will not be used for matching but are more 
 | ||||||
|  | 					// 		mnemonic...
 | ||||||
|  | 					return p == that.normalize(p) | ||||||
|  | 						// get the matching handler keys...
 | ||||||
|  | 						&& that.directMatch(p, tag) | ||||||
|  | 				}) | ||||||
|  | 				// resolve handler aliases...
 | ||||||
|  | 				.map(function(match){ | ||||||
|  | 					do { | ||||||
|  | 						match = handlers[match]	 | ||||||
|  | 					} while(!(match instanceof Function) && match in handlers) | ||||||
|  | 
 | ||||||
|  | 					return match instanceof Function ?  | ||||||
|  | 						match  | ||||||
|  | 						// no handler...
 | ||||||
|  | 						: [] }) | ||||||
|  | 				.flat() | ||||||
|  | 				// call the handlers...
 | ||||||
|  | 				// NOTE: we are threading tag through the handlers...
 | ||||||
|  | 				.reduce(function(tag, handler){ | ||||||
|  | 					return tag && handler.call(that, tag, ...args) }, tag)  | ||||||
|  | 			// no handlers -> return as-is...
 | ||||||
|  | 			|| tag }, | ||||||
|  | 
 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
 | ||||||
|  | 
 | ||||||
|  | var TagsWithHandlers =  | ||||||
|  | module.TagsWithHandlers =  | ||||||
|  | object.makeConstructor('TagsWithHandlers',  | ||||||
|  | 		BaseTagsClassPrototype, | ||||||
|  | 		TagsWithHandlersPrototype) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | //---------------------------------------------------------------------
 | ||||||
|  | 
 | ||||||
| var Tags = | var Tags = | ||||||
| module.Tags =  | module.Tags = TagsWithHandlers | ||||||
| object.makeConstructor('Tags',  |  | ||||||
| 		TagsClassPrototype,  |  | ||||||
| 		TagsPrototype) |  | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user