| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2014-08-01 19:20:11 +04:00
										 |  |  | * Minimal UI API... | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							| 
									
										
										
										
											2016-08-21 02:19:24 +03:00
										 |  |  | ((typeof define)[0]=='u'?function(f){module.exports=f(require)}:define) | 
					
						
							|  |  |  | (function(require){ var module={} // make module AMD/node compatible...
 | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2014-07-21 16:38:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-19 19:55:11 +03:00
										 |  |  | if(typeof(window) == 'undefined'){ | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 17:38:54 +04:00
										 |  |  | // XXX is this correct...
 | 
					
						
							| 
									
										
										
										
											2015-09-08 01:01:06 +03:00
										 |  |  | //require('ext-lib/jquery')
 | 
					
						
							| 
									
										
										
										
											2014-07-24 17:38:54 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | var util = require('lib/util') | 
					
						
							| 
									
										
										
										
											2015-12-26 23:21:14 +03:00
										 |  |  | var transform = require('lib/transform') | 
					
						
							| 
									
										
										
										
											2015-12-08 07:42:07 +03:00
										 |  |  | var object = require('lib/object') | 
					
						
							| 
									
										
										
										
											2014-11-18 20:20:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-01 16:12:10 +03:00
										 |  |  | var data = require('imagegrid/data') | 
					
						
							|  |  |  | var images = require('imagegrid/images') | 
					
						
							| 
									
										
										
										
											2014-07-22 17:09:25 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-31 10:37:21 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | var IMAGE = '.image:not(.clone)' | 
					
						
							|  |  |  | var RIBBON = '.ribbon:not(.clone)' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-16 19:42:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-21 02:30:24 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | // This expects/builds the following HTML structure...
 | 
					
						
							| 
									
										
										
										
											2014-07-21 02:30:24 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // Unpopulated:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	<div class="viewer">
 | 
					
						
							|  |  |  | //	</div>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // Populated:
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	<div class="viewer">
 | 
					
						
							|  |  |  | //		<div class="ribbon-set">
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | //			<div class="ribbon-locator">
 | 
					
						
							|  |  |  | //				<div class="ribbon">
 | 
					
						
							|  |  |  | //					<div class="image" gid="a"></div>
 | 
					
						
							|  |  |  | //					<div class="image" gid="b"></div>
 | 
					
						
							|  |  |  | //					...
 | 
					
						
							|  |  |  | //				</div>
 | 
					
						
							|  |  |  | //				<div class="ribbon">
 | 
					
						
							|  |  |  | //					<div class="image" gid="c"></div>
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | //					<!-- current image -->
 | 
					
						
							|  |  |  | //					<div class="current image" gid="d"></div>
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | //					<!-- image with mark... -->
 | 
					
						
							|  |  |  | //					<div class="image" gid="e"></div>
 | 
					
						
							|  |  |  | //					<div class="mark selected" gid="f"></div>
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | //					<div class="image" gid="g"></div>
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | //					...
 | 
					
						
							|  |  |  | //				</div>
 | 
					
						
							| 
									
										
										
										
											2014-07-21 02:30:24 +04:00
										 |  |  | //				...
 | 
					
						
							|  |  |  | //			</div>
 | 
					
						
							|  |  |  | //		</div>
 | 
					
						
							|  |  |  | //	</div>
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-07-24 17:38:54 +04:00
										 |  |  | // NOTE: there can be only one .ribbon-set element.
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | // NOTE: other elements can exist in the structure, but as long as they
 | 
					
						
							|  |  |  | // 		use different CSS classes they are ignored by the system, note 
 | 
					
						
							|  |  |  | // 		that such elements may affect alignment and placement though this
 | 
					
						
							|  |  |  | // 		should be obvious ;)
 | 
					
						
							| 
									
										
										
										
											2014-07-24 17:38:54 +04:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2015-12-22 05:49:32 +03:00
										 |  |  | //
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | var BaseRibbonsClassPrototype = { | 
					
						
							| 
									
										
										
										
											2017-04-30 01:02:03 +03:00
										 |  |  | 	// utils...
 | 
					
						
							|  |  |  | 	px2v: function(px, mode){ | 
					
						
							|  |  |  | 		var ref = mode == 'vw' ?  | 
					
						
							|  |  |  | 				document.body.offsetWidth | 
					
						
							|  |  |  | 			: mode == 'vh' ?  | 
					
						
							|  |  |  | 				document.body.offsetHeight | 
					
						
							|  |  |  | 			: mode == 'vmin' ?  | 
					
						
							|  |  |  | 				Math.min(document.body.offsetWidth, document.body.offsetHeight) | 
					
						
							|  |  |  | 			: mode == 'vmax' ?  | 
					
						
							|  |  |  | 				Math.max(document.body.offsetWidth, document.body.offsetHeight) | 
					
						
							|  |  |  | 			: null | 
					
						
							|  |  |  | 		return ref ?  | 
					
						
							|  |  |  | 			(px / ref) * 100  | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			: ref }, | 
					
						
							| 
									
										
										
										
											2017-04-30 01:02:03 +03:00
										 |  |  | 	px2vw: function(px){ return this.px2v(px, 'vw') }, | 
					
						
							|  |  |  | 	px2vh: function(px){ return this.px2v(px, 'vh') }, | 
					
						
							|  |  |  | 	px2vmin: function(px){ return this.px2v(px, 'vmin') }, | 
					
						
							|  |  |  | 	px2vmax: function(px){ return this.px2v(px, 'vmax') }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	// Generic getters...
 | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 	elemGID: function(elem, gid){ | 
					
						
							|  |  |  | 		// get gid...
 | 
					
						
							|  |  |  | 		return (gid == null || gid == '?') ? | 
					
						
							|  |  |  | 				JSON.parse('"'  | 
					
						
							|  |  |  | 					+ (elem instanceof jQuery ?  | 
					
						
							|  |  |  | 							elem.attr('gid')  | 
					
						
							|  |  |  | 						: elem.getAttribute('gid')) | 
					
						
							|  |  |  | 					+ '"') | 
					
						
							|  |  |  | 			// remove gid...
 | 
					
						
							|  |  |  | 			: gid == '' ?  | 
					
						
							|  |  |  | 				$(elem) | 
					
						
							|  |  |  | 					.removesAttr('gid') | 
					
						
							|  |  |  | 			// set gid...
 | 
					
						
							|  |  |  | 			: $(elem) | 
					
						
							|  |  |  | 				.attr('gid',  | 
					
						
							|  |  |  | 					JSON.stringify(gid) | 
					
						
							|  |  |  | 						// this removes the extra quots...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						.replace(/^"(.*)"$/g, '$1')) }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | }  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | var BaseRibbonsPrototype = { | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.viewer (jQuery object)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 	//	.images (Images object)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 02:00:50 +04:00
										 |  |  | 	// XXX to update images we need to know about images...
 | 
					
						
							| 
									
										
										
										
											2014-07-21 02:30:24 +04:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2014-11-18 20:20:35 +03:00
										 |  |  | 	__init__: function(viewer, images){ | 
					
						
							|  |  |  | 		this.viewer = $(viewer) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		this.images = images }, | 
					
						
							| 
									
										
										
										
											2014-11-18 20:20:35 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-30 01:02:03 +03:00
										 |  |  | 	// utils...
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	px2v: BaseRibbonsClassPrototype.px2v, | 
					
						
							|  |  |  | 	px2vw: BaseRibbonsClassPrototype.px2vw, | 
					
						
							|  |  |  | 	px2vh: BaseRibbonsClassPrototype.px2vh, | 
					
						
							|  |  |  | 	px2vmin: BaseRibbonsClassPrototype.px2vmin, | 
					
						
							|  |  |  | 	px2vmax: BaseRibbonsClassPrototype.px2vmax, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-22 20:27:11 +04:00
										 |  |  | 	// Generic getters...
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	elemGID: BaseRibbonsClassPrototype.elemGID, | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 	get parent(){ | 
					
						
							| 
									
										
										
										
											2017-05-04 00:46:11 +03:00
										 |  |  | 		return this.__parent }, | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 	// NOTE: this will reset locally referenced .images to .parent.images
 | 
					
						
							|  |  |  | 	set parent(parent){ | 
					
						
							|  |  |  | 		this.__parent = parent | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		delete this.__images }, | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// maintain images in .parent.images if available...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: images can be stored locally if no parent is set but will 
 | 
					
						
							|  |  |  | 	// 		get overridden as soon as .parent is set.
 | 
					
						
							|  |  |  | 	get images(){ | 
					
						
							| 
									
										
										
										
											2017-05-04 00:46:11 +03:00
										 |  |  | 		return this.parent ? this.parent.images : this.__images }, | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 	set images(images){ | 
					
						
							|  |  |  | 		if(this.parent){ | 
					
						
							|  |  |  | 			this.parent.images = images | 
					
						
							|  |  |  | 			delete this.__images | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			this.__images = images } }, | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 	// Helpers...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Prevent CSS transitions...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Prevent transitions globally (.viewer):
 | 
					
						
							|  |  |  | 	// 	.preventTransitions()
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Prevent transitions on elem:
 | 
					
						
							|  |  |  | 	// 	.preventTransitions(elem)
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will set a .no-transitions CSS class and force 
 | 
					
						
							|  |  |  | 	// 		recalculation on the given element
 | 
					
						
							|  |  |  | 	// NOTE: for this to have effect proper CSS configuration is needed.
 | 
					
						
							|  |  |  | 	preventTransitions: function(target){ | 
					
						
							|  |  |  | 		target = target || this.viewer | 
					
						
							|  |  |  | 		//prevent_nested = prevent_nested || false
 | 
					
						
							|  |  |  | 		if(target.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 		var t = target[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// handle nesting...
 | 
					
						
							|  |  |  | 		var l = t.getAttribute('__prevent_transitions') | 
					
						
							|  |  |  | 		if(l != null){ | 
					
						
							|  |  |  | 			t.setAttribute('__prevent_transitions', parseInt(l)+1) | 
					
						
							|  |  |  | 			return this | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		t.setAttribute('__prevent_transitions', 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		target.addClass('no-transitions') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var s = getComputedStyle(t) | 
					
						
							|  |  |  | 		s.webkitTransition | 
					
						
							|  |  |  | 		s.mozTransition | 
					
						
							|  |  |  | 		s.msTransition | 
					
						
							|  |  |  | 		s.oTransition | 
					
						
							|  |  |  | 		s.transition | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Restore CSS transitions...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This is a companion to .preventTransitions(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Restore transitions globally (.viewer):
 | 
					
						
							|  |  |  | 	// 	.restoreTransitions()
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Restore transitions on elem: 
 | 
					
						
							|  |  |  | 	// 	.restoreTransitions(elem)
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Restore transitions on elem (force sync): 
 | 
					
						
							|  |  |  | 	// 	.restoreTransitions(elem, true)
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Force restore transitions: 
 | 
					
						
							|  |  |  | 	// 	.restoreTransitions(.., .., true)
 | 
					
						
							|  |  |  | 	// 		-> data
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// When at least one .preventTransitions(..) is called with 
 | 
					
						
							|  |  |  | 	// prevent_nested set to true, this will be a no-op on all nested
 | 
					
						
							|  |  |  | 	// levels.
 | 
					
						
							|  |  |  | 	// This can be overridden via setting the force to true.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: the implementation of this method might seem ugly, but the 
 | 
					
						
							|  |  |  | 	// 		code is speed-critical, thus we access the DOM directly and
 | 
					
						
							|  |  |  | 	// 		the two branches are unrolled...
 | 
					
						
							|  |  |  | 	restoreTransitions: function(target, now, force){ | 
					
						
							|  |  |  | 		if(target === true || target === false){ | 
					
						
							|  |  |  | 			now = target | 
					
						
							|  |  |  | 			target = this.viewer | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			target = target || this.viewer } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 		if(target.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 		var t = target[0] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// sync...
 | 
					
						
							|  |  |  | 		if(now){ | 
					
						
							|  |  |  | 			// handle nesting...
 | 
					
						
							|  |  |  | 			var l = t.getAttribute('__prevent_transitions') | 
					
						
							|  |  |  | 			if(l != null && !force && l != '0'){ | 
					
						
							|  |  |  | 				t.setAttribute('__prevent_transitions', parseInt(l)-1) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return this } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 			t.removeAttribute('__prevent_transitions') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			target.removeClass('no-transitions') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var s = getComputedStyle(t) | 
					
						
							|  |  |  | 			s.webkitTransition | 
					
						
							|  |  |  | 			s.mozTransition | 
					
						
							|  |  |  | 			s.msTransition | 
					
						
							|  |  |  | 			s.oTransition | 
					
						
							|  |  |  | 			s.transition | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// on next exec frame...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 			setTimeout(function(){ | 
					
						
							|  |  |  | 				// handle nesting...
 | 
					
						
							|  |  |  | 				var l = t.getAttribute('__prevent_transitions') | 
					
						
							|  |  |  | 				if(l != null && !force && l != '0'){ | 
					
						
							|  |  |  | 					t.setAttribute('__prevent_transitions', l-1) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					return this } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 				t.removeAttribute('__prevent_transitions') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				target.removeClass('no-transitions') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var s = getComputedStyle(t) | 
					
						
							|  |  |  | 				s.webkitTransition | 
					
						
							|  |  |  | 				s.mozTransition | 
					
						
							|  |  |  | 				s.msTransition | 
					
						
							|  |  |  | 				s.oTransition | 
					
						
							|  |  |  | 				s.transition | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			}, 0) } | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Shorthand wrappers of the above...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX do we need custom target support here???
 | 
					
						
							|  |  |  | 	noTransitions: function(func){ | 
					
						
							|  |  |  | 		this.preventTransitions() | 
					
						
							| 
									
										
										
										
											2018-11-12 23:04:00 +03:00
										 |  |  | 		func.apply(this, [...arguments].slice(1)) | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 		this.restoreTransitions(true) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 	noTransitionsDeep: function(func){ | 
					
						
							|  |  |  | 		this.preventTransitions(null, true) | 
					
						
							| 
									
										
										
										
											2018-11-12 23:04:00 +03:00
										 |  |  | 		func.apply(this, [...arguments].slice(1)) | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 		this.restoreTransitions(true) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-27 06:50:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-05-01 21:27:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 	// Scale...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Get scale...
 | 
					
						
							|  |  |  | 	// 	.scale()
 | 
					
						
							|  |  |  | 	// 		-> <scale>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Set scale...
 | 
					
						
							|  |  |  | 	// 	.scale(<scale>)
 | 
					
						
							|  |  |  | 	// 		-> <ribbons>
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will also set origin...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX if chrome 38 renders images blurry uncomment the fix...
 | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 	scale: function(scale){ | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 		// get...
 | 
					
						
							|  |  |  | 		if(arguments.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this.getRibbonSet().scale() || 1 } | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// set...
 | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 		var ribbon_set = this.getRibbonSet()   | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 		if(ribbon_set.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2014-10-13 00:18:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		ribbon_set.scale(scale) | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2016-11-22 19:12:36 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Get visible image tile size...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.getVisibleImageSize()
 | 
					
						
							|  |  |  | 	//	.getVisibleImageSize('width')
 | 
					
						
							|  |  |  | 	//		-> size
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.getVisibleImageSize('height')
 | 
					
						
							|  |  |  | 	//		-> size
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.getVisibleImageSize('max')
 | 
					
						
							|  |  |  | 	//	.getVisibleImageSize('min')
 | 
					
						
							|  |  |  | 	//		-> size
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this is similar to vh, vw, vmin and vmax CSS3 units, but
 | 
					
						
							|  |  |  | 	// 		gets the visible size of the image tile in pixels.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-11-16 16:49:12 +03:00
										 |  |  | 	// XXX this might break when no images are loaded and proportions 
 | 
					
						
							|  |  |  | 	// 		are not square...
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 	// XXX this depends on .createImage(..)
 | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | 	getVisibleImageSize: function(dim, scale, img, force){ | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		dim = dim == null ? 'width' : dim | 
					
						
							| 
									
										
										
										
											2015-12-03 00:58:43 +03:00
										 |  |  | 		img = img || this.viewer.find(IMAGE) | 
					
						
							| 
									
										
										
										
											2014-11-16 16:49:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		var tmp | 
					
						
							| 
									
										
										
										
											2014-11-09 18:54:53 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | // 		// XXX size cache -- not sure if this needs to be cached...
 | 
					
						
							|  |  |  | //		var res = (this.__visible_image_size_cache || {})[dim]
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		if(this.__visible_image_size_cache == false 
 | 
					
						
							|  |  |  | //				|| img.length > 0 
 | 
					
						
							|  |  |  | //				|| force 
 | 
					
						
							|  |  |  | //				|| res == null){
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// if no images are loaded create one temporarily....
 | 
					
						
							|  |  |  | 			if(img.length == 0){ | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 				img = tmp = $(this.createImage('__tmp_image__')) | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | 					.css({ | 
					
						
							|  |  |  | 						position: 'absolute', | 
					
						
							|  |  |  | 						visibility: 'hidden', | 
					
						
							|  |  |  | 						top: '-200%', | 
					
						
							|  |  |  | 						left: '-200%', | 
					
						
							|  |  |  | 					}) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					.appendTo(this.viewer) } | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// account for image rotation...
 | 
					
						
							|  |  |  | 			// NOTE: this way we do not need to account for margins...
 | 
					
						
							|  |  |  | 			var o = img.attr('orientation') | 
					
						
							|  |  |  | 			o = o == null ? 0 : o | 
					
						
							|  |  |  | 			dim = o == 0 || o == 180 ? dim  | 
					
						
							|  |  |  | 				// swap width/height when image is rotated +/- 90deg...
 | 
					
						
							|  |  |  | 				: dim == 'height' ? 'width'  | 
					
						
							|  |  |  | 				: 'height' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// do the calc...
 | 
					
						
							|  |  |  | 			scale = scale || this.scale() | 
					
						
							|  |  |  | 			var css = getComputedStyle(img[0]) | 
					
						
							|  |  |  | 			var res = dim == 'height' ? parseFloat(css.height) | 
					
						
							|  |  |  | 				: dim == 'width' ? parseFloat(css.width) | 
					
						
							|  |  |  | 				: dim == 'max' ?  Math.max(parseFloat(css.height), parseFloat(css.width)) | 
					
						
							|  |  |  | 				: dim == 'min' ?  Math.min(parseFloat(css.height), parseFloat(css.width)) | 
					
						
							|  |  |  | 				: null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // 			// XXX size cache -- not sure if this needs to be cached...
 | 
					
						
							|  |  |  | //			if(this.__visible_image_size_cache != false){
 | 
					
						
							|  |  |  | //				var cache = this.__visible_image_size_cache = this.__visible_image_size_cache || {}
 | 
					
						
							|  |  |  | //				cache[dim] = res
 | 
					
						
							|  |  |  | //			}
 | 
					
						
							|  |  |  | //		}
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-16 04:49:17 +03:00
										 |  |  | 		// get size for given scale...
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		res = res ? res * scale : res | 
					
						
							| 
									
										
										
										
											2016-06-16 00:40:14 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 16:49:12 +03:00
										 |  |  | 		// remove the tmp image we created...
 | 
					
						
							|  |  |  | 		if(tmp != null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			tmp.remove() } | 
					
						
							| 
									
										
										
										
											2014-11-16 16:49:12 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return res }, | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-09 18:54:53 +03:00
										 |  |  | 	getScreenWidthImages: function(scale, min){ | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		scale = scale || this.scale() | 
					
						
							| 
									
										
										
										
											2014-10-13 00:18:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var W = this.viewer.width() | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		var w = this.getVisibleImageSize(min ? 'min' : 'width', scale) | 
					
						
							| 
									
										
										
										
											2014-10-13 00:18:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return W/w }, | 
					
						
							| 
									
										
										
										
											2014-11-06 14:25:09 +03:00
										 |  |  | 	// XXX this does not account for ribbon spacing...
 | 
					
						
							|  |  |  | 	getScreenHeightRibbons: function(scale){ | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		scale = scale || this.scale() | 
					
						
							| 
									
										
										
										
											2014-11-06 14:25:09 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var H = this.viewer.height() | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		var h = this.getVisibleImageSize('height', scale) | 
					
						
							| 
									
										
										
										
											2014-11-06 14:25:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return H/h }, | 
					
						
							| 
									
										
										
										
											2014-10-13 00:18:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 	// Fit image to view...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// If n is given this will fit n images (default: 1)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will never scale the view in a way that an image 
 | 
					
						
							|  |  |  | 	// 		overflows either in height nor width.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX might be useful to set origin before scaling...
 | 
					
						
							|  |  |  | 	fitImage: function(n, min){ | 
					
						
							|  |  |  | 		n = n || 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// NOTE: this is width oriented...
 | 
					
						
							|  |  |  | 		var scale = this.getScreenWidthImages(1, min) / n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// check bounds...
 | 
					
						
							|  |  |  | 		var H = this.viewer.height() | 
					
						
							|  |  |  | 		var h = this.getVisibleImageSize('height', 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// n images will be higher than the viewer, adjust for height...
 | 
					
						
							|  |  |  | 		if(h*scale >= H){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			scale = H/h } | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		this | 
					
						
							|  |  |  | 			.scale(scale) | 
					
						
							|  |  |  | 			//.centerRibbon(null, null, scale)
 | 
					
						
							|  |  |  | 			//.centerImage(null, null, null, scale)
 | 
					
						
							|  |  |  | 		 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 	// NOTE: if fit_whole_images is true (default) this will fit a discrete
 | 
					
						
							|  |  |  | 	// 		number of images in width...
 | 
					
						
							|  |  |  | 	// XXX this does not account for ribbon spacing...
 | 
					
						
							|  |  |  | 	fitRibbon: function(n, fit_whole_images){ | 
					
						
							|  |  |  | 		n = n || 1 | 
					
						
							|  |  |  | 		fit_whole_images = fit_whole_images == null ? true : false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var scale = this.getScreenHeightRibbons(1) / n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var w = this.getVisibleImageSize('width', 1) | 
					
						
							|  |  |  | 		var W = this.viewer.width() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// n ribbons will be wider than the viewer...
 | 
					
						
							|  |  |  | 		if(w*scale >= W){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			scale = W/w } | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// shift the scale to the point where screen width is a whole 
 | 
					
						
							|  |  |  | 		// number of images...
 | 
					
						
							|  |  |  | 		if(fit_whole_images){ | 
					
						
							|  |  |  | 			var d = this.getScreenWidthImages(scale) | 
					
						
							|  |  |  | 			d = d / Math.ceil(d) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			scale *= d } | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		this.scale(scale) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// Contextual getters...
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// Get ribbon-set...
 | 
					
						
							| 
									
										
										
										
											2014-10-17 15:24:32 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// 	Get ribbon set if it exists
 | 
					
						
							|  |  |  | 	// 	.getRibbonSet()
 | 
					
						
							|  |  |  | 	// 		-> ribbon-set
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Get ribbon set if it exists or create it if not
 | 
					
						
							|  |  |  | 	// 	.getRibbonSet(true)
 | 
					
						
							|  |  |  | 	// 		-> ribbon-set
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-11-22 23:41:38 +03:00
										 |  |  | 	// XXX revise...
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 	getRibbonSet: function(create){ | 
					
						
							| 
									
										
										
										
											2016-11-22 23:38:16 +03:00
										 |  |  | 		// ribbon set...
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 		var ribbon_set = this.viewer.find('.ribbon-set') | 
					
						
							| 
									
										
										
										
											2016-11-22 23:38:16 +03:00
										 |  |  | 		if(create && ribbon_set.length == 0){ | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 			ribbon_set = $('<div/>') | 
					
						
							|  |  |  | 				.addClass('ribbon-set') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				.appendTo(this.viewer) } | 
					
						
							| 
									
										
										
										
											2016-11-22 23:38:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// ribbon locator...
 | 
					
						
							|  |  |  | 		var locator = ribbon_set.find('.ribbon-locator') | 
					
						
							|  |  |  | 		if(create && locator.length == 0){ | 
					
						
							|  |  |  | 			ribbon_set | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 				.append($('<div/>') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					.addClass('ribbon-locator')) } | 
					
						
							| 
									
										
										
										
											2016-11-22 23:38:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return ribbon_set }, | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 	getRibbonLocator: function(create){ | 
					
						
							|  |  |  | 		return this.getRibbonSet(create) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			.find('.ribbon-locator') }, | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 02:00:50 +04:00
										 |  |  | 	// Get image...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get current image:
 | 
					
						
							|  |  |  | 	//	.getImage()
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	//	.getImage('current')
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get image by gid:
 | 
					
						
							|  |  |  | 	//	.getImage(gid)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	// Get image at offset relative to current image:
 | 
					
						
							|  |  |  | 	//	.getImage('next')
 | 
					
						
							|  |  |  | 	//	.getImage('prev')
 | 
					
						
							|  |  |  | 	//	.getImage(offset)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get image at offset relative to image:
 | 
					
						
							|  |  |  | 	//	.getImage(image, 'next')
 | 
					
						
							|  |  |  | 	//	.getImage(image, 'prev')
 | 
					
						
							|  |  |  | 	//	.getImage(image, offset)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	// Get images from list:
 | 
					
						
							|  |  |  | 	//	.getImage($(..))
 | 
					
						
							|  |  |  | 	//	.getImage([..])
 | 
					
						
							|  |  |  | 	//		-> image(s)
 | 
					
						
							|  |  |  | 	//		NOTE: this will filter the list but not search the tree...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	getImage: function(target, offset){ | 
					
						
							|  |  |  | 		var img = null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// relative to current -- target is offset...
 | 
					
						
							|  |  |  | 		if(target == 'next'  | 
					
						
							|  |  |  | 				|| target == 'prev'  | 
					
						
							|  |  |  | 				|| typeof(target) == typeof(123)){ | 
					
						
							|  |  |  | 			offset = target | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			target = 'current' } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		// get the base image...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		// current...
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 		if(target == null || target == 'current') { | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 			img = this.viewer.find('.current'+IMAGE) | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		// gid...
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		} else if(typeof(target) == typeof('str')){ | 
					
						
							| 
									
										
										
										
											2014-07-22 17:09:25 +04:00
										 |  |  | 			//return this.viewer.find('.image[gid="'+JSON.stringify(target)+'"]')
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			img = this.viewer.find(IMAGE+'[gid='+JSON.stringify(target)+']') } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// we got a collection...
 | 
					
						
							|  |  |  | 		if(img == null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return $(target).filter(IMAGE) } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// get the offset...
 | 
					
						
							|  |  |  | 		if(offset != null && offset != 0){ | 
					
						
							|  |  |  | 			// relative keywords...
 | 
					
						
							|  |  |  | 			offset = offset == 'next' ? 1 | 
					
						
							|  |  |  | 				: offset == 'prev' ? -1 | 
					
						
							|  |  |  | 				: offset | 
					
						
							|  |  |  | 			var list = offset > 0 ? 'nextAll' : 'prevAll' | 
					
						
							|  |  |  | 			offset = Math.abs(offset)-1 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 			var res = img[list](IMAGE) | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 			// handle overflow...
 | 
					
						
							|  |  |  | 			res = res.eq(Math.min(offset, res.length-1)) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			img = res.length == 0 ? img : res } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return img }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-11-02 03:16:01 +03:00
										 |  |  | 	// Get images...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.getImages()
 | 
					
						
							|  |  |  | 	// 		-> images
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.getImages(jquery)
 | 
					
						
							|  |  |  | 	// 	.getImages(ribbon)
 | 
					
						
							|  |  |  | 	// 		-> images
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	.getImages(ribbon-gid)
 | 
					
						
							|  |  |  | 	// 		-> images
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	getImages: function(target){ | 
					
						
							|  |  |  | 		return (target instanceof jQuery ? | 
					
						
							|  |  |  | 					target | 
					
						
							|  |  |  | 				// gid...
 | 
					
						
							|  |  |  | 				: target ? | 
					
						
							|  |  |  | 					this.viewer.find(RIBBON + '[gid='+ target +']') | 
					
						
							|  |  |  | 				// viewer...
 | 
					
						
							|  |  |  | 				: this.viewer) | 
					
						
							|  |  |  | 			.find(IMAGE) }, | 
					
						
							|  |  |  | 	// same as .getImages(..) but returns a list of gids...
 | 
					
						
							|  |  |  | 	getImageGIDs: function(target){ | 
					
						
							|  |  |  | 		return this.getImages(...arguments) | 
					
						
							|  |  |  | 			.map(function(_, e){ | 
					
						
							|  |  |  | 				return e.getAttribute('gid') }) | 
					
						
							|  |  |  |    			.toArray() }, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	// Get image marks...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.getImageMarks(gid)
 | 
					
						
							|  |  |  | 	//	.getImageMarks(image)
 | 
					
						
							|  |  |  | 	//		-> marks
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	.getImageMarks(gid, cls)
 | 
					
						
							|  |  |  | 	//	.getImageMarks(image, cls)
 | 
					
						
							|  |  |  | 	//		-> marks
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// XXX should this be here or in a marks plugin...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	getImageMarks: function(img, cls){ | 
					
						
							| 
									
										
										
										
											2014-10-19 05:01:22 +04:00
										 |  |  | 		img = img || this.getImage() | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		var gid = typeof(img) == typeof('str') ? img : null | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 		gid = gid == null ? this.elemGID(img) : gid | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var marks = this.viewer.find('.mark[gid='+JSON.stringify(gid)+']') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(cls != null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return marks.filter('.'+cls) } | 
					
						
							|  |  |  | 		return marks }, | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 	// Get an image at a relative to viewer position...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get central image in current ribbon:
 | 
					
						
							|  |  |  | 	//	.getImageByPosition()
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get central image closest to current:
 | 
					
						
							|  |  |  | 	//	.getImageByPosition('current'[, <ribbon>])
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get central image closest to html element:
 | 
					
						
							|  |  |  | 	//	.getImageByPosition(<elem>[, <ribbon>])
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get image in a specific ribbon:
 | 
					
						
							|  |  |  | 	//	.getImageByPosition('left'[, <ribbon>])
 | 
					
						
							|  |  |  | 	//	.getImageByPosition('center'[, <ribbon>])
 | 
					
						
							|  |  |  | 	//	.getImageByPosition('right'[, <ribbon>])
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This can return a pair of images when position is either 'center',
 | 
					
						
							|  |  |  | 	// 'current' or a jquery object, this can happen when the two 
 | 
					
						
							|  |  |  | 	// candidates are closer to the target than delta.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: if no ribbon is given, current ribbon is assumed.
 | 
					
						
							|  |  |  | 	// NOTE: <ribbon> is the same as expected by .getRibbon(..)
 | 
					
						
							|  |  |  | 	// NOTE: position can also be an image...
 | 
					
						
							|  |  |  | 	// NOTE: delta is used ONLY if position is either 'center', 'current'
 | 
					
						
							|  |  |  | 	// 		or an jQuery object...
 | 
					
						
							|  |  |  | 	getImageByPosition: function(position, ribbon, delta){ | 
					
						
							|  |  |  | 		position = position || 'center'	 | 
					
						
							|  |  |  | 		ribbon = this.getRibbon(ribbon)  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var viewer = this.viewer | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var W = viewer.outerWidth() | 
					
						
							|  |  |  | 		var L = viewer.offset().left | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var target = position == 'current' ? this.getImage() | 
					
						
							|  |  |  | 			: position == 'center' ? viewer | 
					
						
							|  |  |  | 			: position == 'left' ? L | 
					
						
							|  |  |  | 			: position == 'right' ? L + W | 
					
						
							|  |  |  | 			: position | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// unknown keyword...
 | 
					
						
							|  |  |  | 		if(target == null){ | 
					
						
							|  |  |  | 			return $() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// center of an element...
 | 
					
						
							|  |  |  | 		} else if(typeof(target) != typeof(123)){ | 
					
						
							|  |  |  | 			target = $(target) | 
					
						
							| 
									
										
										
										
											2016-11-28 19:16:13 +03:00
										 |  |  | 			if(target.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return $() } | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 			var w = target.hasClass('image') ?  | 
					
						
							|  |  |  | 				this.getVisibleImageSize('width', null, target) :  | 
					
						
							|  |  |  | 				target.outerWidth() | 
					
						
							|  |  |  | 			// NOTE: we will need delta only in this branch, i.e. when
 | 
					
						
							|  |  |  | 			// 		position is either 'current', 'center' or a jQuery 
 | 
					
						
							|  |  |  | 			// 		object...
 | 
					
						
							|  |  |  | 			delta = delta || w / 10 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			target = target.offset().left + w/2 } | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		var that = this | 
					
						
							|  |  |  | 		var res = ribbon.find(IMAGE) | 
					
						
							|  |  |  | 			.toArray() | 
					
						
							|  |  |  | 			.map(function(img){ | 
					
						
							|  |  |  | 				img = $(img) | 
					
						
							|  |  |  | 				var l = img.offset().left | 
					
						
							|  |  |  | 				var w = that.getVisibleImageSize('width', null, img) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// skip images not fully shown in viewer...
 | 
					
						
							|  |  |  | 				// NOTE: we explicitly leave partial images here so as to
 | 
					
						
							|  |  |  | 				// 		include at least two.
 | 
					
						
							|  |  |  | 				// 		This is done so as to include at least a couple 
 | 
					
						
							|  |  |  | 				// 		of images at large magnifications when nothing 
 | 
					
						
							|  |  |  | 				// 		other than the current image fully fit...
 | 
					
						
							|  |  |  | 				if(L > l+w || l > L+W){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					return } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// distance between centers...
 | 
					
						
							|  |  |  | 				if(position == 'center' || position == 'current'){ | 
					
						
							|  |  |  | 					return [target - (l + w/2), img] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// distance between left edges...
 | 
					
						
							|  |  |  | 				} else if(position == 'left'){ | 
					
						
							|  |  |  | 					return [target - l, img] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// distance between right edges...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					return [target - (l + w), img] } }) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 			// drop images outside the viewer...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			.filter(function(e){  | 
					
						
							|  |  |  | 				return e != null }) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 			// sort images by distance...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			.sort(function(a, b){  | 
					
						
							|  |  |  | 				return Math.abs(a[0]) - Math.abs(b[0]) }) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var a = res[0] ? res[0][0] : null | 
					
						
							|  |  |  | 		var b = res[1] ? res[1][0] : null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// we have two images that are about the same distance from 
 | 
					
						
							|  |  |  | 		// target...
 | 
					
						
							|  |  |  | 		// NOTE: this is a one-dimentional filter so there can not be 
 | 
					
						
							|  |  |  | 		// 		more than two hits...
 | 
					
						
							|  |  |  | 		// NOTE: delta is used ONLY if position is either 'center', 
 | 
					
						
							|  |  |  | 		// 		'current' or an jQuery object...
 | 
					
						
							|  |  |  | 		if(b && (a >= 0) != (b >= 0) && Math.abs(a + b) < delta){ | 
					
						
							|  |  |  | 			return $([res[0][1][0], res[1][1][0]]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// a single hit...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// NOTE: if no image is on screen this will get nothing...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return res[0] ? res[0][1] : null } }, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Get ribbon...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get current ribbon:
 | 
					
						
							|  |  |  | 	//	.getRibbon()
 | 
					
						
							|  |  |  | 	//	.getRibbon('current')
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get base ribbon:
 | 
					
						
							|  |  |  | 	//	.getRibbon('base')
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get ribbon by its index/gid:
 | 
					
						
							|  |  |  | 	//	.getRibbon(index)
 | 
					
						
							|  |  |  | 	//	.getRibbon(gid)
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get ribbon by image:
 | 
					
						
							|  |  |  | 	//	.getRibbon(image)
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//		NOTE: image must be .getImage(..) compatible.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Get ribbons from list:
 | 
					
						
							|  |  |  | 	//	.getRibbon($(..))
 | 
					
						
							|  |  |  | 	//	.getRibbon([..])
 | 
					
						
							|  |  |  | 	//		-> ribbon(s)
 | 
					
						
							|  |  |  | 	//		NOTE: this will filter the list but not search the tree...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: if current image is unset then this will not be able to 
 | 
					
						
							|  |  |  | 	// 		get it.
 | 
					
						
							|  |  |  | 	// NOTE: if base ribbon is unset this will return the first ribbon.
 | 
					
						
							|  |  |  | 	getRibbon: function(target){ | 
					
						
							|  |  |  | 		// current...
 | 
					
						
							|  |  |  | 		if(target == null || target == 'current') { | 
					
						
							|  |  |  | 			return this.getImage().parents('.ribbon').first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// dom element...
 | 
					
						
							|  |  |  | 		} else if(target instanceof $ | 
					
						
							|  |  |  | 				&& target.hasClass('image')){ | 
					
						
							|  |  |  | 			return this.getImage(target).parents('.ribbon').first() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// base...
 | 
					
						
							|  |  |  | 		} else if(target == 'base'){ | 
					
						
							|  |  |  | 			var r = this.viewer.find('.base.ribbon').first() | 
					
						
							|  |  |  | 			if(r.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return this.viewer.find(RIBBON).first() } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 			return r | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// index...
 | 
					
						
							|  |  |  | 		} else if(typeof(target) == typeof(123)){ | 
					
						
							|  |  |  | 			return this.viewer.find(RIBBON).eq(target) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// gid...
 | 
					
						
							|  |  |  | 		} else if(typeof(target) == typeof('str')){ | 
					
						
							|  |  |  | 			//return this.viewer.find('.ribbon[gid="'+JSON.stringify(target)+'"]')
 | 
					
						
							|  |  |  | 			var r = this.viewer.find('.ribbon[gid='+JSON.stringify(target)+']:not(.clone)') | 
					
						
							|  |  |  | 			// if no ribbon is found, try and get an image and it's ribbon...
 | 
					
						
							|  |  |  | 			return r.length == 0  | 
					
						
							|  |  |  | 				? this.getImage(target).parents('.ribbon').first() | 
					
						
							|  |  |  | 				: r | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return $(target).filter(RIBBON) }, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// Like .getRibbon(..) but returns ribbon index instead of the actual 
 | 
					
						
							|  |  |  | 	// ribbon object...
 | 
					
						
							|  |  |  | 	getRibbonOrder: function(target){ | 
					
						
							|  |  |  | 		return this.viewer.find(RIBBON).index(this.getRibbon(target)) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	// Image info...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: these are simply shorthands to image attr access...
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	getImageRotation: function(target){ | 
					
						
							|  |  |  | 		return (this.getImage(target).attr('orientation') || 0)*1 }, | 
					
						
							|  |  |  | 	getImageFlip: function(target){ | 
					
						
							|  |  |  | 		return (this.getImage(target).attr('flipped') || '') | 
					
						
							|  |  |  | 			.split(',') | 
					
						
							|  |  |  | 			.map(function(e){ return e.trim() }) | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 			.filter(function(e){ return e != '' }) }, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// UI manipulation...
 | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// Compensate for viewer proportioned and rotated images.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will set the margins so as to make the rotated image offset the
 | 
					
						
							|  |  |  | 	// same space as it is occupying visually...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this is not needed for square image blocks.
 | 
					
						
							|  |  |  | 	// NOTE: if an image block is square, this will remove the margins.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX this does the same job as features/ui-single-image.js' .updateImageProportions(..)
 | 
					
						
							|  |  |  | 	_calcImageProportions: function(image, W, H, w, h, o){ | 
					
						
							|  |  |  | 		image = image instanceof jQuery ? image[0] : image | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//var s = (!w || !h) ? getComputedStyle(image) : null
 | 
					
						
							|  |  |  | 		//w = w || parseFloat(s.width)
 | 
					
						
							|  |  |  | 		//h = h || parseFloat(s.height) 
 | 
					
						
							|  |  |  | 		//w = this.px2vmin(w || image.offsetWidth)
 | 
					
						
							|  |  |  | 		//h = this.px2vmin(h || image.offsetHeight)
 | 
					
						
							|  |  |  | 		w = w || image.offsetWidth | 
					
						
							|  |  |  | 		h = h || image.offsetHeight | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// non-square image...
 | 
					
						
							|  |  |  | 		if(w != h){ | 
					
						
							|  |  |  | 			W = W || this.viewer.innerWidth() | 
					
						
							|  |  |  | 			H = H || this.viewer.innerHeight() | 
					
						
							|  |  |  | 			o = o || image.getAttribute('orientation') || 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var viewer_p = W > H ? 'landscape' : 'portrait' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: we need to use the default (CSS) value when 
 | 
					
						
							|  |  |  | 			// 		possible, to avoid sizing issues...
 | 
					
						
							|  |  |  | 			var dfl_w = image.style.width == '' | 
					
						
							|  |  |  | 			var dfl_h = image.style.height == '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var image_p = w > h ? 'landscape' : 'portrait' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// when the image is turned 90deg/270deg and its 
 | 
					
						
							|  |  |  | 			// proportions are the same as the screen...
 | 
					
						
							|  |  |  | 			if((o == 90 || o == 270) && image_p == viewer_p){ | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					width: dfl_h ? '' : (this.px2vmin(h) + 'vmin'), | 
					
						
							|  |  |  | 					height: dfl_w ? '' : (this.px2vmin(w) + 'vmin'), | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					margin:  | 
					
						
							|  |  |  | 						this.px2vmin(-((w - h)/2)) +'vmin ' | 
					
						
							|  |  |  | 						+ this.px2vmin((w - h)/2) + 'vmin', | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if((o == 0 || o == 180) && image_p != viewer_p){ | 
					
						
							|  |  |  | 				return { | 
					
						
							|  |  |  | 					width: dfl_h ? '' : (this.px2vmin(h) + 'vmin'), | 
					
						
							|  |  |  | 					height: dfl_w ? '' : (this.px2vmin(w) + 'vmin'), | 
					
						
							|  |  |  | 					margin: '', | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				} } | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// square image...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return { | 
					
						
							|  |  |  | 				width: '', | 
					
						
							|  |  |  | 				height: '', | 
					
						
							|  |  |  | 				margin: '', | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			} } }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	correctImageProportionsForRotation: function(images, W, H){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		W = W || this.viewer.innerWidth() | 
					
						
							|  |  |  | 		H = H || this.viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var images = images || this.viewer.find(IMAGE) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return $(images).each(function(i, e){ | 
					
						
							|  |  |  | 			var data = that._calcImageProportions(this, W, H) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			data  | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				&& $(this).css(data) }) }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// center a ribbon vertically...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Center current ribbon...
 | 
					
						
							|  |  |  | 	// 	.centerRibbon()
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Center specific ribbon...
 | 
					
						
							|  |  |  | 	// 	.centerRibbon(image)
 | 
					
						
							|  |  |  | 	// 	.centerRibbon(ribbon)
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	// 
 | 
					
						
							|  |  |  | 	centerRibbon: function(target){ | 
					
						
							|  |  |  | 		var ribbon = this.getRibbon(target) | 
					
						
							|  |  |  | 		var locator = this.getRibbonLocator()  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(locator.length == 0 || ribbon.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-21 15:24:06 +03:00
										 |  |  | 		// NOTE: we need to use the same unit here as is used to size 
 | 
					
						
							|  |  |  | 		// 		the image blocks...
 | 
					
						
							|  |  |  | 		var unit = 'vmin' | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 		var t = ribbon[0].offsetTop | 
					
						
							|  |  |  | 		var h = ribbon[0].offsetHeight | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-21 15:24:06 +03:00
										 |  |  | 		locator.transform({ x: 0, y: this.px2v(-(t + h/2), unit) + unit, z: 0 })  | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// center an image horizontally...
 | 
					
						
							|  |  |  | 	// 
 | 
					
						
							|  |  |  | 	// 	Center current ribbon/image...
 | 
					
						
							|  |  |  | 	// 	.centerImage()
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Center specific image...
 | 
					
						
							|  |  |  | 	// 	.centerImage(image)
 | 
					
						
							|  |  |  | 	// 	.centerImage(image, 'center')
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 	Center ribbon before/after an image...
 | 
					
						
							|  |  |  | 	// 	.centerImage(image, 'before')
 | 
					
						
							|  |  |  | 	// 	.centerImage(image, 'after')
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	centerImage: function(target, mode){ | 
					
						
							|  |  |  | 		target = this.getImage(target) | 
					
						
							|  |  |  | 		var ribbon = this.getRibbon(target) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(ribbon.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var l = target[0].offsetLeft | 
					
						
							|  |  |  | 		var w = target[0].offsetWidth | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var image_offset = mode == 'before' ? 0 | 
					
						
							|  |  |  | 			: mode == 'after' ? w | 
					
						
							|  |  |  | 			: w/2 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ribbon.transform({x: -this.px2vmin(l + image_offset) + 'vmin', y: 0, z: 0})  | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | var BaseRibbons =  | 
					
						
							|  |  |  | module.BaseRibbons =  | 
					
						
							| 
									
										
										
										
											2019-07-17 00:07:24 +03:00
										 |  |  | 	object.Constructor('BaseRibbons',  | 
					
						
							| 
									
										
										
										
											2018-12-26 05:21:25 +03:00
										 |  |  | 		BaseRibbonsClassPrototype,  | 
					
						
							|  |  |  | 		BaseRibbonsPrototype) | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //---------------------------------------------------------------------
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | var RibbonsClassPrototype = { | 
					
						
							|  |  |  | 	// DOM Constructors...
 | 
					
						
							|  |  |  | 	// NOTE: these will return unattached objects...
 | 
					
						
							|  |  |  | 	createViewer: function(){ | 
					
						
							|  |  |  | 		return $('<div>') | 
					
						
							|  |  |  | 			.addClass('viewer') | 
					
						
							|  |  |  | 			.attr('tabindex', 0) | 
					
						
							|  |  |  | 			//.append($('<div>')
 | 
					
						
							|  |  |  | 			//	.addClass('ribbon-set'))
 | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// XXX NOTE: quots removal might render this incompatible with older data formats...
 | 
					
						
							|  |  |  | 	createRibbon: function(gids){ | 
					
						
							|  |  |  | 		gids = gids || [] | 
					
						
							|  |  |  | 		gids = gids.constructor !== Array ? [gids] : gids | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		return $(gids.map(function(gid){ | 
					
						
							|  |  |  | 			gid = gid != null ? gid+'' : gid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			return that.elemGID($('<div>') | 
					
						
							|  |  |  | 				.addClass('ribbon'), gid)[0] | 
					
						
							|  |  |  | 			//return $('<div>')
 | 
					
						
							|  |  |  | 			//	.addClass('ribbon-container')
 | 
					
						
							|  |  |  | 			//	.append(that.elemGID($('<div>')
 | 
					
						
							|  |  |  | 			//		.addClass('ribbon'), gid))[0]
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		})) }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	// XXX NOTE: quots removal might render this incompatible with older data formats...
 | 
					
						
							|  |  |  | 	createImage: function(gids){ | 
					
						
							|  |  |  | 		gids = gids || [] | 
					
						
							|  |  |  | 		gids = gids.constructor !== Array ? [gids] : gids | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		return $(gids.map(function(gid){ | 
					
						
							|  |  |  | 			gid = gid != null ? gid+'' : gid | 
					
						
							|  |  |  | 			return that.elemGID($('<div>') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					.addClass('image'), gid)[0] })) }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | 	createMark: function(cls, gid){ | 
					
						
							|  |  |  | 		gid = gid != null ? gid+'' : gid | 
					
						
							|  |  |  | 		return this.elemGID($('<div class="mark">') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			.addClass(cls), gid) }, | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | } | 
					
						
							|  |  |  | RibbonsClassPrototype.__proto__ = BaseRibbonsClassPrototype | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | var RibbonsPrototype = { | 
					
						
							|  |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	clone: function(){ | 
					
						
							|  |  |  | 		var o = new this.constructor() | 
					
						
							|  |  |  | 		if(this.viewer){ | 
					
						
							|  |  |  | 			// XXX does this completely detach from the orriginal???
 | 
					
						
							|  |  |  | 			// XXX do we need to reattach something???
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			o.viewer = this.viewer.clone() } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		if(this.images){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			o.images = this.images.clone() } | 
					
						
							|  |  |  | 		return o }, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Constructors...
 | 
					
						
							|  |  |  | 	createViewer: RibbonsClassPrototype.createViewer, | 
					
						
							|  |  |  | 	createRibbon: RibbonsClassPrototype.createRibbon, | 
					
						
							|  |  |  | 	createImage: RibbonsClassPrototype.createImage, | 
					
						
							|  |  |  | 	createMark: RibbonsClassPrototype.createMark, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Rotate...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Get ribbon rotation angle...
 | 
					
						
							|  |  |  | 	//	.rotate()
 | 
					
						
							|  |  |  | 	//		-> angle
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Rotate to angle...
 | 
					
						
							|  |  |  | 	//	.rotate(20)
 | 
					
						
							|  |  |  | 	//	.rotate(-10)
 | 
					
						
							|  |  |  | 	//		-> ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//	Rotate by angle...
 | 
					
						
							|  |  |  | 	//	.rotate('-=20')
 | 
					
						
							|  |  |  | 	//	.rotate('+=30')
 | 
					
						
							|  |  |  | 	//		-> ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: the angles are not base 360 normalised...
 | 
					
						
							|  |  |  | 	// NOTE: units are ignored and the final angle is always in deg.
 | 
					
						
							|  |  |  | 	rotate: function(angle){ | 
					
						
							|  |  |  | 		// get...
 | 
					
						
							|  |  |  | 		if(arguments.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this.getRibbonSet().rotate() } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// set...
 | 
					
						
							|  |  |  | 		var ribbon_set = this.getRibbonSet()   | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		if(ribbon_set.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return this } | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		angle = typeof(angle) == typeof('str') | 
					
						
							|  |  |  | 			? (/^\+=/.test(angle) ? (ribbon_set.rotate() || 0) + parseFloat(angle.slice(2)) | 
					
						
							|  |  |  | 				:/^\-=/.test(angle) ? (ribbon_set.rotate() || 0) - parseFloat(angle.slice(2)) | 
					
						
							|  |  |  | 				: parseFloat(angle)) | 
					
						
							|  |  |  | 			: angle | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		ribbon_set.rotate(angle) | 
					
						
							| 
									
										
										
										
											2015-12-25 06:22:17 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	 | 
					
						
							|  |  |  | 	// Make a "shadow" image for use with image oriented animations...
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	//	.makeShadow([<image>][, <animate>][, <delay>])
 | 
					
						
							|  |  |  | 	//		-> <finalize>
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// A shadow is a clone of <image> placed directly above it while it 
 | 
					
						
							|  |  |  | 	// is hidden (transparent), calling <finalize> will remove the shadwo
 | 
					
						
							|  |  |  | 	// and restore the original image, if <animate> is set then the shadow
 | 
					
						
							|  |  |  | 	// will be moved to the image location, and <delay> sets the time delay
 | 
					
						
							|  |  |  | 	// to provision for shadow animations.
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// <finalize> is a function, that when called will remove the shadow
 | 
					
						
							|  |  |  | 	// and restore image state.
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// <image> is the target image to clone
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// <animate> if is set, <finalize> will shift the shadow to target 
 | 
					
						
							|  |  |  | 	// image offset before removing it (default: false).
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	// <delay> sets the delay before the shadow is removed and the target 
 | 
					
						
							|  |  |  | 	// state is restored (default: 200).
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: if a previous shadow if the same image exists this will recycle
 | 
					
						
							|  |  |  | 	// 		the existing shadow and cancel it's removal.
 | 
					
						
							|  |  |  | 	// 		...this is useful for when a second consecutive action with
 | 
					
						
							|  |  |  | 	// 		the same image is issued before the previous has time to
 | 
					
						
							|  |  |  | 	// 		complete, recycling the shadow will enable a single flowing 
 | 
					
						
							|  |  |  | 	// 		animation for such series of commands.
 | 
					
						
							|  |  |  | 	// 		Example: several fast consecutive horizontal shifts will result
 | 
					
						
							|  |  |  | 	// 			in a single shadow "flowing" through the ribbon.
 | 
					
						
							|  |  |  | 	// NOTE: multiple shadows of different images are supported...
 | 
					
						
							|  |  |  | 	// NOTE: the .shadow element is essentially a ribbon.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX add duration configuration...
 | 
					
						
							|  |  |  | 	// XXX should we also have a ribbon shadow???
 | 
					
						
							|  |  |  | 	// XXX when this cant find a target it will return an empty function,
 | 
					
						
							|  |  |  | 	// 		not sure if this is correct...
 | 
					
						
							|  |  |  | 	// XXX should we use transforms instead of css positions???
 | 
					
						
							|  |  |  | 	makeShadow: function(target, animate, delay, start_delay){ | 
					
						
							|  |  |  | 		delay = delay || 200 | 
					
						
							|  |  |  | 		start_delay = start_delay || 10 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		var img = this.getImage(target) | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		if(img.length == 0){ | 
					
						
							|  |  |  | 			// XXX is this correct???
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return function(){} } | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		var gid = this.elemGID(img) | 
					
						
							|  |  |  | 		var s = this.scale() | 
					
						
							|  |  |  | 		var vo = this.viewer.offset() | 
					
						
							|  |  |  | 		var io = img.offset() | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 		// get the shadow if it exists...
 | 
					
						
							|  |  |  | 		var shadow = this.viewer.find('.shadow[gid="'+gid+'"]') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// recycle the shadow...
 | 
					
						
							|  |  |  | 		if(shadow.length > 0){ | 
					
						
							|  |  |  | 			// cancel previous shadow removal ticket...
 | 
					
						
							|  |  |  | 			var ticket = shadow.attr('ticket') + 1 | 
					
						
							|  |  |  | 			shadow | 
					
						
							|  |  |  | 				// reset ticket...
 | 
					
						
							|  |  |  | 				// NOTE: this is a possible race condition... (XXX)
 | 
					
						
							|  |  |  | 				.attr('ticket', ticket) | 
					
						
							|  |  |  | 				// place it over the current image...
 | 
					
						
							|  |  |  | 				.css({ | 
					
						
							|  |  |  | 					top: io.top - vo.top, | 
					
						
							|  |  |  | 					left: io.left - vo.left, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// create a new shadow...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// removal ticket...
 | 
					
						
							|  |  |  | 			var ticket = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// make a shadow element...
 | 
					
						
							|  |  |  | 			// ...we need to scale it to the current scale...
 | 
					
						
							|  |  |  | 			var shadow = $('<div>') | 
					
						
							|  |  |  | 				.addClass('shadow ribbon clone') | 
					
						
							|  |  |  | 				.attr({ | 
					
						
							|  |  |  | 					gid: gid, | 
					
						
							|  |  |  | 					ticket: ticket, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.append( | 
					
						
							|  |  |  | 					// clone the target into the shadow..
 | 
					
						
							|  |  |  | 					img | 
					
						
							|  |  |  | 						.clone() | 
					
						
							|  |  |  | 						.addClass('clone') | 
					
						
							|  |  |  | 						.removeClass('current') | 
					
						
							|  |  |  | 						.attr('gid', null)) | 
					
						
							|  |  |  | 				.scale(s) | 
					
						
							|  |  |  | 				// place it over the current image...
 | 
					
						
							|  |  |  | 				.css({ | 
					
						
							|  |  |  | 					top: io.top - vo.top, | 
					
						
							|  |  |  | 					left: io.left - vo.left, | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				.append(this.getImageMarks(img) | 
					
						
							|  |  |  | 						.clone() | 
					
						
							|  |  |  | 						.attr('gid', null)) | 
					
						
							|  |  |  | 				// place in the viewer...
 | 
					
						
							|  |  |  | 				// NOTE: placing the shadow in the viewer is a compromise that
 | 
					
						
							|  |  |  | 				// 		lets us do simpler positioning 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				.appendTo(this.viewer) } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		img.addClass('moving') | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// function to clear the shadow...
 | 
					
						
							|  |  |  | 		return function(){ | 
					
						
							|  |  |  | 			// remove only the item with the correct ticket...
 | 
					
						
							|  |  |  | 			if(ticket == shadow.attr('ticket')){ | 
					
						
							|  |  |  | 				var s = that.scale() | 
					
						
							|  |  |  | 				var img = that.getImage(gid) | 
					
						
							|  |  |  | 				var vo = that.viewer.offset() | 
					
						
							|  |  |  | 				var io = img.offset() | 
					
						
							|  |  |  | 				if(animate){ | 
					
						
							|  |  |  | 					if(start_delay){ | 
					
						
							|  |  |  | 						setTimeout(function(){ | 
					
						
							|  |  |  | 							shadow.css({ | 
					
						
							|  |  |  | 								top: io.top - vo.top, | 
					
						
							|  |  |  | 								left: io.left - vo.left, | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 						}, start_delay) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					} else { | 
					
						
							|  |  |  | 						shadow.css({ | 
					
						
							|  |  |  | 							top: io.top - vo.top, | 
					
						
							|  |  |  | 							left: io.left - vo.left, | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						}) } } | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 				setTimeout(function(){ | 
					
						
							|  |  |  | 					// remove only the item with the correct ticket...
 | 
					
						
							|  |  |  | 					if(ticket == shadow.attr('ticket')){ | 
					
						
							|  |  |  | 						img.removeClass('moving') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						shadow.remove() } }, delay) } | 
					
						
							|  |  |  | 			return img } }, | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	// Basic manipulation...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	// Place a ribbon...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	// Append target ribbon:
 | 
					
						
							|  |  |  | 	//	.placeRibbon(target)
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Place target ribbon at position:
 | 
					
						
							|  |  |  | 	//	.placeRibbon(target, index)
 | 
					
						
							|  |  |  | 	//	.placeRibbon(target, ribbon-gid)
 | 
					
						
							|  |  |  | 	//	.placeRibbon(target, ribbon)
 | 
					
						
							|  |  |  | 	//		-> ribbon
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// The ribbon will be placed at the new position shifting the next 
 | 
					
						
							|  |  |  | 	// ribbon(s), if present, by one.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Indexes if used, can be negative. Negative indexes are relative 
 | 
					
						
							|  |  |  | 	// to the end, e.g. -1 is the same as length-1.
 | 
					
						
							|  |  |  | 	// Placing an element at a negative index will place it AFTER the 
 | 
					
						
							|  |  |  | 	// target element, this is in contrast to positive indexes where an
 | 
					
						
							|  |  |  | 	// element is placed before the target. In both of the above cases
 | 
					
						
							|  |  |  | 	// (positive and negative indexes) the resulting target position 
 | 
					
						
							|  |  |  | 	// will AT the passed position.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: negative and positive indexes overflow to 0 and length
 | 
					
						
							|  |  |  | 	// 		respectively.
 | 
					
						
							|  |  |  | 	// NOTE: both target and position must be .getRibbon(..) compatible.
 | 
					
						
							|  |  |  | 	// NOTE: if target ribbon does not exist a new ribbon will be created.
 | 
					
						
							|  |  |  | 	// NOTE: if position ribbon (gid,ribbon) does not exist or is not 
 | 
					
						
							|  |  |  | 	// 		attached then the target will be appended to the end.
 | 
					
						
							|  |  |  | 	// NOTE: this uses the DOM data for placement, this may differ from 
 | 
					
						
							|  |  |  | 	// 		the actual data.
 | 
					
						
							|  |  |  | 	placeRibbon: function(target, position){ | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		// get create the ribbon...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		var ribbon = this.getRibbon(target) | 
					
						
							| 
									
										
										
										
											2014-09-02 02:55:03 +04:00
										 |  |  | 		var i = this.getRibbonOrder(ribbon) | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		ribbon = ribbon.length == 0 ? this.createRibbon(target) : ribbon | 
					
						
							| 
									
										
										
										
											2016-11-22 16:52:32 +03:00
										 |  |  | 		var ribbon_set = this.getRibbonLocator(true)  | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 		var ribbons = this.viewer.find(RIBBON) | 
					
						
							| 
									
										
										
										
											2014-11-02 03:13:23 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		// normalize the position...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		if(typeof(position) == typeof(123)){ | 
					
						
							|  |  |  | 			position = position < 0 ? ribbons.length + position + 1 : position | 
					
						
							|  |  |  | 			position = position < 0 ? 0 : position | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2014-11-02 03:13:23 +03:00
										 |  |  | 			position = this.getRibbonOrder(position) | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 			// XXX what do we do if the target does not exist, i.e. p == -1 ????
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-18 04:26:52 +04:00
										 |  |  | 		if(i == position){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return ribbon } | 
					
						
							| 
									
										
										
										
											2014-10-18 04:26:52 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		// place the ribbon...
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 		if(ribbons.length == 0 || ribbons.length <= position){ | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 			ribbon_set.append(ribbon) | 
					
						
							| 
									
										
										
										
											2014-07-21 02:30:24 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-02 03:13:23 +03:00
										 |  |  | 		} else if(i == -1 || i > position) { | 
					
						
							| 
									
										
										
										
											2016-11-22 19:12:36 +03:00
										 |  |  | 			// XXX need to compensate for offset???
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 			ribbons.eq(position).before(ribbon) | 
					
						
							| 
									
										
										
										
											2014-10-18 04:26:52 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// for placing after need to account for target ribbon removal...
 | 
					
						
							|  |  |  | 		} else if(i < position) { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			ribbons.eq(position).after(ribbon) } | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// XXX do we need to update the ribbon here???
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return ribbon }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Place an image...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 07:01:08 +04:00
										 |  |  | 	// Place target at at offset from current position:
 | 
					
						
							|  |  |  | 	//	.placeImage(target, offset)
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 07:01:08 +04:00
										 |  |  | 	// Place target at image position:
 | 
					
						
							|  |  |  | 	//	.placeImage(target, image)
 | 
					
						
							|  |  |  | 	//	.placeImage(target, image, 'before')
 | 
					
						
							|  |  |  | 	//	.placeImage(target, image, 'after')
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-10-12 03:14:29 +04:00
										 |  |  | 	// Place target at ribbon start/end:
 | 
					
						
							|  |  |  | 	//	.placeImage(target, ribbon)
 | 
					
						
							|  |  |  | 	//	.placeImage(target, ribbon, 'before')
 | 
					
						
							|  |  |  | 	//	.placeImage(target, ribbon, 'after')
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: mode defaults to 'before'.
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	// NOTE: if image gid does not exist it will be created.
 | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 	// NOTE: if target is a list of gids, this will place the gids in 
 | 
					
						
							|  |  |  | 	// 		the same order as given, not as they were before placing...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX is this too complicated???
 | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 	placeImage: function(target, to, mode){ | 
					
						
							|  |  |  | 		mode = mode == null ? 'before' : mode | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 		if(this.getRibbonSet().length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return } | 
					
						
							| 
									
										
										
										
											2014-11-11 17:33:07 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 		target = target == null || target.constructor !== Array ? [target] : target | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// get or make images...
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var img = $($(target) | 
					
						
							|  |  |  | 			.map(function(_, e){ | 
					
						
							|  |  |  | 				var i = that.getImage(e) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return (i.length == 0 ? that.createImage(e) : i)[0] })) | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 	 | 
					
						
							| 
									
										
										
										
											2014-11-02 03:35:26 +03:00
										 |  |  | 		var i = this.getImage(to) | 
					
						
							| 
									
										
										
										
											2014-10-12 03:14:29 +04:00
										 |  |  | 		var r = this.getRibbon(to) | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 		// offset on same ribbon...
 | 
					
						
							|  |  |  | 		if(typeof(to) == typeof(123)){ | 
					
						
							| 
									
										
										
										
											2014-07-25 07:12:57 +04:00
										 |  |  | 			// moving the image to itself...
 | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 			if(to == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return img } | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 			var i = to | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 			var images = img[i > 0 ? 'last' : 'first']() | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 				[i > 0 ? 'nextAll' : 'prevAll'](IMAGE) | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 			to = images.length > 0  | 
					
						
							|  |  |  | 				? images.eq(Math.min(Math.abs(i), images.length)-1)  | 
					
						
							|  |  |  | 				: img | 
					
						
							| 
									
										
										
										
											2014-10-12 03:14:29 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// append/prepend to ribbon...
 | 
					
						
							| 
									
										
										
										
											2014-11-02 03:35:26 +03:00
										 |  |  | 		} else if(i.length == 0 && r.length > 0 && r.hasClass('ribbon')){ | 
					
						
							| 
									
										
										
										
											2014-10-12 03:14:29 +04:00
										 |  |  | 			if(mode == 'before'){ | 
					
						
							|  |  |  | 				r.append(img) | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				r.prepend(img) } | 
					
						
							| 
									
										
										
										
											2014-10-12 03:14:29 +04:00
										 |  |  | 			return this.updateImage(img) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 		// relative to image...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			var i = mode == 'before' ? -1 : 1 | 
					
						
							|  |  |  | 			to = this.getImage(to) | 
					
						
							| 
									
										
										
										
											2014-07-25 07:12:57 +04:00
										 |  |  | 			// moving the image to itself...
 | 
					
						
							| 
									
										
										
										
											2014-07-25 07:01:08 +04:00
										 |  |  | 			if(to[0] == img[0]){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return img } | 
					
						
							|  |  |  | 			var images = to[mode](IMAGE) } | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// place the image...
 | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 		if(images.length <= i){ | 
					
						
							| 
									
										
										
										
											2014-10-19 05:01:22 +04:00
										 |  |  | 			to.parents('.ribbon') | 
					
						
							|  |  |  | 				.append(img) | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 		// after...
 | 
					
						
							|  |  |  | 		} else if(i > 0){ | 
					
						
							| 
									
										
										
										
											2014-11-03 00:29:49 +03:00
										 |  |  | 			// XXX this stumbles on non-images...
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 			//to.next(IMAGE)
 | 
					
						
							| 
									
										
										
										
											2014-11-03 00:29:49 +03:00
										 |  |  | 			// XXX is this fast enough??
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 			to.nextAll(IMAGE).first() | 
					
						
							| 
									
										
										
										
											2014-10-19 05:01:22 +04:00
										 |  |  | 				.before(img) | 
					
						
							| 
									
										
										
										
											2014-07-25 06:49:36 +04:00
										 |  |  | 		// before...
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2014-10-19 05:01:22 +04:00
										 |  |  | 			to | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				.before(img) } | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 00:53:02 +03:00
										 |  |  | 		// cleanup source ribbons...
 | 
					
						
							|  |  |  | 		this.clearEmptyRibbons() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this.updateImage(img) }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Loading and updating...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 	// Replace image gid...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX should this work for ribbon gids???
 | 
					
						
							|  |  |  | 	replaceGid: function(from, to){ | 
					
						
							|  |  |  | 		var img = this.getImage(from) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		img && img.length > 0  | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 			&& this.elemGID(img, to) | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 	// XXX is .__image_updaters the right way to go???
 | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 	callImageUpdaters: function(gid, image, options){ | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 		gid = gid == null ? this.elemGID() : gid | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		image = image == null ? this.getImage() : $(image) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-19 05:01:22 +04:00
										 |  |  | 		// collect marks...
 | 
					
						
							|  |  |  | 		image.after(this.getImageMarks(gid)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 		;(this.__image_updaters || []) | 
					
						
							|  |  |  | 			.forEach(function(update){ | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 				update(gid, image, options) }) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return image }, | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 	_loadImagePreviewURL: function(image, url, other, callback){ | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | 		url = util.path2url(url) | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		// pre-cache and load image...
 | 
					
						
							|  |  |  | 		// NOTE: this will make images load without a blackout...
 | 
					
						
							|  |  |  | 		var img = new Image() | 
					
						
							| 
									
										
										
										
											2017-04-28 22:38:31 +03:00
										 |  |  | 		var i = image instanceof jQuery ? image[0] : image | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		img.onload = function(){ | 
					
						
							| 
									
										
										
										
											2020-05-21 03:37:50 +03:00
										 |  |  | 			i.style.backgroundImage = 'url("'+ img.src +'")', | 
					
						
							| 
									
										
										
										
											2016-04-02 22:53:56 +03:00
										 |  |  | 			// NOTE: these do not account for rotation...
 | 
					
						
							|  |  |  | 			i.setAttribute('preview-width', img.width) | 
					
						
							| 
									
										
										
										
											2020-05-21 03:37:50 +03:00
										 |  |  | 			i.setAttribute('preview-height', img.height) } | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 		// error -> try other images -> load placeholder...
 | 
					
						
							| 
									
										
										
										
											2020-05-21 03:37:50 +03:00
										 |  |  | 		img.onerror = function(){ | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 			other = other instanceof Function ? | 
					
						
							|  |  |  | 				[...other(), images.MISSING] | 
					
						
							|  |  |  | 				: other | 
					
						
							|  |  |  | 			other  | 
					
						
							|  |  |  | 				&& other.length > 0 | 
					
						
							|  |  |  | 				&& (img.src = other.shift())  | 
					
						
							|  |  |  | 			// call the callback once...
 | 
					
						
							|  |  |  | 			callback | 
					
						
							|  |  |  | 				&& callback()  | 
					
						
							|  |  |  | 			callback = null } | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		img.src = url | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return img }, | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Update image(s)...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Update current image:
 | 
					
						
							|  |  |  | 	//	.updateImage()
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-29 19:09:05 +04:00
										 |  |  | 	// Update specific image:
 | 
					
						
							|  |  |  | 	//	.updateImage(gid)
 | 
					
						
							|  |  |  | 	//	.updateImage(image)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Update all image:
 | 
					
						
							|  |  |  | 	//	.updateImage('*')
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// options format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		nochrome: <bool>,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		pre_updaters_callback: <function>,
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-29 19:09:05 +04:00
										 |  |  | 	// NOTE: this can update collections of images by passing either a 
 | 
					
						
							|  |  |  | 	// 		list of gids, images or a jQuery collection...
 | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 	// NOTE: pre_updaters_callback if given is called after image is fully
 | 
					
						
							|  |  |  | 	// 		constructed but before .callImageUpdaters(..) is called...
 | 
					
						
							| 
									
										
										
										
											2014-07-29 19:09:05 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 22:10:43 +04:00
										 |  |  | 	// If this is set to true image previews will be loaded synchronously...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	load_img_sync: false, | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 	// handle image load errors...
 | 
					
						
							|  |  |  | 	// XXX revise...
 | 
					
						
							|  |  |  | 	imageLoadErrorCallback: undefined, | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-09-02 02:55:03 +04:00
										 |  |  | 	// XXX this depends on .images...
 | 
					
						
							|  |  |  | 	// 		...a good candidate to move to images, but not yet sure...
 | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 	// XXX things to inline:
 | 
					
						
							|  |  |  | 	// 		.gid
 | 
					
						
							|  |  |  | 	// 		.style.backgroundImage
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		.getImageMarks(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		.rotateImage(..)
 | 
					
						
							|  |  |  | 	// 		.flipImage(..)
 | 
					
						
							|  |  |  | 	// 		._loadImagePreviewURL(..)
 | 
					
						
							|  |  |  | 	// 		.correctImageProportionsForRotation(..)
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 	// 		.callImageUpdaters(..)
 | 
					
						
							| 
									
										
										
										
											2019-10-09 03:04:46 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2017-04-24 14:34:09 +03:00
										 |  |  | 	// XXX add options for images to preload and only then do the update...
 | 
					
						
							| 
									
										
										
										
											2018-03-23 00:47:39 +03:00
										 |  |  | 	// XXX really slow for very large numbers of input images/gids...
 | 
					
						
							| 
									
										
										
										
											2019-10-09 03:04:46 +03:00
										 |  |  | 	// XXX add support for basic image templating here...
 | 
					
						
							|  |  |  | 	// 		...templates for blank images, text blocks and other stuff,
 | 
					
						
							|  |  |  | 	// 		this would best be done by simply filling in SVG templates...
 | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 	updateImage: function(image, gid, size, sync, options){ | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2018-03-23 00:47:39 +03:00
										 |  |  | 		var imgs = this.viewer.find(IMAGE) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 		options = options || {} | 
					
						
							|  |  |  | 		var pre_updaters_callback = options.pre_updaters_callback | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 		var error_update_callback = options.error_update_callback | 
					
						
							|  |  |  | 			|| this.imageLoadErrorCallback | 
					
						
							|  |  |  | 		error_update_callback = error_update_callback  | 
					
						
							|  |  |  | 			&& error_update_callback.bind(this) | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-03-23 00:47:39 +03:00
										 |  |  | 		// reduce the length of input image set...
 | 
					
						
							|  |  |  | 		// NOTE: this will make things substantially faster for very large
 | 
					
						
							|  |  |  | 		// 		input sets...
 | 
					
						
							|  |  |  | 		if(image instanceof Array && image.length > imgs.length){ | 
					
						
							|  |  |  | 			image = imgs | 
					
						
							|  |  |  | 				.filter(function(_, img){ | 
					
						
							|  |  |  | 					return image.indexOf(img) >= 0 | 
					
						
							|  |  |  | 						|| image.indexOf(that.elemGID(img)) >= 0 }) | 
					
						
							|  |  |  | 				.map(function(_, img){ | 
					
						
							|  |  |  | 					return that.elemGID(img) }) | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 				.toArray() } | 
					
						
							| 
									
										
										
										
											2018-03-23 00:47:39 +03:00
										 |  |  | 		// normalize...
 | 
					
						
							|  |  |  | 		image = image == '*' ?  | 
					
						
							|  |  |  | 				imgs | 
					
						
							|  |  |  | 			: (image == null || typeof(image) == typeof('str')) ?  | 
					
						
							|  |  |  | 				this.getImage(image) | 
					
						
							|  |  |  | 			: $(image) | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 		sync = sync == null ? this.load_img_sync : sync | 
					
						
							|  |  |  | 		size = size == null ? this.getVisibleImageSize('max') : size | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var update = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// build update data...
 | 
					
						
							|  |  |  | 		image.map(function(_, image){ | 
					
						
							|  |  |  | 			image = typeof(image) == typeof('str') ?  | 
					
						
							|  |  |  | 				that.getImage(image)  | 
					
						
							|  |  |  | 				: $(image) | 
					
						
							|  |  |  | 			if(image.length == 0){ | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 			var old_gid = that.elemGID(image) | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 			var data = update[old_gid] = { | 
					
						
							|  |  |  | 				image: image, | 
					
						
							|  |  |  | 				attrs: {}, | 
					
						
							|  |  |  | 				style: {}, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var reset_preview = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// same image -- update...
 | 
					
						
							|  |  |  | 			if(old_gid == gid || gid == null){ | 
					
						
							|  |  |  | 				// XXX BUG: we are actually ignoring gid...
 | 
					
						
							|  |  |  | 				var gid = old_gid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// reuse for different image -- reconstruct...
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// remove old marks...
 | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 				typeof(old_gid) == typeof('str') | 
					
						
							|  |  |  | 					&& that.getImageMarks(old_gid).remove() | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 				// reset gid...
 | 
					
						
							|  |  |  | 				data.attrs = { | 
					
						
							|  |  |  | 					gid: JSON.stringify(gid) | 
					
						
							|  |  |  | 						// this removes the extra quots...
 | 
					
						
							|  |  |  | 						.replace(/^"(.*)"$/g, '$1'), | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				reset_preview = true } | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 			data.gid = gid | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// if no images data defined drop out...
 | 
					
						
							|  |  |  | 			if(that.images == null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return } | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// image data...
 | 
					
						
							|  |  |  | 			var img_data = that.images[gid] || images.IMAGE_DATA | 
					
						
							|  |  |  | 			// if we are a group, get the cover...
 | 
					
						
							|  |  |  | 			// NOTE: groups can be nested...
 | 
					
						
							|  |  |  | 			var seen = [] | 
					
						
							|  |  |  | 			while(img_data.type == 'group'){ | 
					
						
							|  |  |  | 				// error, recursive group...
 | 
					
						
							|  |  |  | 				if(seen.indexOf(img_data.id) >= 0){ | 
					
						
							|  |  |  | 					img_data = images.IMAGE_DATA | 
					
						
							|  |  |  | 					console.error('Recursive group:', gid) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					break } | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 				seen.push(img_data.id) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				img_data = that.images[img_data.cover] } | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// image state...
 | 
					
						
							|  |  |  | 			data.attrs.orientation = img_data.orientation == null ? '' : img_data.orientation*1 | 
					
						
							|  |  |  | 			data.attrs.flipped = (img_data.flipped == null ? [] : img_data.flipped).join(', ') | 
					
						
							|  |  |  | 			//will_change.push('transform')
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// stage background image update...
 | 
					
						
							| 
									
										
										
										
											2019-10-09 03:04:46 +03:00
										 |  |  | 			// XXX add support for basic templating here...
 | 
					
						
							|  |  |  | 			var p_url = (that.images.getBestPreview(img_data.id, size, img_data, true) || {}).url | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 			// XXX sort the previews by size...
 | 
					
						
							|  |  |  | 			var alt_url = function(){ | 
					
						
							|  |  |  | 				return [...Object.values(img_data.preview || {}), img_data.path] | 
					
						
							|  |  |  | 					.map(function(u){  | 
					
						
							|  |  |  | 						return (img_data.base_path || '') + u }) | 
					
						
							|  |  |  | 					.filter(function(u){ return u != p_url }) } | 
					
						
							| 
									
										
										
										
											2019-10-09 03:04:46 +03:00
										 |  |  | 			// no preview -> reset bg...
 | 
					
						
							|  |  |  | 			if(p_url == null){ | 
					
						
							|  |  |  | 				image[0].style.backgroundImage = '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else if(old_gid != gid  | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 					// the new preview (p_url) is different to current...
 | 
					
						
							|  |  |  | 					// NOTE: this may not work correctly for relative urls...
 | 
					
						
							|  |  |  | 					|| image.css('background-image').indexOf(util.path2url(p_url)) < 0){ | 
					
						
							|  |  |  | 				//will_change.push('background-image')
 | 
					
						
							|  |  |  | 				reset_preview | 
					
						
							|  |  |  | 					&& (image[0].style.backgroundImage = '') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// sync...
 | 
					
						
							|  |  |  | 				if(sync){ | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 					that._loadImagePreviewURL( | 
					
						
							|  |  |  | 						image,  | 
					
						
							|  |  |  | 						p_url,  | 
					
						
							|  |  |  | 						alt_url,  | 
					
						
							|  |  |  | 						error_update_callback) | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// async...
 | 
					
						
							|  |  |  | 				// NOTE: storing the url in .data() makes the image load the 
 | 
					
						
							|  |  |  | 				// 		last requested preview and in a case when we manage to 
 | 
					
						
							|  |  |  | 				// 		call updateImage(...) on the same element multiple times 
 | 
					
						
							|  |  |  | 				// 		before the previews get loaded...
 | 
					
						
							|  |  |  | 				// 		...setting the data().loading is sync while loading an 
 | 
					
						
							|  |  |  | 				// 		image is not, and if several loads are done in sequence
 | 
					
						
							|  |  |  | 				// 		there is no guarantee that they will happen in the same
 | 
					
						
							|  |  |  | 				// 		order as requested...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					image.data().loading = p_url | 
					
						
							|  |  |  | 					setTimeout(function(){  | 
					
						
							| 
									
										
										
										
											2020-05-21 04:29:44 +03:00
										 |  |  | 						that._loadImagePreviewURL( | 
					
						
							|  |  |  | 							image,  | 
					
						
							|  |  |  | 							image.data().loading,  | 
					
						
							|  |  |  | 							alt_url,  | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 							error_update_callback) }, 0) } } }) | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var W = this.viewer.innerWidth() | 
					
						
							|  |  |  | 		var H = this.viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// do the update...
 | 
					
						
							|  |  |  | 		return $(Object.keys(update).map(function(gid){ | 
					
						
							|  |  |  | 			var data = update[gid] | 
					
						
							|  |  |  | 			var img = data.image | 
					
						
							|  |  |  | 			var _img = img[0] | 
					
						
							|  |  |  | 			var attrs = data.attrs | 
					
						
							|  |  |  | 			var css = data.style | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			attrs && img.attr(attrs) | 
					
						
							|  |  |  | 			css && img.css(css) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			that.correctImageProportionsForRotation(img, W, H) | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 			pre_updaters_callback  | 
					
						
							|  |  |  | 				&& pre_updaters_callback.call(that, image, data) | 
					
						
							| 
									
										
										
										
											2019-10-10 18:01:55 +03:00
										 |  |  | 			that.callImageUpdaters(data.gid, img, options) | 
					
						
							| 
									
										
										
										
											2017-04-23 02:03:33 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return _img })) }, | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 	// Update ribbon content...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// This will reuse the images that already exist, thus if updating or
 | 
					
						
							|  |  |  | 	// adding images to an already loaded set this should be very fast.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-10-29 23:38:27 +03:00
										 |  |  | 	// If reference is given then this will compensate ribbon offset to
 | 
					
						
							|  |  |  | 	// keep the reference image in the same position (XXX ???) 
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// gids must be a list of gids.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// ribbons must be .getRibbon(..) compatible.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-11-08 16:18:20 +03:00
										 |  |  | 	// reference must be .getImage(..) compatible or null to disable 
 | 
					
						
							|  |  |  | 	// offset compensation.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will change ribbon size and compensate for it, but this 
 | 
					
						
							|  |  |  | 	// 		will not disable transitions, which at this point is the 
 | 
					
						
							|  |  |  | 	// 		responsibility of the caller...
 | 
					
						
							|  |  |  | 	// NOTE: offset calculation depends on image blocks being square...
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:56:59 +03:00
										 |  |  | 	// NOTE: the argument force is currently ignored, it serves as a 
 | 
					
						
							|  |  |  | 	// 		place holder for overloading...
 | 
					
						
							| 
									
										
										
										
											2015-12-16 07:58:13 +03:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-26 06:44:43 +03:00
										 |  |  | 	// XXX this depends on image size being fixed for compensating 
 | 
					
						
							|  |  |  | 	// 		position shift...
 | 
					
						
							|  |  |  | 	// 		...a simpler way to go is to check .position().left of the 
 | 
					
						
							|  |  |  | 	// 		reference image before and after the chage and add the delta
 | 
					
						
							|  |  |  | 	// 		to the offset...
 | 
					
						
							| 
									
										
										
										
											2015-12-16 07:58:13 +03:00
										 |  |  | 	// XXX make this add images in chunks of adjacent images...
 | 
					
						
							| 
									
										
										
										
											2015-12-23 03:01:55 +03:00
										 |  |  | 	// XXX might be a good idea to do the actual adding in requestAnimationFrame(..)
 | 
					
						
							| 
									
										
										
										
											2014-11-25 15:56:59 +03:00
										 |  |  | 	updateRibbon: function(gids, ribbon, reference, force){ | 
					
						
							| 
									
										
										
										
											2014-10-22 01:05:59 +04:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2015-07-31 19:00:29 +03:00
										 |  |  | 		var place = false | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 		// get/create the ribbon...
 | 
					
						
							|  |  |  | 		var r = this.getRibbon(ribbon) | 
					
						
							| 
									
										
										
										
											2015-07-31 19:00:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 		if(r.length == 0){ | 
					
						
							| 
									
										
										
										
											2015-07-31 19:00:29 +03:00
										 |  |  | 			place = true | 
					
						
							|  |  |  | 			// no such ribbon exists, then create and append it in the end...
 | 
					
						
							|  |  |  | 			// NOTE: this effectively makes the update offline and pushes
 | 
					
						
							|  |  |  | 			// 		the new ribbon on the dom in one go...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			r = this.createRibbon(ribbon) } | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 		var loaded = r.find(IMAGE) | 
					
						
							| 
									
										
										
										
											2014-10-29 23:38:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// compensate for new/removed images...
 | 
					
						
							|  |  |  | 		if(reference != null){ | 
					
						
							|  |  |  | 			var ref = this.getImage(reference) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// align only if ref is loaded...
 | 
					
						
							|  |  |  | 			if(ref.length > 0){ | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 				var gid = this.elemGID(ref) | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 				var W = Math.min(document.body.offsetWidth, document.body.offsetHeight) | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 				var w = this.getVisibleImageSize('width', 1, ref) / W * 100 | 
					
						
							| 
									
										
										
										
											2014-10-29 23:38:27 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// calculate offset...
 | 
					
						
							|  |  |  | 				// NOTE: this will not work for non-square images...
 | 
					
						
							|  |  |  | 				var dl = loaded.index(ref) - gids.indexOf(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(dl != 0){ | 
					
						
							| 
									
										
										
										
											2016-12-02 03:10:12 +03:00
										 |  |  | 					var x = parseFloat((r.transform('translate3d') || [0])[0]) + w * dl | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					r.transform({x: x + 'vmin', y: 0, z: 0}) } } } | 
					
						
							| 
									
										
										
										
											2014-11-19 19:30:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 01:05:59 +04:00
										 |  |  | 		// remove all images that we do not need...
 | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 		var unloaded = [] | 
					
						
							|  |  |  | 		var unload_marks = [] | 
					
						
							| 
									
										
										
										
											2014-10-22 01:05:59 +04:00
										 |  |  | 		loaded = loaded | 
					
						
							|  |  |  | 			.filter(function(i, img){  | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 				var g = that.elemGID(img) | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 				if(gids.indexOf(g) >= 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					return true } | 
					
						
							| 
									
										
										
										
											2014-11-15 03:17:21 +03:00
										 |  |  | 				unloaded.push(img) | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 				unload_marks = unload_marks.concat(that.getImageMarks(g).toArray()) | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return false }) | 
					
						
							| 
									
										
										
										
											2016-04-13 01:17:53 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// detach/remove everything in one go...
 | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 		$(unloaded) | 
					
						
							| 
									
										
										
										
											2014-11-17 00:12:29 +03:00
										 |  |  | 			.detach() | 
					
						
							| 
									
										
										
										
											2015-12-17 09:14:59 +03:00
										 |  |  | 			.removeClass('moving current') | 
					
						
							| 
									
										
										
										
											2015-11-18 06:16:04 +03:00
										 |  |  | 			// blank out images to prevent wrong image flashing...
 | 
					
						
							|  |  |  | 			.css('background-image', 'none') | 
					
						
							| 
									
										
										
										
											2014-11-21 23:53:55 +03:00
										 |  |  | 		// clear marks...
 | 
					
						
							|  |  |  | 		$(unload_marks) | 
					
						
							|  |  |  | 			.remove() | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | 		var images = [] | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 		$(gids).each(function(i, gid){ | 
					
						
							| 
									
										
										
										
											2014-07-28 22:10:43 +04:00
										 |  |  | 			// support for sparse ribbons...
 | 
					
						
							|  |  |  | 			if(gid == null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				return } | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 			// get/create image...
 | 
					
						
							| 
									
										
										
										
											2014-11-15 03:17:21 +03:00
										 |  |  | 			// NOTE: as this will get a loaded image if it's loaded in 
 | 
					
						
							|  |  |  | 			// 		a different ribbon this WILL affect that ribbon...
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 			var img = that.getImage(gid) | 
					
						
							| 
									
										
										
										
											2014-11-15 03:17:21 +03:00
										 |  |  | 			if(img.length == 0){ | 
					
						
							|  |  |  | 				img = unloaded.length > 0  | 
					
						
							|  |  |  | 					// reuse an image we just detached...
 | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 					? that.elemGID(unloaded.pop(), gid)  | 
					
						
							| 
									
										
										
										
											2014-11-15 03:17:21 +03:00
										 |  |  | 					// create a new image...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					: that.createImage(gid) } | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 01:05:59 +04:00
										 |  |  | 			// see of we are loaded in the right position...
 | 
					
						
							| 
									
										
										
										
											2014-11-17 01:21:14 +03:00
										 |  |  | 			// NOTE: loaded is maintained current later, thus it always 
 | 
					
						
							|  |  |  | 			// 		contains a set of images representative of the ribbon...
 | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 			var g = loaded.length > i ? that.elemGID(loaded.eq(i)) : null | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// check if we need to reattach the image...
 | 
					
						
							|  |  |  | 			if(gid != g){ | 
					
						
							|  |  |  | 				// append the image to set...
 | 
					
						
							|  |  |  | 				if(loaded.length == 0 || loaded.length <= i){ | 
					
						
							|  |  |  | 					r.append(img.detach()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// attach the image at i...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// update the DOM...
 | 
					
						
							|  |  |  | 					loaded.eq(i).before(img.detach()) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// update the loaded list...
 | 
					
						
							|  |  |  | 					var l = loaded.index(img) | 
					
						
							|  |  |  | 					if(l >= 0){ | 
					
						
							|  |  |  | 						loaded.splice(l, 1) | 
					
						
							|  |  |  | 					} | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					loaded.splice(i, 0, img) } } | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			images.push(img[0]) }) | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-12-19 19:34:38 +03:00
										 |  |  | 		// XXX this appears to be the bottleneck on large numbers of images...
 | 
					
						
							|  |  |  | 		this.updateImage($(images)) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-07-31 19:00:29 +03:00
										 |  |  | 		if(place){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			this.placeRibbon(r, this.viewer.find(RIBBON).length) } | 
					
						
							| 
									
										
										
										
											2015-07-31 19:00:29 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 	// NOTE: reference must be both present in the loaded ribbon and in
 | 
					
						
							|  |  |  | 	// 		the given gids...
 | 
					
						
							|  |  |  | 	updateRibbonInPlace: function(gids, ribbon, reference){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		var r = this.getRibbon(ribbon) | 
					
						
							|  |  |  | 		var loaded = r.find(IMAGE) | 
					
						
							| 
									
										
										
										
											2017-04-20 03:46:35 +03:00
										 |  |  | 		gids = gids.slice(0, loaded.length) | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// update offset...
 | 
					
						
							|  |  |  | 		if(reference != null){ | 
					
						
							|  |  |  | 			var ref = this.getImage(reference) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// align only if ref is loaded...
 | 
					
						
							|  |  |  | 			if(ref.length > 0){ | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 				var gid = this.elemGID(ref) | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 				var W = Math.min(document.body.offsetWidth, document.body.offsetHeight) | 
					
						
							|  |  |  | 				var w = this.getVisibleImageSize('width', 1, ref) / W * 100 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// calculate offset...
 | 
					
						
							|  |  |  | 				// NOTE: this will not work for non-square images...
 | 
					
						
							|  |  |  | 				var dl = loaded.index(ref) - gids.indexOf(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(dl != 0){ | 
					
						
							|  |  |  | 					var x = parseFloat((r.transform('translate3d') || [0])[0]) + w * dl | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					r.transform({x: x + 'vmin', y: 0, z: 0}) } } } | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// update gids...
 | 
					
						
							| 
									
										
										
										
											2017-04-19 21:39:25 +03:00
										 |  |  | 		var unload_marks = [] | 
					
						
							| 
									
										
										
										
											2017-04-21 14:52:58 +03:00
										 |  |  | 		for(var i = 0; i < gids.length; i++){ | 
					
						
							|  |  |  | 			var gid = gids[i] | 
					
						
							|  |  |  | 		//gids
 | 
					
						
							|  |  |  | 		//	.forEach(function(gid, i){ 
 | 
					
						
							| 
									
										
										
										
											2017-04-19 21:39:25 +03:00
										 |  |  | 				if(gid !== undefined){ | 
					
						
							|  |  |  | 					var img = loaded.eq(i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// cleanup marks...
 | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 					var g = that.elemGID(img) | 
					
						
							| 
									
										
										
										
											2017-04-19 21:39:25 +03:00
										 |  |  | 					unload_marks = gids.indexOf(g) < 0 ? | 
					
						
							|  |  |  | 						unload_marks.concat(that.getImageMarks(g).toArray()) | 
					
						
							|  |  |  | 						: unload_marks | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-04-20 03:46:35 +03:00
										 |  |  | 					// XXX for some reason this is smoother than:
 | 
					
						
							|  |  |  | 					// 		gid && that.updateImage(img, gid)
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					gid && that.updateImage(that.elemGID(img, gid)) } | 
					
						
							| 
									
										
										
										
											2017-04-21 14:52:58 +03:00
										 |  |  | 		//	})
 | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-04-19 21:39:25 +03:00
										 |  |  | 		$(unload_marks) | 
					
						
							|  |  |  | 			.remove() | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2017-04-16 18:35:28 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 	// Resize ribbon...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 	// 	.resizeRibbon(ribbon, left, right)
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 	// 		-> ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// left/right can be:
 | 
					
						
							|  |  |  | 	// 	- negative number		- the number of images to trim
 | 
					
						
							|  |  |  | 	// 	- list of gids			- the images to add
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this is a less general but simpler/faster alternative to 
 | 
					
						
							|  |  |  | 	// 		.updateRibbon(..)
 | 
					
						
							|  |  |  | 	// NOTE: this needs the ribbon to exist...
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// XXX revize offset compensation + cleanup...
 | 
					
						
							|  |  |  | 	// 		...at this point offset compensation animates...
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 	resizeRibbon: function(ribbon, left, right, transitions, reference){ | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 		ribbon = this.getRibbon(ribbon) | 
					
						
							|  |  |  | 		left = left || 0 | 
					
						
							|  |  |  | 		right = right || 0 | 
					
						
							|  |  |  | 		reference = this.getImage(reference) | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 		 | 
					
						
							|  |  |  | 		var W = Math.min(document.body.offsetWidth, document.body.offsetHeight) | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 		var w = this.getVisibleImageSize('width', 1, reference) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var images = ribbon.find(IMAGE) | 
					
						
							|  |  |  | 		var unloaded = $() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// trim right...
 | 
					
						
							|  |  |  | 		if(right < 0){ | 
					
						
							|  |  |  | 			var marks = [] | 
					
						
							|  |  |  | 			var unloaded = images.slice(images.length + right) | 
					
						
							|  |  |  | 				// remove marks...
 | 
					
						
							|  |  |  | 				.each(function(_, img){ | 
					
						
							|  |  |  | 					marks = marks.concat( | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						that.getImageMarks(that.elemGID(img)).toArray()) }) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				 | 
					
						
							|  |  |  | 			// clear stuff...
 | 
					
						
							|  |  |  | 			$(marks) | 
					
						
							|  |  |  | 				.remove() | 
					
						
							|  |  |  | 			unloaded | 
					
						
							|  |  |  | 				.detach() | 
					
						
							|  |  |  | 				.removeClass('moving current') | 
					
						
							|  |  |  | 				// blank out images to prevent wrong image flashing 
 | 
					
						
							|  |  |  | 				// when reusing...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				.css('background-image', 'none') }  | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// trim left...
 | 
					
						
							|  |  |  | 		// NOTE: this affects ribbon placement, thus we'll need to compensate...
 | 
					
						
							|  |  |  | 		if(left < 0){ | 
					
						
							|  |  |  | 			var marks = [] | 
					
						
							|  |  |  | 			// NOTE: we do not need to append or conserve previous unloaded
 | 
					
						
							|  |  |  | 			// 		images as we will need them only if we are trimming from 
 | 
					
						
							|  |  |  | 			// 		one side and growing the other...
 | 
					
						
							|  |  |  | 			var unloaded = images.slice(0, -left) | 
					
						
							|  |  |  | 				// remove marks...
 | 
					
						
							|  |  |  | 				.each(function(_, img){ | 
					
						
							|  |  |  | 					marks = marks.concat( | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						that.getImageMarks(that.elemGID(img)).toArray()) }) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// calculate the compensation...
 | 
					
						
							|  |  |  | 			// XXX this assumes that all widths are equal...
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 			// 		...we can't calculate image width unless it is attached...
 | 
					
						
							|  |  |  | 			//var l = -left * (reference.outerWidth() / scale)
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 			//var l = -left * w
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// clear stuff...
 | 
					
						
							|  |  |  | 			$(marks) | 
					
						
							|  |  |  | 				.remove() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			requestAnimationFrame(function(){ | 
					
						
							|  |  |  | 				transitions || that.preventTransitions(ribbon) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 				var a = images[-left].offsetLeft | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				unloaded | 
					
						
							|  |  |  | 					.detach() | 
					
						
							|  |  |  | 					.removeClass('moving current') | 
					
						
							|  |  |  | 					// blank out images to prevent wrong image flashing 
 | 
					
						
							|  |  |  | 					// when reusing...
 | 
					
						
							|  |  |  | 					.css('background-image', 'none') | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				// compensate for the offset...
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 				var b = images[-left].offsetLeft | 
					
						
							|  |  |  | 				var d = ((a - b) / W) * 100 | 
					
						
							| 
									
										
										
										
											2016-12-02 03:10:12 +03:00
										 |  |  | 				var x = parseFloat((ribbon.transform('translate3d') || [0])[0]) + d | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				ribbon.transform({x: x + 'vmin', y: 0, z: 0}) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				transitions || that.restoreTransitions(ribbon, true) }) } | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// grow right...
 | 
					
						
							|  |  |  | 		if(right.length > 0 || right > 0){ | 
					
						
							|  |  |  | 			var c = right.length || right | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// build set of empty images...
 | 
					
						
							|  |  |  | 			var loading = unloaded.slice(0, c) | 
					
						
							|  |  |  | 			while(loading.length < c){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				loading.push(that.createImage([''])[0]) } | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// update images...
 | 
					
						
							|  |  |  | 			right instanceof Array && right.forEach(function(gid, i){ | 
					
						
							|  |  |  | 				var img = loading.eq(i) | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 				that.elemGID(img, gid)  | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				// XXX for some reason this does not add indicators...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				that.updateImage(img) }) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			ribbon.append(loading) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX this is here to update the indicators...
 | 
					
						
							|  |  |  | 			// 		...indicators seem to not be attached above...
 | 
					
						
							|  |  |  | 			loading.each(function(_, img){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				that.updateImage(img) }) } | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// grow left...
 | 
					
						
							|  |  |  | 		// NOTE: this affects ribbon placement, thus we'll need to compensate...
 | 
					
						
							|  |  |  | 		if(left.length > 0 || left > 0){ | 
					
						
							|  |  |  | 			var c = left.length || left | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// build set of empty images...
 | 
					
						
							|  |  |  | 			var loading = unloaded.slice(0, c) | 
					
						
							|  |  |  | 			while(loading.length < c){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				loading.push(that.createImage([''])[0]) } | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// update images...
 | 
					
						
							|  |  |  | 			left instanceof Array && left.forEach(function(gid, i){ | 
					
						
							|  |  |  | 				var img = loading.eq(i) | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 				that.elemGID(img, gid)  | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				// XXX for some reason this does not add indicators...
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				that.updateImage(img) }) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// calculate the compensation...
 | 
					
						
							|  |  |  | 			// XXX this assumes that all widths are equal...
 | 
					
						
							|  |  |  | 			// 		...we can't calculate image with unless it is attached...
 | 
					
						
							| 
									
										
										
										
											2016-06-19 19:06:01 +03:00
										 |  |  | 			//var l = c * (reference.outerWidth() / scale)
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 			//var l = c * w 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			requestAnimationFrame(function(){ | 
					
						
							|  |  |  | 				transitions || that.preventTransitions(ribbon) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 				// XXX is this the correct reference item -- can it be deleted above???
 | 
					
						
							|  |  |  | 				var a = images[0].offsetLeft | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 				ribbon.prepend(loading) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX this is here to update the indicators...
 | 
					
						
							|  |  |  | 				// 		...indicators seem to not be attached above...
 | 
					
						
							|  |  |  | 				loading.each(function(_, img){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					that.updateImage(img) }) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// compensate for the offset...
 | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 				// XXX is this the correct reference item -- can it be deleted above???
 | 
					
						
							|  |  |  | 				var b = images[0].offsetLeft | 
					
						
							|  |  |  | 				var d = ((a - b) / W) * 100 | 
					
						
							| 
									
										
										
										
											2016-12-02 03:10:12 +03:00
										 |  |  | 				var x = parseFloat((ribbon.transform('translate3d') || [0])[0]) + d | 
					
						
							| 
									
										
										
										
											2016-11-30 06:37:22 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				ribbon.transform({x: x + 'vmin', y: 0, z: 0}) | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				transitions || that.restoreTransitions(ribbon, true) }) } | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2016-04-23 17:12:38 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-06-20 23:30:46 +03:00
										 |  |  | 	// Update the data in ribbons...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	// 	.updateData(data, settings)
 | 
					
						
							|  |  |  | 	// 		-> ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	// This uses .updateRibbon(..) to load individual ribbons, for
 | 
					
						
							|  |  |  | 	// more info see docs for that.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This uses data.ribbon_order to place the ribbons and data.ribbons
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	// to place the images.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// This uses data.base and data.current to set the base ribbon and 
 | 
					
						
							|  |  |  | 	// current image respectively.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// All the data fields are optional, but for this to make a change 
 | 
					
						
							|  |  |  | 	// at least one must be present.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Settings format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		// if true keep the unchanged ribbons (default: false)
 | 
					
						
							|  |  |  | 	// 		// NOTE: untouched ribbons are the ones loaded into DOM but
 | 
					
						
							|  |  |  | 	// 		//		not included in any of:
 | 
					
						
							|  |  |  | 	// 		//			- data.ribbon_order
 | 
					
						
							|  |  |  | 	// 		//			- data.ribbons
 | 
					
						
							|  |  |  | 	// 		//			- data.base
 | 
					
						
							|  |  |  | 	// 		keep_ribbons: bool,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		// if true do not update the base ribbon (default: false)
 | 
					
						
							|  |  |  | 	// 		keep_base: bool,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// 		// if true do not update the current image (default: false)
 | 
					
						
							|  |  |  | 	// 		keep_current: bool,
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//		// a shorthand setting all the above to true (default: false).
 | 
					
						
							|  |  |  | 	//		// NOTE: if this is set to true all other settings will be 
 | 
					
						
							|  |  |  | 	//		//		ignored...
 | 
					
						
							|  |  |  | 	// 		keep_all: bool,
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: this will not clear the ribbons object explicitly.
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	// NOTE: this will never remove the ribbons included in any of the
 | 
					
						
							|  |  |  | 	// 		data.base, data.ribbon_order or data.ribbons...
 | 
					
						
							|  |  |  | 	updateData: function(data, settings){ | 
					
						
							| 
									
										
										
										
											2014-11-08 02:48:04 +03:00
										 |  |  | 		settings = settings == null ? {} : settings | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		// load the data...
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-08 16:18:20 +03:00
										 |  |  | 		// update ribbons -- place images...
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 		if(data.ribbons != null){ | 
					
						
							| 
									
										
										
										
											2014-11-08 16:18:20 +03:00
										 |  |  | 			// see if we've got a custom ribbon updater...
 | 
					
						
							|  |  |  | 			var updateRibbon = settings.updateRibbon || this.updateRibbon.bind(this) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 			Object.keys(data.ribbons).forEach(function(gid){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				updateRibbon(data.ribbons[gid], gid) }) } | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// place ribbons...
 | 
					
						
							|  |  |  | 		if(data.ribbon_order != null){ | 
					
						
							|  |  |  | 			data.ribbon_order.forEach(function(gid, i){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				that.placeRibbon(gid, i) }) } | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 		if(!settings.keep_all){ | 
					
						
							|  |  |  | 			// set base ribbon...
 | 
					
						
							|  |  |  | 			if(!settings.keep_base && data.base != null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				this.setBaseRibbon(data.base) } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// set base ribbon...
 | 
					
						
							|  |  |  | 			if(!settings.keep_current && data.current != null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				this.focusImage(data.current) } | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// clear the ribbons that did not get updated...
 | 
					
						
							|  |  |  | 			if(!settings.keep_ribbons  | 
					
						
							|  |  |  | 					&& (data.ribbon_order != null || data.ribbons != null)){ | 
					
						
							| 
									
										
										
										
											2014-10-22 01:05:59 +04:00
										 |  |  | 				var ribbons = data.ribbon_order != null ? data.ribbon_order.slice()  | 
					
						
							|  |  |  | 					: data.ribbons != null ? Object.keys(data.ribbons) | 
					
						
							|  |  |  | 					: [] | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-15 18:48:45 +03:00
										 |  |  | 				that.viewer.find(RIBBON).each(function(){ | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 					var r = $(this) | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 					if(ribbons.indexOf(that.elemGID(r)) < 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 						r.remove() } }) } } | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-07-22 20:27:11 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-11-16 00:53:02 +03:00
										 |  |  | 	clearEmptyRibbons: function(){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		this.viewer.find(RIBBON) | 
					
						
							|  |  |  | 			.filter(function(_, e){ | 
					
						
							|  |  |  | 				return $(e).children().length == 0 }) | 
					
						
							|  |  |  | 			.remove() | 
					
						
							|  |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-11-16 00:53:02 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-22 20:27:11 +04:00
										 |  |  | 	// Clear elements...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Clear all elements:
 | 
					
						
							|  |  |  | 	// 	.clear()
 | 
					
						
							|  |  |  | 	// 	.clear('*')
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Clear an image or a ribbon by gid:
 | 
					
						
							|  |  |  | 	// 	.clear(gid)
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Clear a set of elements:
 | 
					
						
							|  |  |  | 	// 	.clear([gid, ...])
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2015-12-26 01:12:39 +03:00
										 |  |  | 	// Clear ribbon-set -- full rest:
 | 
					
						
							|  |  |  | 	// 	.clear('full')
 | 
					
						
							|  |  |  | 	// 		-> Ribbons
 | 
					
						
							|  |  |  | 	// 		NOTE: this will lose any state stored in the ribbon set, this
 | 
					
						
							|  |  |  | 	// 			includes vertical align and scaling...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-22 20:27:11 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: another way to remove a ribbon or an image just to use 
 | 
					
						
							|  |  |  | 	// 		.getRibbon(..).remove() and .getImage(...).remove() respectivly.
 | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 	clear: function(gids){ | 
					
						
							|  |  |  | 		// clear all...
 | 
					
						
							| 
									
										
										
										
											2016-11-22 23:41:38 +03:00
										 |  |  | 		if(gids == 'full' || gids == '*' || gids == null){ | 
					
						
							|  |  |  | 			this.getRibbonSet().remove() | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// clear one or more gids...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2014-10-22 01:23:56 +04:00
										 |  |  | 			gids = gids.constructor !== Array ? [gids] : gids | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 			var that = this | 
					
						
							|  |  |  | 			gids.forEach(function(g){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				that.viewer.find('[gid='+JSON.stringify(g)+']').detach() }) } | 
					
						
							|  |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-07-22 19:57:57 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:36:25 +04:00
										 |  |  | 	// Focus image...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Focus image by gid:
 | 
					
						
							|  |  |  | 	//	.focusImage(gid)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Focus next/prev image relative to current:
 | 
					
						
							|  |  |  | 	//	.focusImage('next')
 | 
					
						
							|  |  |  | 	//	.focusImage('prev')
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Focus image at offset from current:
 | 
					
						
							|  |  |  | 	//	.focusImage(offset)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: gid must be a .getImage(..) compatible object.
 | 
					
						
							|  |  |  | 	// NOTE: for keyword and offset to work an image must be focused.
 | 
					
						
							|  |  |  | 	// NOTE: overflowing offset will focus first/last image.
 | 
					
						
							| 
									
										
										
										
											2014-10-11 06:33:49 +04:00
										 |  |  | 	focusImage: function(target){ | 
					
						
							| 
									
										
										
										
											2014-07-24 16:36:25 +04:00
										 |  |  | 		var cur = this.viewer | 
					
						
							| 
									
										
										
										
											2019-10-10 16:54:50 +03:00
										 |  |  | 			.find('.current'+IMAGE) | 
					
						
							| 
									
										
										
										
											2014-10-11 06:33:49 +04:00
										 |  |  | 		var next = this.getImage(target) | 
					
						
							| 
									
										
										
										
											2014-07-24 16:36:25 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		cur.removeClass('current') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return next.addClass('current') }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Set base ribbon...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	// XXX is this really needed here???
 | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 	// XXX should this support keywords a-la .focusImage(..)???
 | 
					
						
							|  |  |  | 	setBaseRibbon: function(gid){ | 
					
						
							|  |  |  | 		this.viewer.find('.base.ribbon').removeClass('base') | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this.getRibbon(gid).addClass('base') }, | 
					
						
							| 
									
										
										
										
											2014-07-25 19:17:09 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Image manipulation...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 22:10:43 +04:00
										 |  |  | 	// Toggle image mark...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Toggle current image cls mark:
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(cls)
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(cls, 'toggle')
 | 
					
						
							|  |  |  | 	// 		-> mark
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Set current image cls mark on or off explicitly:
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(cls, 'on')
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(cls, 'off')
 | 
					
						
							|  |  |  | 	// 		-> mark
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// Toggle image cls mark:
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(image, cls)
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(image, cls, 'toggle')
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	// 		-> mark
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Set image cls mark on or off explicitly:
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(image, cls, 'on')
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(image, cls, 'off')
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	// 		-> mark
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	// Get image cls mark state:
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(cls, '?')
 | 
					
						
							|  |  |  | 	// 	.toggleImageMark(image, cls, '?')
 | 
					
						
							|  |  |  | 	// 		-> 'on'
 | 
					
						
							|  |  |  | 	// 		-> 'off'
 | 
					
						
							|  |  |  | 	// 		NOTE: this will only test the first image.
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: cls can be a list...
 | 
					
						
							|  |  |  | 	// NOTE: this can operate on multiple images...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	// NOTE: this will reuse existing marks...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 	toggleImageMark: function(image, cls, action){ | 
					
						
							|  |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2020-07-10 18:58:22 +03:00
										 |  |  | 		if(cls == null || ['toggle', 'on', 'off', '?'].includes(cls)){ | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 			action = cls | 
					
						
							|  |  |  | 			cls = image | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			image = null } | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		image = this.getImage(image)  | 
					
						
							| 
									
										
										
										
											2014-10-22 01:23:56 +04:00
										 |  |  | 		cls = cls.constructor !== Array ? [cls] : cls | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		action = action == null ? 'toggle' : action | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// no image is loaded...
 | 
					
						
							|  |  |  | 		if(image.length == 0){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return } | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		// get marked state...
 | 
					
						
							|  |  |  | 		if(action == '?'){ | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 			var gid = this.elemGID(image) | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 			var res = 0 | 
					
						
							|  |  |  | 			cls.forEach(function(cls){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				res += that.getImageMarks(gid, cls).length != 0 ? 1 : 0 }) | 
					
						
							|  |  |  | 			return res == cls.length ? 'on' : 'off' } | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 		// set the marks...
 | 
					
						
							|  |  |  | 		image.each(function(){ | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 			var image = $(this) | 
					
						
							| 
									
										
										
										
											2017-05-17 04:53:00 +03:00
										 |  |  | 			var gid = that.elemGID(image) | 
					
						
							| 
									
										
										
										
											2014-07-28 19:45:51 +04:00
										 |  |  | 			cls.forEach(function(cls){ | 
					
						
							|  |  |  | 				var mark = that.getImageMarks(gid, cls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// set the mark...
 | 
					
						
							|  |  |  | 				if(mark.length == 0  | 
					
						
							|  |  |  | 						&& (action == 'toggle'  | 
					
						
							|  |  |  | 							|| action == 'on')){ | 
					
						
							|  |  |  | 					that.createMark(cls, gid) | 
					
						
							|  |  |  | 						.insertAfter(image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// clear the mark...
 | 
					
						
							|  |  |  | 				} else if(action != 'on') { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					mark.remove() } }) }) | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return image }, | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	// Rotate an image...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	// Rotate image clockwise:
 | 
					
						
							|  |  |  | 	//	.rotateImage(target, 'cw')
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	// Rotate image counterclockwise:
 | 
					
						
							|  |  |  | 	//	.rotateImage(target, 'ccw')
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 	// Set explicit image rotation angle:
 | 
					
						
							|  |  |  | 	//	.rotateImage(target, 0|90|180|270)
 | 
					
						
							|  |  |  | 	//	.rotateImage(target, -90|-180|-270)
 | 
					
						
							|  |  |  | 	//		-> image
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: target must be .getImage(..) compatible.
 | 
					
						
							|  |  |  | 	// NOTE: this can be applied in bulk, e.g. 
 | 
					
						
							|  |  |  | 	// 		this.rotateImage($('.image'), 'cw') will rotate all the 
 | 
					
						
							|  |  |  | 	// 		loaded images clockwise.
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 	rotateImage: function(target, direction){ | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 		target = target == null || target.constructor !== Array ? [target] : target | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// validate direction...
 | 
					
						
							|  |  |  | 		if(images.calcRelativeRotation(direction) == null){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 			return target } | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 		$(target).each(function(i, e){ | 
					
						
							|  |  |  | 			var img = that.getImage(e) | 
					
						
							|  |  |  | 			var o = (direction == 'cw' || direction == 'ccw') | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 				? images.calcRelativeRotation(img.attr('orientation'), direction) | 
					
						
							|  |  |  | 				: direction*1 | 
					
						
							|  |  |  | 			if(o == 0){ | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 				img.removeAttr('orientation') | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				img.attr('orientation', o) } | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 			// account for proportions...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 06:36:02 +04:00
										 |  |  | 			that.correctImageProportionsForRotation(img) | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 			// XXX this is a bit of an overkill but it will update the 
 | 
					
						
							|  |  |  | 			// 		preview if needed...
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 			//that.updateImage(img)
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Flip an image...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:50:20 +03:00
										 |  |  | 	// Flip image relative to view:
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	// 	.flipImage(target, 'horizontal')
 | 
					
						
							|  |  |  | 	// 	.flipImage(target, 'vertical')
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:50:20 +03:00
										 |  |  | 	// 	.flipImage(target, 'horizontal', 'view')
 | 
					
						
							|  |  |  | 	// 	.flipImage(target, 'vertical', 'view')
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	// 		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:50:20 +03:00
										 |  |  | 	// Flip image relative to image:
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 	// 	.flipImage(target, 'horizontal', 'image')
 | 
					
						
							|  |  |  | 	// 	.flipImage(target, 'vertical', 'image')
 | 
					
						
							|  |  |  | 	// 		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 	// Set an explicit state:
 | 
					
						
							|  |  |  | 	// 	.flipImage(target, [ .. ])
 | 
					
						
							|  |  |  | 	// 		-> image
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							| 
									
										
										
										
											2014-07-24 16:46:32 +04:00
										 |  |  | 	// NOTE: target must be .getImage(..) compatible.
 | 
					
						
							|  |  |  | 	// NOTE: this can be applied in bulk, e.g. 
 | 
					
						
							|  |  |  | 	// 		this.flipImage($('.image'), 'vertical') will rotate all the 
 | 
					
						
							|  |  |  | 	// 		loaded images vertically.
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:50:20 +03:00
										 |  |  | 	// NOTE: this is relative to how the image is viewed and not to 
 | 
					
						
							|  |  |  | 	// 		it's original orientation by default...
 | 
					
						
							|  |  |  | 	// 		...this makes things consistent both visually and internally
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 	flipImage: function(target, direction, reference){ | 
					
						
							| 
									
										
										
										
											2014-11-25 03:34:46 +03:00
										 |  |  | 		reference = reference || 'view' | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 		target = target == null || target.constructor !== Array ? [target] : target | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-10-22 01:23:56 +04:00
										 |  |  | 		var set_state = direction.constructor === Array ? direction : null | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var that = this | 
					
						
							|  |  |  | 		$(target).each(function(i, e){ | 
					
						
							|  |  |  | 			var img = that.getImage(e) | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 			// update existing state...
 | 
					
						
							|  |  |  | 			if(set_state == null){ | 
					
						
							| 
									
										
										
										
											2014-11-25 03:34:46 +03:00
										 |  |  | 				var d = direction | 
					
						
							| 
									
										
										
										
											2020-07-10 18:58:22 +03:00
										 |  |  | 				if(reference == 'view' && [90, 270].includes(that.getImageRotation(img))){ | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					d = direction == 'vertical' ? 'horizontal' : 'vertical' } | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 				var state = img.attr('flipped') | 
					
						
							|  |  |  | 				state = (state == null ? '' : state) | 
					
						
							|  |  |  | 					.split(',') | 
					
						
							|  |  |  | 					.map(function(e){ return e.trim() }) | 
					
						
							|  |  |  | 					.filter(function(e){ return e != '' }) | 
					
						
							|  |  |  | 				// toggle the specific state...
 | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 				var i = state.indexOf(d) | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 				if(i >= 0){ | 
					
						
							|  |  |  | 					state.splice(i, 1) | 
					
						
							|  |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 					state.push(d) } | 
					
						
							| 
									
										
										
										
											2014-07-28 17:28:03 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// set an explicit state...
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				var state = set_state.slice() } | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// write the state...
 | 
					
						
							|  |  |  | 			if(state.length == 0){ | 
					
						
							|  |  |  | 				img.removeAttr('flipped') | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 				img.attr('flipped', state.join(', ')) } }) | 
					
						
							| 
									
										
										
										
											2014-11-06 02:42:16 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-14 20:06:58 +03:00
										 |  |  | 		return this }, | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// shorthands...
 | 
					
						
							|  |  |  | 	// XXX should these be here???
 | 
					
						
							| 
									
										
										
										
											2014-10-17 16:55:31 +04:00
										 |  |  | 	rotateCW: function(target){ return this.rotateImage(target, 'cw') }, | 
					
						
							|  |  |  | 	rotateCCW: function(target){ return this.rotateImage(target, 'ccw') }, | 
					
						
							| 
									
										
										
										
											2014-11-06 02:50:20 +03:00
										 |  |  | 	flipVertical: function(target, reference){ | 
					
						
							|  |  |  | 		return this.flipImage(target, 'vertical', reference) }, | 
					
						
							|  |  |  | 	flipHorizontal: function(target, reference){  | 
					
						
							|  |  |  | 		return this.flipImage(target, 'horizontal', reference) }, | 
					
						
							| 
									
										
										
										
											2014-07-24 16:05:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | }  | 
					
						
							| 
									
										
										
										
											2017-05-20 03:59:11 +03:00
										 |  |  | RibbonsPrototype.__proto__ = BaseRibbonsPrototype | 
					
						
							| 
									
										
										
										
											2014-11-18 20:20:35 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | var Ribbons =  | 
					
						
							|  |  |  | module.Ribbons =  | 
					
						
							| 
									
										
										
										
											2019-07-17 00:07:24 +03:00
										 |  |  | 	object.Constructor('Ribbons',  | 
					
						
							| 
									
										
										
										
											2018-12-26 05:21:25 +03:00
										 |  |  | 		RibbonsClassPrototype,  | 
					
						
							|  |  |  | 		RibbonsPrototype) | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-05-19 23:13:03 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-07-20 02:25:36 +04:00
										 |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2016-08-20 22:49:36 +03:00
										 |  |  | * vim:set ts=4 sw=4 :                               */ return module }) |