| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | * Viewer Generation III | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * Split the API into the following sections: | 
					
						
							|  |  |  | * 	- main control actions | 
					
						
							|  |  |  | * 		do main domain tasks like image and ribbon manipulation. | 
					
						
							|  |  |  | * 	- serialization and deserialization | 
					
						
							|  |  |  | * 		load and save data | 
					
						
							|  |  |  | * 	- UI | 
					
						
							|  |  |  | * 		basic align, animation and modes | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * TODO group all actions into an object, referencing the viewer... | 
					
						
							|  |  |  | * 	...this will make this reusable multiple times.			 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | * TODO wrap the actions into an object and make all queries relative to | 
					
						
							|  |  |  | * 		a single root viewer... | 
					
						
							|  |  |  | * 		...this will make the code reusable multiple times... | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // XXX STUB
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | // Data format...
 | 
					
						
							|  |  |  | var DATA = { | 
					
						
							|  |  |  | 	// the ribbon cache...
 | 
					
						
							|  |  |  | 	// in the simplest form this is a list of lists of GIDs
 | 
					
						
							|  |  |  | 	ribbons: [ | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		$(new Array(100)).map(function(i){return i}).toArray() | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	], | 
					
						
							|  |  |  | 	// flat ordered list of images in current context...
 | 
					
						
							|  |  |  | 	// in the simplest form this is a list of GIDs.
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	order: $(new Array(100)).map(function(i){return i}).toArray(), | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	// the images object, this is indexed by image GID and contains all 
 | 
					
						
							|  |  |  | 	// the needed data...
 | 
					
						
							|  |  |  | 	images: { | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | * Helpers | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 04:18:47 +04:00
										 |  |  | // XXX might need shift left/right indicators (later)...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function flashIndicator(direction){ | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | 	$({ | 
					
						
							|  |  |  | 		prev: '.up-indicator', | 
					
						
							|  |  |  | 		next: '.down-indicator', | 
					
						
							|  |  |  | 		start: '.start-indicator', | 
					
						
							|  |  |  | 		end: '.end-indicator', | 
					
						
							|  |  |  | 	}[direction]) | 
					
						
							| 
									
										
										
										
											2013-05-02 23:48:55 +04:00
										 |  |  | 		// NOTE: this needs to be visible in all cases and key press 
 | 
					
						
							|  |  |  | 		// 		rhythms... 
 | 
					
						
							|  |  |  | 		.show() | 
					
						
							|  |  |  | 		.delay(20) | 
					
						
							|  |  |  | 		.fadeOut(200) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | function getRibbon(image){ | 
					
						
							|  |  |  | 	image = image == null ? $('.current.image') : $(image) | 
					
						
							|  |  |  | 	return image.closest('.ribbon') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | // NOTE: elem is optional and if given can be an image or a ribbon...
 | 
					
						
							|  |  |  | function getRibbonIndex(elem){ | 
					
						
							|  |  |  | 	if(elem == null){ | 
					
						
							|  |  |  | 		var ribbon = getRibbon() | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		elem = $(elem) | 
					
						
							|  |  |  | 		if(elem.hasClass('image')){ | 
					
						
							|  |  |  | 			ribbon = getRibbon(elem) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ribbon = elem | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return $('.ribbon').index(ribbon) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | function getImageOrder(image){ | 
					
						
							|  |  |  | 	image = image == null ? $('.current.image') : $(image) | 
					
						
							|  |  |  | 	if(image.length == 0){ | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return JSON.parse(image.attr('order')) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | function getImageGID(image){ | 
					
						
							|  |  |  | 	image = image == null ? $('.current.image') : $(image) | 
					
						
							|  |  |  | 	if(image.length == 0){ | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return JSON.parse(image.attr('gid')) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Calculate relative position between two elements
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | // ...tried to make this as brain-dead-stupidly-simple as possible...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | //				...looks spectacular comparing to either gen2 or gen1 ;)
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function getRelativeVisualPosition(outer, inner){ | 
					
						
							|  |  |  | 	outer = $(outer).offset() | 
					
						
							|  |  |  | 	inner = $(inner).offset() | 
					
						
							|  |  |  | 	return { | 
					
						
							|  |  |  | 		top: inner.top - outer.top, | 
					
						
							|  |  |  | 		left: inner.left - outer.left | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 04:18:47 +04:00
										 |  |  | // Returns the image size (width) as viewed on screen...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | function getVisibleImageSize(){ | 
					
						
							|  |  |  | 	return $('.image').outerWidth() * getElementScale($('.ribbon-set')) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 04:18:47 +04:00
										 |  |  | // Return the number of images that can fit to viewer width...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | function getScreenWidthInImages(){ | 
					
						
							|  |  |  | 	return $('.viewer').innerWidth() / getVisibleImageSize() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | // NOTE: this will return an empty jquery object if no image is before 
 | 
					
						
							|  |  |  | // 		the target...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 23:48:55 +04:00
										 |  |  | // NOTE: this might return an empty target if the ribbon is empty...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // NOTE: this only "sees" the loaded images, for a full check use 
 | 
					
						
							|  |  |  | // 		getGIDBefore(...) that will check the full data...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | function getImageBefore(image, ribbon, mode){ | 
					
						
							|  |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-02 23:48:55 +04:00
										 |  |  | 	image = image == null ? $('.current.image') : $(image) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	if(ribbon == null){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 		ribbon = getRibbon(image) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	var images = $(ribbon).find('.image').filter(mode) | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 	// XXX need to process/format this correctly...
 | 
					
						
							|  |  |  | 	var order = JSON.parse(image.attr('order')) | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	var prev = [] | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	images.each(function(){ | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		if(order < JSON.parse($(this).attr('order'))){ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		prev = this | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return $(prev) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // A predicate returning:
 | 
					
						
							|  |  |  | // 	- 0 if a is equal at position i in lst or is between i and i+1
 | 
					
						
							|  |  |  | // 	- -1 if a is "below" position i
 | 
					
						
							|  |  |  | // 	- +1 if a is "above" position i
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this is here mostly to make debuging easy...
 | 
					
						
							|  |  |  | function isBetween(a, i, lst){ | 
					
						
							|  |  |  | 	var b = lst[i] | 
					
						
							|  |  |  | 	var c = lst[i+1] | 
					
						
							|  |  |  | 	// hit...
 | 
					
						
							|  |  |  | 	if(a == b || (a > b && a < c)){ | 
					
						
							|  |  |  | 		return 0 | 
					
						
							|  |  |  | 	// before...
 | 
					
						
							|  |  |  | 	} else if(a < b){ | 
					
						
							|  |  |  | 		return -1 | 
					
						
							|  |  |  | 	// later...
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Basic binary search implementation...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this will return the object by default, to return position set
 | 
					
						
							|  |  |  | // 		return_position to true.
 | 
					
						
							|  |  |  | // NOTE: by default this will use isBetween as a predicate.
 | 
					
						
							|  |  |  | // NOTE: this still depends on .indexOf(...), to disable set
 | 
					
						
							|  |  |  | // 		disable_direct_indexing to true
 | 
					
						
							|  |  |  | function binSearch(target, lst, check, return_position, disable_direct_indexing){ | 
					
						
							|  |  |  | 	// XXX is this the correct default?
 | 
					
						
							|  |  |  | 	check = check == null ? isBetween : check | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 	// special case: target in the list directly...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	if(disable_direct_indexing  | 
					
						
							|  |  |  | 			&& check(target, lst.indexOf(target), lst) == 0){ | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 		return target | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// special case: tail...
 | 
					
						
							|  |  |  | 	if(check(target, lst.length-1, lst) >= 0){ | 
					
						
							|  |  |  | 		return lst[lst.length-1] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// special case: head...
 | 
					
						
							|  |  |  | 	if(check(target, 0, lst) == 0){ | 
					
						
							|  |  |  | 		return lst[0] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var l = Math.ceil(lst.length/2) | 
					
						
							|  |  |  | 	var i = l | 
					
						
							|  |  |  | 	var res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(l > 0){ | 
					
						
							|  |  |  | 		l = Math.ceil(l/2) | 
					
						
							|  |  |  | 		res = check(target, i, lst) | 
					
						
							|  |  |  | 		// right branch...
 | 
					
						
							|  |  |  | 		if(res > 0){ | 
					
						
							|  |  |  | 			i += l | 
					
						
							|  |  |  | 		// left branch...
 | 
					
						
							|  |  |  | 		} else if(res < 0){ | 
					
						
							|  |  |  | 			i -= l | 
					
						
							|  |  |  | 		// hit...
 | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 			return return_position ? i : lst[i] | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// no hit...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	return return_position ? -1 : null | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // Same as getImageBefore, but uses gids and searches in DATA...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | function getGIDBefore(gid, ribbon){ | 
					
						
							|  |  |  | 	ribbon = DATA.ribbons[ribbon] | 
					
						
							|  |  |  | 	var order = DATA.order | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 	var target = order.indexOf(gid) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return binSearch(target, ribbon, function (a, i, lst){ | 
					
						
							|  |  |  | 		var b = order.indexOf(lst[i]) | 
					
						
							|  |  |  | 		var c = order.indexOf(lst[i+1]) | 
					
						
							|  |  |  | 		// hit...
 | 
					
						
							|  |  |  | 		if(a == b || (a > b && a < c)){ | 
					
						
							|  |  |  | 			return 0 | 
					
						
							|  |  |  | 		// before...
 | 
					
						
							|  |  |  | 		} else if(a < b){ | 
					
						
							|  |  |  | 			return -1 | 
					
						
							|  |  |  | 		// later...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 			return 1 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | function shiftTo(image, ribbon){ | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 	var target = getImageBefore(image, ribbon, NAV_ALL) | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	var cur_ribbon = getRibbon(image) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// insert before the first image if nothing is before the target...
 | 
					
						
							|  |  |  | 	if(target.length == 0){ | 
					
						
							|  |  |  | 		image.prependTo($(ribbon)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		image.insertAfter(target) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	$('.viewer').trigger('shiftedImage', [image, cur_ribbon, ribbon]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	// if removing last image out of a ribbon, remove the ribbon....
 | 
					
						
							|  |  |  | 	if(cur_ribbon.find('.image').length == 0){ | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | 		// XXX check if the ribbon outside the loaded area is empty...
 | 
					
						
							|  |  |  | 		// 		...do we need this check? it might be interresting to
 | 
					
						
							|  |  |  | 		// 		"collapse" disjoint, empty areas...
 | 
					
						
							|  |  |  | 		// 		......if so, will also need to do this in DATA...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		removeRibbon(cur_ribbon) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return image | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function shiftImage(direction, image, force_create_ribbon){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		// XXX need to make this context specific...
 | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		image = $(image) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	var old_ribbon = getRibbon(image) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	var ribbon = old_ribbon[direction]('.ribbon') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// need to create a new ribbon...
 | 
					
						
							|  |  |  | 	if(ribbon.length == 0 || force_create_ribbon == true){ | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		var index = getRibbonIndex(old_ribbon) | 
					
						
							|  |  |  | 		index = direction == 'after' ? index + 1 : index | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		ribbon = createRibbon(index) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 		shiftTo(image, ribbon) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		shiftTo(image, ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return image | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * Constructors | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // NOTE: unless force_create_new is set to true this will clone an 
 | 
					
						
							|  |  |  | // 		image if one is available...
 | 
					
						
							|  |  |  | // NOTE: this will not attach the created images.
 | 
					
						
							|  |  |  | function createImage(n, force_create_new){ | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 	if(n == null){ | 
					
						
							|  |  |  | 		if(window._n == null){ | 
					
						
							|  |  |  | 			window._n = 0 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		n = _n | 
					
						
							|  |  |  | 		_n += 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var img = $('.image') | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	if(!force_create_new && img.length > 0){ | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 		return img.first().clone() | 
					
						
							|  |  |  | 					.attr({ | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 						'order': JSON.stringify(n), | 
					
						
							|  |  |  | 						'gid': JSON.stringify(n), | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 						// need to strip extra classes...
 | 
					
						
							|  |  |  | 						'class': 'image' | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		return $('<div order="'+n+'" gid="'+n+'" class="image"/>') | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Create a set of new images, reusing a list of existing elements if 
 | 
					
						
							|  |  |  | // given.
 | 
					
						
							|  |  |  | // NOTE: this will not attach the created images.
 | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | function createImages(need, have){ | 
					
						
							|  |  |  | 	have = have == null ? [] : have | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// we have enough elements in the cache...
 | 
					
						
							|  |  |  | 	if(have.length >= need){ | 
					
						
							|  |  |  | 		return $(have.splice(0, need)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// need to create additional elements...
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return $(have.toArray().concat(new Array(need - have.length))) | 
					
						
							|  |  |  | 			.map(function(i, elem){ | 
					
						
							|  |  |  | 				if(elem != null){ | 
					
						
							|  |  |  | 					return elem | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				return createImage()[0] | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // NOTE: if index is given, this will also attach the created ribbon to 
 | 
					
						
							|  |  |  | // 		that position...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | function createRibbon(index){ | 
					
						
							|  |  |  | 	var ribbon = $('<div class="ribbon"/>') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(index == null){ | 
					
						
							|  |  |  | 		return ribbon | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var ribbons = $('.ribbon') | 
					
						
							|  |  |  | 	if(index >= ribbons.length){ | 
					
						
							|  |  |  | 		ribbons.last().after(ribbon) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ribbons.eq(index).before(ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	$('.viewer').trigger('createdRibbon', [ribbon]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return ribbon | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | // NOTE: this will pass the index where the ribbon was to the event,
 | 
					
						
							|  |  |  | // 		rather than an actual ribbon...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | // XXX check if ribbon is empty...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | function removeRibbon(ribbon){ | 
					
						
							|  |  |  | 	// ribbon can be an index...
 | 
					
						
							|  |  |  | 	if(typeof(ribbon) == typeof(1)){ | 
					
						
							|  |  |  | 		ribbon = $('.ribbon').eq(ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	$('.viewer').trigger('removedRibbon', [getRibbonIndex(ribbon)]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return $(ribbon).remove() | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * Infinite ribbon machinery | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: negative left or right will contract the ribbon...
 | 
					
						
							|  |  |  | // XXX check what goes on if left/right are far more than length...
 | 
					
						
							|  |  |  | function extendRibbon(left, right, ribbon){ | 
					
						
							|  |  |  | 	ribbon = ribbon == null ?  | 
					
						
							|  |  |  | 				getRibbon() | 
					
						
							|  |  |  | 				: $(ribbon) | 
					
						
							|  |  |  | 	left = left == null ? 0 : left | 
					
						
							|  |  |  | 	right = right == null ? 0 : right | 
					
						
							|  |  |  | 	var images = ribbon.children('.image') | 
					
						
							|  |  |  | 	var removed = [] | 
					
						
							|  |  |  | 	var res = { | 
					
						
							|  |  |  | 		left: $([]), | 
					
						
							|  |  |  | 		right: $([]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// truncate...
 | 
					
						
							|  |  |  | 	// NOTE: we save the detached elements to reuse them on extending,
 | 
					
						
							|  |  |  | 	//		if needed...
 | 
					
						
							|  |  |  | 	if(left < 0){ | 
					
						
							|  |  |  | 		removed = $(images.splice(0, -left)).detach() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if(right < 0){ | 
					
						
							|  |  |  | 		var l = images.length | 
					
						
							|  |  |  | 		removed = $(images.splice(l+right, l)).detach() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// extend...
 | 
					
						
							|  |  |  | 	if (left > 0){ | 
					
						
							|  |  |  | 		res.left = createImages(left, removed).prependTo(ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if (right > 0){ | 
					
						
							|  |  |  | 		res.right = createImages(right, removed).appendTo(ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// compensate for the truncation...
 | 
					
						
							|  |  |  | 	// XXX do we need to split this into a separate function?
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	// 		...the rest of the function is pretty generic...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | 	if(left != 0){ | 
					
						
							|  |  |  | 		var l = parseFloat(ribbon.css('left')) | 
					
						
							|  |  |  | 		l = isNaN(l) ? 0 : l | 
					
						
							|  |  |  | 		ribbon.css({ | 
					
						
							|  |  |  | 			left: l + (-left * parseFloat(images.outerWidth())) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Roll the ribbon n positions to the left.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: if n is negative the ribbon will be rolled right.
 | 
					
						
							|  |  |  | // NOTE: rollRibbon(N, R) is equivalent to extendRibbon(-N, N, R)
 | 
					
						
							|  |  |  | // NOTE: this will return a single list of relocated elements...
 | 
					
						
							|  |  |  | function rollRibbon(n, ribbon){ | 
					
						
							|  |  |  | 	var res = extendRibbon(-n, n, ribbon) | 
					
						
							|  |  |  | 	return n > 0 ? res.right : res.left | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | * Loaders | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // NOTE: count can be either negative or positive, this will indicate 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | // 		load direction...
 | 
					
						
							|  |  |  | // NOTE: this will not include the 'from' GID in the resulting list...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | // NOTE: this can calculate the ribbon number if an image can be only 
 | 
					
						
							|  |  |  | // 		in one ribbon...
 | 
					
						
							|  |  |  | // NOTE: if an image can be in more than one ribbon, one MUST suply the
 | 
					
						
							|  |  |  | // 		correct ribbon number...
 | 
					
						
							|  |  |  | // XXX do we need more checking???
 | 
					
						
							|  |  |  | function getImageGIDs(from, count, ribbon){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	if(count == 0){ | 
					
						
							|  |  |  | 		return [] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	// ribbon default value...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	if(ribbon == null){ | 
					
						
							|  |  |  | 		$(DATA.ribbons).each(function(i, e){  | 
					
						
							|  |  |  | 			if(e.indexOf(from) >= 0){  | 
					
						
							|  |  |  | 				ribbon = i | 
					
						
							|  |  |  | 				return false  | 
					
						
							|  |  |  | 			}  | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	// XXX check if this is empty...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	ribbon = DATA.ribbons[ribbon] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(count > 0){ | 
					
						
							|  |  |  | 		var start = ribbon.indexOf(from) + 1 | 
					
						
							|  |  |  | 		return ribbon.slice(start, start + count) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var end = ribbon.indexOf(from) | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 		return ribbon.slice((Math.abs(count) >= end ? 0 : end + count), end) | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | function updateImage(image, gid, size){ | 
					
						
							|  |  |  | 	image = $(image) | 
					
						
							|  |  |  | 	if(gid == null){ | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 		gid = JSON.parse(image.attr('gid')) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		image.attr('gid', JSON.stringify(gid)) | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	size = size == null ? getVisibleImageSize() : size | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	image.attr({ | 
					
						
							|  |  |  | 		//order: JSON.stringify(DATA.order.indexOf(gid)),
 | 
					
						
							|  |  |  | 		order: JSON.stringify(gid)  | 
					
						
							|  |  |  | 		// XXX update attrs 
 | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX STUB
 | 
					
						
							|  |  |  | 	image.text(gid) | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | 	// XXX slect best preview by size...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	// XXX
 | 
					
						
							|  |  |  | 	// XXX update classes...
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	// XXX
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // Load count images around a given image/gid into the given ribbon.
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this will reload the current image elements...
 | 
					
						
							|  |  |  | // NOTE: this is similar to extendRibbon(...) but different in interface...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // XXX still buggy, needs more testing...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | function loadImages(ref_gid, count, ribbon){ | 
					
						
							|  |  |  | 	ribbon = $(ribbon) | 
					
						
							|  |  |  | 	var images = ribbon.find('.image') | 
					
						
							|  |  |  | 	var ribbon_i = getRibbonIndex(ribbon) | 
					
						
							|  |  |  | 	var gid = getGIDBefore(ref_gid, ribbon_i) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// start/end points...
 | 
					
						
							|  |  |  | 	var from_i = DATA.ribbons[ribbon_i].indexOf(gid) - Math.floor(count/2) | 
					
						
							|  |  |  | 	from_i = from_i < 0 ? 0 : from_i | 
					
						
							|  |  |  | 	var from_gid = DATA.ribbons[ribbon_i][from_i] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX make this load only what is needed instead of reloading everything...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var size = getVisibleImageSize() | 
					
						
							|  |  |  | 	var gids = getImageGIDs(from_gid, count) | 
					
						
							|  |  |  | 	// XXX is this the only special case???
 | 
					
						
							|  |  |  | 	if(from_gid == from_gid){ | 
					
						
							|  |  |  | 		gids.splice(0, 0, ref_gid) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return createImages(gids.length, images.detach()) | 
					
						
							|  |  |  | 		.each(function(i, e){ | 
					
						
							|  |  |  | 			updateImage(e, gids[i], size) | 
					
						
							|  |  |  | 		}).appendTo(ribbon) | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | // NOTE: this is signature-compatible with rollRibbon...
 | 
					
						
							|  |  |  | // NOTE: this will load data ONLY if it is available, otherwise this 
 | 
					
						
							|  |  |  | // 		will have no effect...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 05:57:38 +04:00
										 |  |  | // NOTE: this can roll past the currently loaded images (n > images.length)
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | function rollImages(n, ribbon){ | 
					
						
							|  |  |  | 	if(n == 0){ | 
					
						
							|  |  |  | 		return $([]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ribbon = ribbon == null ? getRibbon() : $(ribbon) | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	var images = ribbon.find('.image') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 	var from = n > 0 ? JSON.parse(ribbon.find('.image').last().attr('gid')) | 
					
						
							|  |  |  | 					: JSON.parse(ribbon.find('.image').first().attr('gid')) | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	var gids = getImageGIDs(from, n) | 
					
						
							|  |  |  | 	if(gids.length == 0){ | 
					
						
							|  |  |  | 		return $([]) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	// truncate the results to the length of images...
 | 
					
						
							|  |  |  | 	if(n > images.length){ | 
					
						
							|  |  |  | 		gids.reverse().splice(images.length) | 
					
						
							|  |  |  | 		gids.reverse() | 
					
						
							|  |  |  | 	} else if(Math.abs(n) > images.length){ | 
					
						
							|  |  |  | 		gids.splice(images.length) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(n < images.length){ | 
					
						
							|  |  |  | 		images = rollRibbon(gids.length * (n > 0 ? 1 : -1), ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	var size = getVisibleImageSize() | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	images.each(function(i, e){ | 
					
						
							|  |  |  | 		updateImage($(e), gids[i], size) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return images | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 22:32:20 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | /********************************************************************** | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | * Modes | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 00:39:29 +04:00
										 |  |  | // XXX shifting images and unmarking in this mode do not work correctly...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | var toggleMarkedOnlyView = createCSSClassToggler('.viewer', 'marked-only', | 
					
						
							|  |  |  | 	function(){ | 
					
						
							|  |  |  | 		var cur = $('.current.image') | 
					
						
							|  |  |  | 		// current is marked...
 | 
					
						
							|  |  |  | 		if(cur.hasClass('marked')){ | 
					
						
							|  |  |  | 			centerImage(null, 'css') | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		}  | 
					
						
							|  |  |  | 		// there is a marked image in this ribbon...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 		var target = getImageBefore(cur, null) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 		if(target.length > 0){ | 
					
						
							|  |  |  | 			centerImage(focusImage(target), 'css') | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// get marked image from other ribbons...
 | 
					
						
							|  |  |  | 		prevRibbon() | 
					
						
							|  |  |  | 		if($('.current.image').hasClass('marked')){ | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nextRibbon() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX add ability to take all marked images and open them in a separate view...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX should we use the createCSSClassToggler for this?
 | 
					
						
							|  |  |  | // XXX revise: does extra stuff...
 | 
					
						
							|  |  |  | function toggleImageProportions(mode){ | 
					
						
							|  |  |  | 	var image = $('.image') | 
					
						
							|  |  |  | 	var h = image.outerHeight(true) | 
					
						
							|  |  |  | 	var w = image.outerWidth(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(mode == '?'){ | 
					
						
							|  |  |  | 		return h != w ? 'viewer' : 'square' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// square...
 | 
					
						
							|  |  |  | 	} else if(h != w || mode == 'square'){ | 
					
						
							|  |  |  | 		var size = Math.min(w, h) | 
					
						
							|  |  |  | 		image.css({ | 
					
						
							|  |  |  | 			width: size, | 
					
						
							|  |  |  | 			height: size | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		centerImage(null, 'css') | 
					
						
							|  |  |  | 		return 'square' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// viewer size...
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var viewer = $('.viewer') | 
					
						
							|  |  |  | 		var W = viewer.innerWidth() | 
					
						
							|  |  |  | 		var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(W > H){ | 
					
						
							|  |  |  | 			image.css('width', W * h/H) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			image.css('height', H * w/W) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		centerImage(null, 'css') | 
					
						
							|  |  |  | 		return 'viewer' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * Layout | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | */ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | function focusImage(image){ | 
					
						
							|  |  |  | 	image.closest('.viewer').find('.current.image').removeClass('current') | 
					
						
							|  |  |  | 	return image.addClass('current') | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | /* | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // Generic align
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | // XXX need to split this into two:
 | 
					
						
							|  |  |  | // 		- offset calculator
 | 
					
						
							|  |  |  | // 		- actual move
 | 
					
						
							|  |  |  | // XXX this does not account for scale at this point...
 | 
					
						
							|  |  |  | // XXX for this to be generic, need a uniform way to get any element scale
 | 
					
						
							|  |  |  | // 		regardless of weather it was scaled directly or is within one or 
 | 
					
						
							|  |  |  | // 		several scaled elements...
 | 
					
						
							|  |  |  | function alignVia(container, elem, via, valign, halign, mode){ | 
					
						
							|  |  |  | 	container = $(container) | 
					
						
							|  |  |  | 	elem = $(elem) | 
					
						
							|  |  |  | 	via = $(via) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	valign = valign == null ? 'center' : valign | 
					
						
							|  |  |  | 	halign = halign == null ? 'center' : halign | 
					
						
							|  |  |  | 	mode = mode == null ? 'animate' : mode | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var pos = getRelativeVisualPosition(container, elem) | 
					
						
							|  |  |  | 	var dt = pos.top | 
					
						
							|  |  |  | 	var dl = pos.left | 
					
						
							|  |  |  | 	var target = {} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var t = parseFloat(via.css('top')) | 
					
						
							|  |  |  | 	t = !isNaN(t) ? t : 0 | 
					
						
							|  |  |  | 	var l = parseFloat(via.css('left')) | 
					
						
							|  |  |  | 	l = !isNaN(l) ? l : 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(valign == 'center'){ | 
					
						
							|  |  |  | 		var H = container.innerHeight() | 
					
						
							|  |  |  | 		var h = elem.outerHeight() | 
					
						
							|  |  |  | 		target.top = t - dt + (H - h)/2, | 
					
						
							|  |  |  | 	} else if(valign == 'top'){ | 
					
						
							|  |  |  | 		target.top = t - dt | 
					
						
							|  |  |  | 	} else if(valign == 'bottom'){ | 
					
						
							|  |  |  | 		var h = elem.outerHeight() | 
					
						
							|  |  |  | 		target.top = t - dt - h | 
					
						
							|  |  |  | 	}  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(halign == 'center'){ | 
					
						
							|  |  |  | 		var W = container.innerWidth() | 
					
						
							|  |  |  | 		var w = elem.outerWidth() | 
					
						
							|  |  |  | 		target.left = l - dl + (W - w)/2 | 
					
						
							|  |  |  | 	} else if(halign == 'left'){ | 
					
						
							|  |  |  | 		target.left = l - dl | 
					
						
							|  |  |  | 	} else if(halign == 'right'){ | 
					
						
							|  |  |  | 		var w = elem.outerWidth() | 
					
						
							|  |  |  | 		target.left = l - dl - w | 
					
						
							|  |  |  | 	}  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// do the actual work...
 | 
					
						
							|  |  |  | 	if(mode == 'animate'){ | 
					
						
							|  |  |  | 		via.stop().animate(target, 100, 'linear') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		via.css(target) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX ???
 | 
					
						
							|  |  |  | 	return | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // XXX make this more configurable (centering, ...)...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function centerImage(image, mode){ | 
					
						
							|  |  |  | 	if(mode == null){ | 
					
						
							|  |  |  | 		//mode = 'css'
 | 
					
						
							|  |  |  | 		mode = 'animate' | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	$('.viewer').trigger('preCenteringRibbon', [getRibbon(image), image]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	if(image == null || image.length == 0){ | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var viewer = $('.viewer') | 
					
						
							|  |  |  | 	// XXX should these be "inner"???
 | 
					
						
							|  |  |  | 	var W = viewer.innerWidth() | 
					
						
							|  |  |  | 	var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ribbons = $('.ribbon-set') | 
					
						
							|  |  |  | 	var scale = getElementScale(ribbons) | 
					
						
							|  |  |  | 	// NOTE: these are scalable, this needs to get normalized...
 | 
					
						
							|  |  |  | 	var w = image.outerWidth()*scale | 
					
						
							|  |  |  | 	var h = image.outerHeight()*scale | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var pos = getRelativeVisualPosition(viewer, image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// zero out top/left if set to anything other than a specific number...
 | 
					
						
							|  |  |  | 	var t = parseFloat(ribbons.css('top')) | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 	t = !isNaN(t) ? t : 0 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	var l = parseFloat(ribbons.css('left')) | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 	l = !isNaN(l) ? l : 0 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var res = { | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 		'top': t - pos.top + (H - h)/2, | 
					
						
							|  |  |  | 		'left': l - pos.left + (W - w)/2 | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	// do the actual work...
 | 
					
						
							|  |  |  | 	if(mode == 'animate'){ | 
					
						
							| 
									
										
										
										
											2013-05-03 02:11:24 +04:00
										 |  |  | 		ribbons.stop().animate(res, 100, 'linear') | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-05-03 02:11:24 +04:00
										 |  |  | 		ribbons.css(res) | 
					
						
							| 
									
										
										
										
											2013-05-02 23:22:43 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-03 02:11:24 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	$('.viewer').trigger('centeringRibbon', [getRibbon(image), image]) | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:11:24 +04:00
										 |  |  | 	return image | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Center a ribbon...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This behaves differently for different ribbons:
 | 
					
						
							|  |  |  | // 	- ribbon containing the target (given) image
 | 
					
						
							|  |  |  | // 		center relative to the .viewer via .ribbon-set
 | 
					
						
							|  |  |  | // 		calls centerImage(...) directly
 | 
					
						
							|  |  |  | // 		both top and left are used...
 | 
					
						
							|  |  |  | // 	- any other ribbon
 | 
					
						
							|  |  |  | // 		center relative to target (given) via the ribbon left
 | 
					
						
							|  |  |  | // 		only left coordinate is changed...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: image defaults to $('.current.image').
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX might be good to merge this and centerImage...
 | 
					
						
							|  |  |  | // 		...or make a generic centering function...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | // XXX this does not work in marked-only mode...
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // XXX this needs the image to exist... should be GID compatible... (???)
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | function centerRibbon(ribbon, image, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 	if(mode == null){ | 
					
						
							|  |  |  | 		//mode = 'css'
 | 
					
						
							|  |  |  | 		mode = 'animate' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	ribbon = $(ribbon) | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 	image = image == null ? $('.current.image') : $(image) | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// if centering current ribbon, just center the image...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 	if(ribbon.find('.image').index(image) >= 0){ | 
					
						
							|  |  |  | 		centerImage(image, mode) | 
					
						
							|  |  |  | 		// XXX should this return a ribbon or the target image???
 | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 		return ribbon | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 21:16:30 +04:00
										 |  |  | 	// XXX is this the correct spot for this?
 | 
					
						
							|  |  |  | 	$('.viewer').trigger('preCenteringRibbon', [ribbon, image]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 	var scale = getElementScale($('.ribbon-set')) | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | 	var target = getImageBefore(image, ribbon, null) | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if(target.length > 0){ | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 		var dl = getRelativeVisualPosition(target, image).left/scale | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 		var l = parseFloat(ribbon.css('left')) | 
					
						
							|  |  |  | 		l = !isNaN(l) ? l : 0 | 
					
						
							|  |  |  | 		l = {left: l + dl - ($('.image').outerWidth()/2)} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 		target = ribbon.find('.image').filter(NAV_DEFAULT).first()  | 
					
						
							|  |  |  | 		var dl = getRelativeVisualPosition(target, image).left/scale | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 		var l = parseFloat(ribbon.css('left')) | 
					
						
							|  |  |  | 		l = !isNaN(l) ? l : 0 | 
					
						
							|  |  |  | 		l = {left: l + dl + ($('.image').outerWidth()/2)} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(mode == 'animate'){ | 
					
						
							|  |  |  | 		ribbon.stop().animate(l, 100, 'linear') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ribbons.css(res) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	$('.viewer').trigger('centeringRibbon', [ribbon, image]) | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 	// XXX should this return a ribbon or the target image???
 | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | 	return ribbon | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | // a shorthand...
 | 
					
						
							|  |  |  | function centerRibbons(mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 05:47:26 +04:00
										 |  |  | 	return $('.ribbon') | 
					
						
							|  |  |  | 		.filter(':visible') | 
					
						
							| 
									
										
										
										
											2013-05-03 15:58:22 +04:00
										 |  |  | 		.each(function(){ centerRibbon($(this), null, mode) }) | 
					
						
							| 
									
										
										
										
											2013-05-03 05:38:40 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * Event handlers... | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: this is on purpose done relative...
 | 
					
						
							|  |  |  | function clickHandler(evt){ | 
					
						
							|  |  |  | 	var img = $(evt.target).closest('.image') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	centerImage(focusImage(img)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	centerRibbons() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * User actions | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: NAV_ALL might not be practical...
 | 
					
						
							|  |  |  | var NAV_ALL = '*' | 
					
						
							|  |  |  | var NAV_VISIBLE = ':visible' | 
					
						
							|  |  |  | var NAV_MARKED = '.marked:visible' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var NAV_DEFAULT = NAV_VISIBLE | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // basic navigation actions...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | function nextImage(n, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | 	n = n == null ? 1 : n | 
					
						
							| 
									
										
										
										
											2013-05-03 03:43:43 +04:00
										 |  |  | 	var target = $('.current.image').nextAll('.image' + mode) | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | 	if(target.length < n){ | 
					
						
							|  |  |  | 		target = target.last() | 
					
						
							|  |  |  | 		flashIndicator('end') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		target = target.eq(n-1) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-03 03:43:43 +04:00
										 |  |  | 	return centerImage(focusImage(target)) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | function prevImage(n, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | 	n = n == null ? 1 : n | 
					
						
							| 
									
										
										
										
											2013-05-03 03:43:43 +04:00
										 |  |  | 	var target = $('.current.image').prevAll('.image' + mode) | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | 	if(target.length < n){ | 
					
						
							|  |  |  | 		target = target.last() | 
					
						
							|  |  |  | 		flashIndicator('start') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		target = target.eq(n-1) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-03 03:43:43 +04:00
										 |  |  | 	return centerImage(focusImage(target)) | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:27:54 +04:00
										 |  |  | function nextScreenImages(mode){ | 
					
						
							|  |  |  | 	return nextImage(Math.round(getScreenWidthInImages()), mode) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function prevScreenImages(mode){ | 
					
						
							|  |  |  | 	return prevImage(Math.round(getScreenWidthInImages()), mode) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | // XXX revise...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function firstImage(mode){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	$('.viewer').trigger('requestedFirstImage', [getRibbon()]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | 	if($('.current.image').prevAll('.image' + mode).length == 0){ | 
					
						
							|  |  |  | 		flashIndicator('start') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 			getRibbon().find('.image').filter(mode).first())) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | // XXX revise...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function lastImage(mode){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	$('.viewer').trigger('requestedLastImage', [getRibbon()]) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-03 19:24:06 +04:00
										 |  |  | 	if($('.current.image').nextAll('.image' + mode).length == 0){ | 
					
						
							|  |  |  | 		flashIndicator('end') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 			getRibbon().find('.image').filter(mode).last())) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: if moving is 'next' these will chose the image after the current's order.
 | 
					
						
							|  |  |  | // NOTE: if an image with the same order is found, moving argument has no effect.
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | // XXX these sometimes behave wrong at the start of the ribbon depending
 | 
					
						
							|  |  |  | // 		on direction...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function prevRibbon(moving, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	var cur = $('.current.image') | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | 	var target = getImageBefore(cur,  | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 			getRibbon(cur).prevAll('.ribbon:visible').first()) | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	if(target.length == 0){ | 
					
						
							|  |  |  | 		// XXX too complex???
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 		target = getRibbon(cur) | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | 					.prevAll('.ribbon:visible').first() | 
					
						
							|  |  |  | 						.find('.image' + mode).first() | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	} else if(moving == 'next' && cur.attr('order') != target.attr('order')){ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 		var next = target.nextAll('.image' + mode).first() | 
					
						
							|  |  |  | 		target = next.length > 0 ? next : target | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return centerImage(focusImage(target)) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function nextRibbon(moving, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	var cur = $('.current.image') | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | 	var target = getImageBefore(cur,  | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 			getRibbon(cur).nextAll('.ribbon:visible').first()) | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	if(target.length == 0){ | 
					
						
							|  |  |  | 		// XXX too complex???
 | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 		target = getRibbon(cur) | 
					
						
							| 
									
										
										
										
											2013-05-03 19:01:00 +04:00
										 |  |  | 					.nextAll('.ribbon:visible').first() | 
					
						
							|  |  |  | 						.find('.image' + mode).first() | 
					
						
							| 
									
										
										
										
											2013-05-06 02:18:36 +04:00
										 |  |  | 	} else if(moving == 'next' && cur.attr('order') != target.attr('order')){ | 
					
						
							|  |  |  | 			var next = target.nextAll('.image' + mode).first() | 
					
						
							|  |  |  | 			target = next.length > 0 ? next : target | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return centerImage(focusImage(target)) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | function fitNImages(n){ | 
					
						
							|  |  |  | 	var image = $('.current.image') | 
					
						
							|  |  |  | 	var size = image.outerHeight(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var viewer = $('.viewer') | 
					
						
							|  |  |  | 	var W = viewer.innerWidth() | 
					
						
							|  |  |  | 	var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var scale = Math.min(W / (size * n), H / size) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX if animating, the next two likes must be animated together...
 | 
					
						
							|  |  |  | 	setElementScale($('.ribbon-set'), scale) | 
					
						
							|  |  |  | 	centerImage(image, 'css') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | var MAX_SCREEN_IMAGES = 10 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX use the actual scale...
 | 
					
						
							|  |  |  | function zoomIn(){ | 
					
						
							|  |  |  | 	var w = getScreenWidthInImages() | 
					
						
							|  |  |  | 	if(w > 1){ | 
					
						
							|  |  |  | 		fitNImages(w-1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function zoomOut(){ | 
					
						
							|  |  |  | 	var w = getScreenWidthInImages() | 
					
						
							|  |  |  | 	if(w <= MAX_SCREEN_IMAGES){ | 
					
						
							|  |  |  | 		fitNImages(w+1) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************** Editor Actions ***/ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | function shiftImageTo(image, direction, moving, force_create_ribbon, mode){ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-05-03 17:08:59 +04:00
										 |  |  | 	mode = mode == null ? NAV_DEFAULT : mode | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// account move for direction...
 | 
					
						
							|  |  |  | 	// XXX get the value from some place more logical than the argument...
 | 
					
						
							| 
									
										
										
										
											2013-05-03 00:57:26 +04:00
										 |  |  | 	var a = moving == 'prev' ? 'prevAll' : 'nextAll'  | 
					
						
							|  |  |  | 	var b = moving == 'prev' ? 'nextAll' : 'prevAll'  | 
					
						
							|  |  |  | 	var target = image[a]('.image' + mode).first() | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 04:30:39 +04:00
										 |  |  | 	target = target.length == 0 ? image[b]().first() : target | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX should this be in here or coupled later via an event???
 | 
					
						
							|  |  |  | 	flashIndicator(direction) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	shiftImage(direction, image, force_create_ribbon) | 
					
						
							|  |  |  | 	// XXX does this need to be animated???
 | 
					
						
							|  |  |  | 	return centerImage(focusImage(target), 'css') | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 00:57:26 +04:00
										 |  |  | function shiftImageUp(image, moving){ | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	return shiftImageTo(image, 'prev', moving) | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 00:57:26 +04:00
										 |  |  | function shiftImageDown(image, moving){ | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	return shiftImageTo(image, 'next') | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 00:57:26 +04:00
										 |  |  | function shiftImageUpNewRibbon(image, moving){ | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	return shiftImageTo(image, 'prev', moving, true) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-03 00:57:26 +04:00
										 |  |  | function shiftImageDownNewRibbon(image, moving){ | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 	return shiftImageTo(image, 'prev', moving, false) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | // TODO manual image ordering (shiftLeft/shiftRight functions)
 | 
					
						
							|  |  |  | // XXX
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-05 23:39:35 +04:00
										 |  |  | /*********************************************************** Marks ***/ | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 02:11:24 +04:00
										 |  |  | // XXX if this unmarks an image in marked-only mode no visible image is 
 | 
					
						
							|  |  |  | // 		going to be current...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | var toggleImageMark = createCSSClassToggler('.current.image', 'marked') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | // mode can be:
 | 
					
						
							|  |  |  | //	- 'ribbon'
 | 
					
						
							|  |  |  | //	- 'all'
 | 
					
						
							|  |  |  | function removeImageMarks(mode){ | 
					
						
							|  |  |  | 	// remove marks from current ribbon (default)...
 | 
					
						
							|  |  |  | 	if(mode == 'ribbon' || mode == null){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 		return getRibbon() | 
					
						
							|  |  |  | 			.find('.marked') | 
					
						
							|  |  |  | 				.removeClass('marked') | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// remove all marks...
 | 
					
						
							|  |  |  | 	} else if(mode == 'all'){ | 
					
						
							|  |  |  | 		return $('.marked') | 
					
						
							|  |  |  | 			.removeClass('marked') | 
					
						
							|  |  |  | 	}  | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function markAll(mode){ | 
					
						
							|  |  |  | 	// remove marks from current ribbon (default)...
 | 
					
						
							|  |  |  | 	if(mode == 'ribbon' || mode == null){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 		return getRibbon() | 
					
						
							|  |  |  | 			.find('.image:not(.marked)') | 
					
						
							|  |  |  | 				.addClass('marked') | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// remove all marks...
 | 
					
						
							|  |  |  | 	} else if(mode == 'all'){ | 
					
						
							|  |  |  | 		return $('.image:not(.marked)').addClass('marked') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-03 00:39:29 +04:00
										 |  |  | // NOTE: this only does it's work in the current ribbon...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function invertImageMarks(){ | 
					
						
							| 
									
										
										
										
											2013-05-05 19:53:06 +04:00
										 |  |  | 	return getRibbon() | 
					
						
							|  |  |  | 		.find('.image') | 
					
						
							|  |  |  | 			.toggleClass('marked') | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-06 23:43:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | // Toggle marks in the current continuous section of marked or unmarked
 | 
					
						
							|  |  |  | // images...
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | function toggleImageMarkBlock(image){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// we need to invert this...
 | 
					
						
							|  |  |  | 	var state = toggleImageMark() | 
					
						
							|  |  |  | 	var _convert = function(){ | 
					
						
							|  |  |  | 		if(toggleImageMark(this, '?') == state){ | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		toggleImageMark(this, state) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	image.nextAll('.image').each(_convert) | 
					
						
							|  |  |  | 	image.prevAll('.image').each(_convert) | 
					
						
							|  |  |  | 	return state | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-05-02 19:47:04 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set sw=4 ts=4 :												 */ |