mirror of
				https://github.com/flynx/ImageGrid.git
				synced 2025-10-31 19:30:07 +00:00 
			
		
		
		
	reorgonized the gen3 code...
Signed-off-by: Alex A. Naanou <alex.nanou@gmail.com>
This commit is contained in:
		
							parent
							
								
									75b2147cd2
								
							
						
					
					
						commit
						bb636f9c91
					
				
							
								
								
									
										618
									
								
								ui/ImageGrid.js
									
									
									
									
									
								
							
							
						
						
									
										618
									
								
								ui/ImageGrid.js
									
									
									
									
									
								
							| @ -1,149 +1,555 @@ | |||||||
| /********************************************************************** | /********************************************************************** | ||||||
| *  | *  | ||||||
| * | * Viewer Generation III | ||||||
| * | *  | ||||||
| * | * Split the API into the following sections: | ||||||
| * This should work over three contexts: | * 	- main control actions | ||||||
| * 	- archive (full) | * 		do main domain tasks like image and ribbon manipulation. | ||||||
| * 		full data available remotely | * 	- serialization and deserialization | ||||||
| * 		handle global operations | * 		load and save data | ||||||
| * 	- local data (full or partial) | * 	- UI | ||||||
| * 		full or partial set of data available locally | * 		basic align, animation and modes | ||||||
| * 		handle global operations (if full data-set is available) | *  | ||||||
| * 		handle local operations (if enough data is available) | *  | ||||||
| * 	- local view (partial) | * TODO group all actions into an object, referencing the viewer... | ||||||
| * 		only the rendered UI and cache | * 	...this will make this reusable multiple times.			 | ||||||
| * | * | ||||||
| * | * | ||||||
| **********************************************************************/ | **********************************************************************/ | ||||||
| 
 | 
 | ||||||
| var Context = { |  | ||||||
| 	// the selection query used to get data...
 |  | ||||||
| 	// NOTE: this should support operations to get next and prev batches if it's partial
 |  | ||||||
| 	// XXX we do not care about this yet
 |  | ||||||
| 	query: null, |  | ||||||
| 
 | 
 | ||||||
| 	// this can be:
 | /********************************************************************** | ||||||
| 	// 	'full'		- indicating that all the data is available locally
 | * Constructors | ||||||
| 	// 	'partial'	- indicating that only part of the data is available
 | */ | ||||||
| 	data_state: 'full', |  | ||||||
| 
 | 
 | ||||||
| 	data: { | // NOTE: to avoid state sync problems this should clone an image if 
 | ||||||
| 		// current image...
 | //		one is available...
 | ||||||
| 		current: null, | function createImage(n){ | ||||||
|  | 	if(n == null){ | ||||||
|  | 		if(window._n == null){ | ||||||
|  | 			window._n = 0 | ||||||
|  | 		} | ||||||
|  | 		n = _n | ||||||
|  | 		_n += 1 | ||||||
|  | 	} | ||||||
|  | 	var img = $('.image') | ||||||
|  | 	if(img.length > 0){ | ||||||
|  | 		return img.first().clone() | ||||||
|  | 					.attr({ | ||||||
|  | 						'order': n, | ||||||
|  | 						// need to strip extra classes...
 | ||||||
|  | 						'class': 'image' | ||||||
|  | 					}) | ||||||
|  | 	} else { | ||||||
|  | 		return $('<div order="'+n+'" class="image"/>') | ||||||
|  | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| 		// images, hashed by GUID...
 | // This will create a set of new images, reusing a list of existing 
 | ||||||
| 		images: { | // elements if given.
 | ||||||
| 		}, | // XXX do we need this???
 | ||||||
|  | function createImages(need, have){ | ||||||
|  | 	have = have == null ? [] : have | ||||||
| 
 | 
 | ||||||
| 		// list of ribbons...
 | 	// we have enough elements in the cache...
 | ||||||
| 		ribbons: [ | 	if(have.length >= need){ | ||||||
| 			// list of GUIDs in sort order...
 | 		return $(have.splice(0, need)) | ||||||
| 			[] | 
 | ||||||
| 		], | 	// need to create additional elements...
 | ||||||
| 		// list of marked GUIDs...
 | 	} else { | ||||||
| 		marked: [ | 		return $(have.toArray().concat(new Array(need - have.length))) | ||||||
| 		], | 			.map(function(i, elem){ | ||||||
|  | 				if(elem != null){ | ||||||
|  | 					return elem | ||||||
|  | 				} | ||||||
|  | 				return createImage()[0] | ||||||
|  | 			}) | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function createRibbon(){ | ||||||
|  | 	return $('<div class="ribbon"/>') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /********************************************************************** | ||||||
|  | * Helpers | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | function flashIndicator(direction){ | ||||||
|  | 	$(direction == 'prev' ? '.up-indicator' : '.down-indicator').fadeIn(200).fadeOut(200) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // ...tried to make this as brain-dead-stupidly-simple as possible...
 | ||||||
|  | function getRelativeVisualPosition(outer, inner){ | ||||||
|  | 	outer = $(outer).offset() | ||||||
|  | 	inner = $(inner).offset() | ||||||
|  | 	return { | ||||||
|  | 		top: inner.top - outer.top, | ||||||
|  | 		left: inner.left - outer.left | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // NOTE: if this returns null, it means that the element is smallest in 
 | ||||||
|  | //		target ribbon -- first position.
 | ||||||
|  | function getImageBefore(image, ribbon, mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	image = $(image) | ||||||
|  | 	if(ribbon == null){ | ||||||
|  | 		ribbon = image.closest('.ribbon') | ||||||
|  | 	} | ||||||
|  | 	var images = $(ribbon).find('.image').filter(mode) | ||||||
|  | 	var order = image.attr('order') | ||||||
|  | 	var prev = null | ||||||
|  | 
 | ||||||
|  | 	images.each(function(){ | ||||||
|  | 		if(order < $(this).attr('order')){ | ||||||
|  | 			return false | ||||||
|  | 		} | ||||||
|  | 		prev = this | ||||||
|  | 	}) | ||||||
|  | 
 | ||||||
|  | 	return $(prev) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | function shiftTo(image, ribbon){ | ||||||
|  | 	var target = getImageBefore(image, ribbon) | ||||||
|  | 	var cur_ribbon = image.closest('.ribbon') | ||||||
|  | 
 | ||||||
|  | 	// insert before the first image if nothing is before the target...
 | ||||||
|  | 	if(target.length == 0){ | ||||||
|  | 		image.prependTo($(ribbon)) | ||||||
|  | 
 | ||||||
|  | 	} else { | ||||||
|  | 		image.insertAfter(target) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	view: null, | 	// if removing last image out of a ribbon, remove the ribbon....
 | ||||||
|  | 	if(cur_ribbon.find('.image').length == 0){ | ||||||
|  | 		cur_ribbon.remove() | ||||||
|  | 	} | ||||||
| 
 | 
 | ||||||
|  | 	return image | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | function shiftImage(direction, image, force_create_ribbon){ | ||||||
|  | 	if(image == null){ | ||||||
|  | 		// XXX need to make this context specific...
 | ||||||
|  | 		image = $('.current.image') | ||||||
|  | 	} else { | ||||||
|  | 		image = $(image) | ||||||
|  | 	} | ||||||
|  | 	var old_ribbon = image.closest('.ribbon') | ||||||
|  | 	var ribbon = old_ribbon[direction]('.ribbon') | ||||||
| 
 | 
 | ||||||
| /********************************************************************** | 	// need to create a new ribbon...
 | ||||||
| * Helpers... | 	if(ribbon.length == 0 || force_create_ribbon == true){ | ||||||
| */ | 		ribbon = createRibbon()['insert' + (direction == 'prev'  | ||||||
| 
 | 												? 'Before'  | ||||||
| // retrun viewer width in images...
 | 												: 'After')](old_ribbon) | ||||||
| function getViewImages(){ | 		shiftTo(image, ribbon) | ||||||
| 	// XXX
 | 	} else { | ||||||
|  | 		shiftTo(image, ribbon) | ||||||
|  | 	} | ||||||
|  | 	return image | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /********************************************************************** | /********************************************************************** | ||||||
| * User actions... | * Modes | ||||||
| */ | */ | ||||||
| 
 | 
 | ||||||
| /* Focus an image... | var toggleMarkedOnlyView = createCSSClassToggler('.viewer', 'marked-only', | ||||||
| * | 	function(){ | ||||||
| * n can be: | 		var cur = $('.current.image') | ||||||
| * 	- position relative to current | 		// current is marked...
 | ||||||
| * 		-1 is previous image, +1 next | 		if(cur.hasClass('marked')){ | ||||||
| * 	- GUID | 			centerImage(null, 'css') | ||||||
| * 		if GUID is present in context select it. | 			return | ||||||
|  | 		}  | ||||||
|  | 		// there is a marked image in this ribbon...
 | ||||||
|  | 		var target = getImageBefore(cur, null, true) | ||||||
|  | 		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' | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /********************************************************************** | ||||||
|  | * Layout | ||||||
| */ | */ | ||||||
| function focusImage(n){ | 
 | ||||||
| 	// XXX
 | function focusImage(image){ | ||||||
|  | 	image.closest('.viewer').find('.current.image').removeClass('current') | ||||||
|  | 	return image.addClass('current') | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // shorthands...
 |  | ||||||
| function nextImage(){ |  | ||||||
| 	return focusImage(1) |  | ||||||
| } |  | ||||||
| function prevImage(){ |  | ||||||
| 	return focusImage(-1) |  | ||||||
| } |  | ||||||
| // NOTE: here n is the multiplier to the screen width of images...
 |  | ||||||
| function nextViewImages(n){ |  | ||||||
| 	n = n == null ? 1 : n |  | ||||||
| 	return focusImage(getViewImages()*n) |  | ||||||
| } |  | ||||||
| function prevViewImages(n){ |  | ||||||
| 	n = n == null ? -1 : -n |  | ||||||
| 	return focusImage(getViewImages()*n) |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| function firstImage(){ | // This appears to work well with scaling...
 | ||||||
| 	// XXX
 | // XXX make this more configurable...
 | ||||||
| } | // XXX this only works for square images...
 | ||||||
| function lastImage(){ | function centerImage(image, mode){ | ||||||
| 	// XXX
 | 	if(mode == null){ | ||||||
|  | 		//mode = 'css'
 | ||||||
|  | 		mode = 'animate' | ||||||
|  | 	} | ||||||
|  | 	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')) | ||||||
|  | 	t = t ? t : 0 | ||||||
|  | 	var l = parseFloat(ribbons.css('left')) | ||||||
|  | 	l = l ? l : 0 | ||||||
|  | 
 | ||||||
|  | 	// do the actual work...
 | ||||||
|  | 	return ribbons[mode]({ | ||||||
|  | 		'top': t - pos.top + (H - h)/2, | ||||||
|  | 		'left': l - pos.left + (W - w)/2 | ||||||
|  | 	}) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | /********************************************************************** | ||||||
| /* Focus a ribbon... | * Infinite ribbon machinery | ||||||
| * |  | ||||||
| * n can be: |  | ||||||
| * 	- position relative to current |  | ||||||
| * 		-1 is previous image, +1 next |  | ||||||
| * 	- GUID (???) |  | ||||||
| * 		if GUID is present in context select it. |  | ||||||
| * |  | ||||||
| * NOTE: this will also focus the closest image... |  | ||||||
| */ | */ | ||||||
| function focusRibbon(n){ | 
 | ||||||
| 	// XXX
 | // XXX need mechanics to populate the images or to connect such 
 | ||||||
|  | //		functionality...
 | ||||||
|  | //		...this is to be done in the loader...
 | ||||||
|  | 
 | ||||||
|  | // NOTE: negative left or right will contract the ribbon...
 | ||||||
|  | function extendRibbon(left, right, ribbon){ | ||||||
|  | 	ribbon = ribbon == null ?  | ||||||
|  | 				$('.current.image').closest('.ribbon')  | ||||||
|  | 				: $(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) | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return res | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // shorthands...
 |  | ||||||
| function ribbonAbove(n){ |  | ||||||
| 	n = n == null ? -1 : n |  | ||||||
| 	return focusRibbon(n) |  | ||||||
| } |  | ||||||
| function ribbonBelow(n){ |  | ||||||
| 	n = n == null ? 1 : -n |  | ||||||
| 	return focusRibbon(n) |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| function topRibbon(){ | // Roll the ribbon n positions to the left.
 | ||||||
| 	// XXX
 | //
 | ||||||
| } | // NOTE: if n is negative the ribbon will be rolled right.
 | ||||||
| function bottomRibbon(){ | // NOTE: rollRibbon(N, R) is equivalent to extendRibbon(-N, N, R)
 | ||||||
| 	// XXX
 | // 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 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
| /* Marking... | 
 | ||||||
| *  | /********************************************************************** | ||||||
| * NOTE: n can be null, then current image is marked. | * User actions | ||||||
| */ | */ | ||||||
| function toggleMark(n){ | 
 | ||||||
| 	// XXX
 | // 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...
 | ||||||
|  | function nextImage(mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	return centerImage( | ||||||
|  | 		focusImage( | ||||||
|  | 			$('.current.image').nextAll('.image' + mode).first())) | ||||||
|  | } | ||||||
|  | function prevImage(mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	return centerImage( | ||||||
|  | 		focusImage( | ||||||
|  | 			$('.current.image').prevAll('.image' + mode).first())) | ||||||
|  | } | ||||||
|  | function firstImage(mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	return centerImage( | ||||||
|  | 		focusImage( | ||||||
|  | 			$('.current.image').closest('.ribbon').find('.image').filter(mode).first())) | ||||||
|  | } | ||||||
|  | function lastImage(mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	return centerImage( | ||||||
|  | 		focusImage( | ||||||
|  | 			$('.current.image').closest('.ribbon').find('.image').filter(mode).last())) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // 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.
 | ||||||
|  | // XXX get move direction...
 | ||||||
|  | function prevRibbon(moving, mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	var cur = $('.current.image') | ||||||
|  | 	// pre marked-only mode...
 | ||||||
|  | 	//var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon'))
 | ||||||
|  | 	var target = getImageBefore(cur, cur.closest('.ribbon').prevAll('.ribbon' + mode).first(), true) | ||||||
|  | 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ | ||||||
|  | 		var next = target.nextAll('.image' + mode).first() | ||||||
|  | 		target = next.length > 0 ? next : target | ||||||
|  | 	} | ||||||
|  | 	return centerImage(focusImage(target)) | ||||||
|  | } | ||||||
|  | // XXX get move direction...
 | ||||||
|  | function nextRibbon(moving, mode){ | ||||||
|  | 	if(mode == null){ | ||||||
|  | 		mode = NAV_DEFAULT | ||||||
|  | 	} | ||||||
|  | 	var cur = $('.current.image') | ||||||
|  | 	// pre marked-only mode...
 | ||||||
|  | 	//var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon'))
 | ||||||
|  | 	var target = getImageBefore(cur, cur.closest('.ribbon').nextAll('.ribbon' + mode).first(), true) | ||||||
|  | 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ | ||||||
|  | 		var next = target.nextAll('.image' + mode).first() | ||||||
|  | 		target = next.length > 0 ? next : target | ||||||
|  | 	} | ||||||
|  | 	return centerImage(focusImage(target)) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // XXX get move direction...
 | ||||||
|  | function _shiftImageTo(image, direction, moving, force_create_ribbon){ | ||||||
|  | 	if(image == null){ | ||||||
|  | 		image = $('.current.image') | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	// account move for direction...
 | ||||||
|  | 	// XXX get the value from some place more logical than the argument...
 | ||||||
|  | 	var a = moving == 'prev' ? 'prev' : 'next'  | ||||||
|  | 	var b = moving == 'prev' ? 'next' : 'prev'  | ||||||
|  | 	var target = image[a]('.image') | ||||||
|  | 
 | ||||||
|  | 	target = target.length == 0 ? image[b]() : target | ||||||
|  | 
 | ||||||
|  | 	// 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') | ||||||
|  | } | ||||||
|  | function shiftImageUp(image){ | ||||||
|  | 	return _shiftImageTo(image, 'prev') | ||||||
|  | } | ||||||
|  | function shiftImageDown(image){ | ||||||
|  | 	return _shiftImageTo(image, 'next') | ||||||
|  | } | ||||||
|  | function shiftImageUpNewRibbon(image){ | ||||||
|  | 	return _shiftImageTo(image, 'prev', true) | ||||||
|  | } | ||||||
|  | function shiftImageDownNewRibbon(image){ | ||||||
|  | 	return _shiftImageTo(image, 'prev', false) | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // TODO manual image ordering (shiftLeft/shiftRight functions)
 | ||||||
|  | // XXX
 | ||||||
|  | 
 | ||||||
|  | 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') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | // Marks...
 | ||||||
|  | 
 | ||||||
|  | var toggleImageMark = createCSSClassToggler('.current.image', 'marked') | ||||||
|  | 
 | ||||||
|  | // mode can be:
 | ||||||
|  | //	- 'ribbon'
 | ||||||
|  | //	- 'all'
 | ||||||
|  | function removeImageMarks(mode){ | ||||||
|  | 	// remove marks from current ribbon (default)...
 | ||||||
|  | 	if(mode == 'ribbon' || mode == null){ | ||||||
|  | 		return $('.current.image') | ||||||
|  | 			.closest('.ribbon') | ||||||
|  | 				.find('.marked') | ||||||
|  | 					.removeClass('marked') | ||||||
|  | 
 | ||||||
|  | 	// remove all marks...
 | ||||||
|  | 	} else if(mode == 'all'){ | ||||||
|  | 		return $('.marked') | ||||||
|  | 			.removeClass('marked') | ||||||
|  | 	}  | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function markAll(mode){ | ||||||
|  | 	// remove marks from current ribbon (default)...
 | ||||||
|  | 	if(mode == 'ribbon' || mode == null){ | ||||||
|  | 		return $('.current.image') | ||||||
|  | 			.closest('.ribbon') | ||||||
|  | 				.find('.image:not(.marked)') | ||||||
|  | 					.addClass('marked') | ||||||
|  | 
 | ||||||
|  | 	// remove all marks...
 | ||||||
|  | 	} else if(mode == 'all'){ | ||||||
|  | 		return $('.image:not(.marked)').addClass('marked') | ||||||
|  | 	} | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | function invertImageMarks(){ | ||||||
|  | 	return $('.current.image') | ||||||
|  | 		.closest('.ribbon') | ||||||
|  | 			.find('.image') | ||||||
|  | 				.toggleClass('marked') | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | // this will toggle marks in the current continuous section of marked 
 | ||||||
|  | // or unmarked images...
 | ||||||
|  | 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 | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | /********************************************************************** | ||||||
|  | * Event handlers... | ||||||
|  | */ | ||||||
|  | 
 | ||||||
|  | // NOTE: this is on purpose done relative...
 | ||||||
|  | function clickHandler(evt){ | ||||||
|  | 	var img = $(evt.target).closest('.image') | ||||||
|  | 
 | ||||||
|  | 	centerImage( | ||||||
|  | 		focusImage(img)) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | |||||||
							
								
								
									
										538
									
								
								ui/index.html
									
									
									
									
									
								
							
							
						
						
									
										538
									
								
								ui/index.html
									
									
									
									
									
								
							| @ -194,544 +194,10 @@ | |||||||
| <script src="lib/jli.js"></script> | <script src="lib/jli.js"></script> | ||||||
| <script src="lib/keyboard.js"></script> | <script src="lib/keyboard.js"></script> | ||||||
| 
 | 
 | ||||||
|  | <script src="ImageGrid.js"></script> | ||||||
|  | 
 | ||||||
| <script> | <script> | ||||||
| 
 | 
 | ||||||
| /* |  | ||||||
| 
 |  | ||||||
| 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.			 |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function flashIndicator(direction){ |  | ||||||
| 	$(direction == 'prev' ? '.up-indicator' : '.down-indicator').fadeIn(200).fadeOut(200) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 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... |  | ||||||
| 		var target = getImageBefore(cur, null, true) |  | ||||||
| 		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... |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| var toggleImageMark = createCSSClassToggler('.current.image', 'marked') |  | ||||||
| 
 |  | ||||||
| // mode can be: |  | ||||||
| //	- 'ribbon' |  | ||||||
| //	- 'all' |  | ||||||
| function removeImageMarks(mode){ |  | ||||||
| 	// remove marks from current ribbon (default)... |  | ||||||
| 	if(mode == 'ribbon' || mode == null){ |  | ||||||
| 		return $('.current.image') |  | ||||||
| 			.closest('.ribbon') |  | ||||||
| 				.find('.marked') |  | ||||||
| 					.removeClass('marked') |  | ||||||
| 
 |  | ||||||
| 	// remove all marks... |  | ||||||
| 	} else if(mode == 'all'){ |  | ||||||
| 		return $('.marked') |  | ||||||
| 			.removeClass('marked') |  | ||||||
| 	}  |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function markAll(mode){ |  | ||||||
| 	// remove marks from current ribbon (default)... |  | ||||||
| 	if(mode == 'ribbon' || mode == null){ |  | ||||||
| 		return $('.current.image') |  | ||||||
| 			.closest('.ribbon') |  | ||||||
| 				.find('.image:not(.marked)') |  | ||||||
| 					.addClass('marked') |  | ||||||
| 
 |  | ||||||
| 	// remove all marks... |  | ||||||
| 	} else if(mode == 'all'){ |  | ||||||
| 		return $('.image:not(.marked)').addClass('marked') |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function invertImageMarks(){ |  | ||||||
| 	return $('.current.image') |  | ||||||
| 		.closest('.ribbon') |  | ||||||
| 			.find('.image') |  | ||||||
| 				.toggleClass('marked') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // this will toggle marks in the current continuous section of marked  |  | ||||||
| // or unmarked images... |  | ||||||
| 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 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // 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' |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // NOTE: to avoid state sync problems this should clone an image if  |  | ||||||
| //		one is available... |  | ||||||
| function createImage(n){ |  | ||||||
| 	if(n == null){ |  | ||||||
| 		if(window._n == null){ |  | ||||||
| 			window._n = 0 |  | ||||||
| 		} |  | ||||||
| 		n = _n |  | ||||||
| 		_n += 1 |  | ||||||
| 	} |  | ||||||
| 	var img = $('.image') |  | ||||||
| 	if(img.length > 0){ |  | ||||||
| 		return img.first().clone() |  | ||||||
| 					.attr({ |  | ||||||
| 						'order': n, |  | ||||||
| 						// need to strip extra classes... |  | ||||||
| 						'class': 'image' |  | ||||||
| 					}) |  | ||||||
| 	} else { |  | ||||||
| 		return $('<div order="'+n+'" class="image"/>') |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // This will create a set of new images, reusing a list of existing  |  | ||||||
| // elements if given. |  | ||||||
| // XXX do we need this??? |  | ||||||
| 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] |  | ||||||
| 			}) |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function createRibbon(){ |  | ||||||
| 	return $('<div class="ribbon"/>') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // NOTE: if this returns null, it means that the element is smallest in  |  | ||||||
| //		target ribbon -- first position. |  | ||||||
| function getImageBefore(image, ribbon, visible_only){ |  | ||||||
| 	image = $(image) |  | ||||||
| 	if(ribbon == null){ |  | ||||||
| 		ribbon = image.closest('.ribbon') |  | ||||||
| 	} |  | ||||||
| 	// pre marked-only mode... |  | ||||||
| 	//var images = $(ribbon).find('.image') |  | ||||||
| 	if(visible_only){ |  | ||||||
| 		var images = $(ribbon).find('.image').filter(':visible') |  | ||||||
| 	} else { |  | ||||||
| 		var images = $(ribbon).find('.image') |  | ||||||
| 	} |  | ||||||
| 	var order = image.attr('order') |  | ||||||
| 	var prev = null |  | ||||||
| 
 |  | ||||||
| 	images.each(function(){ |  | ||||||
| 		if(order < $(this).attr('order')){ |  | ||||||
| 			return false |  | ||||||
| 		} |  | ||||||
| 		prev = this |  | ||||||
| 	}) |  | ||||||
| 
 |  | ||||||
| 	return $(prev) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function shiftTo(image, ribbon){ |  | ||||||
| 	var target = getImageBefore(image, ribbon) |  | ||||||
| 	var cur_ribbon = image.closest('.ribbon') |  | ||||||
| 
 |  | ||||||
| 	// insert before the first image if nothing is before the target... |  | ||||||
| 	if(target.length == 0){ |  | ||||||
| 		image.prependTo($(ribbon)) |  | ||||||
| 
 |  | ||||||
| 	} else { |  | ||||||
| 		image.insertAfter(target) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// if removing last image out of a ribbon, remove the ribbon.... |  | ||||||
| 	if(cur_ribbon.find('.image').length == 0){ |  | ||||||
| 		cur_ribbon.remove() |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	return image |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| function shiftImage(direction, image, force_create_ribbon){ |  | ||||||
| 	if(image == null){ |  | ||||||
| 		// XXX need to make this context specific... |  | ||||||
| 		image = $('.current.image') |  | ||||||
| 	} else { |  | ||||||
| 		image = $(image) |  | ||||||
| 	} |  | ||||||
| 	var old_ribbon = image.closest('.ribbon') |  | ||||||
| 	var ribbon = old_ribbon[direction]('.ribbon') |  | ||||||
| 
 |  | ||||||
| 	// need to create a new ribbon... |  | ||||||
| 	if(ribbon.length == 0 || force_create_ribbon == true){ |  | ||||||
| 		ribbon = createRibbon()['insert' + (direction == 'prev'  |  | ||||||
| 												? 'Before'  |  | ||||||
| 												: 'After')](old_ribbon) |  | ||||||
| 		shiftTo(image, ribbon) |  | ||||||
| 	} else { |  | ||||||
| 		shiftTo(image, ribbon) |  | ||||||
| 	} |  | ||||||
| 	return image |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function focusImage(image){ |  | ||||||
| 	image.closest('.viewer').find('.current.image').removeClass('current') |  | ||||||
| 	return image.addClass('current') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // Alignment API... |  | ||||||
| // ...tried to make this as brain-dead-stupidly-simple as possible... |  | ||||||
| function relativeVisualPosition(outer, inner){ |  | ||||||
| 	outer = $(outer).offset() |  | ||||||
| 	inner = $(inner).offset() |  | ||||||
| 	return { |  | ||||||
| 		top: inner.top - outer.top, |  | ||||||
| 		left: inner.left - outer.left |  | ||||||
| 	} |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| // This appears to work well with scaling... |  | ||||||
| // XXX make this more configurable... |  | ||||||
| // XXX this only works for square images... |  | ||||||
| function centerImage(image, mode){ |  | ||||||
| 	if(mode == null){ |  | ||||||
| 		//mode = 'css' |  | ||||||
| 		mode = 'animate' |  | ||||||
| 	} |  | ||||||
| 	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 = relativeVisualPosition(viewer, image) |  | ||||||
| 
 |  | ||||||
| 	// zero out top/left if set to anything other than a specific number... |  | ||||||
| 	var t = parseFloat(ribbons.css('top')) |  | ||||||
| 	t = t ? t : 0 |  | ||||||
| 	var l = parseFloat(ribbons.css('left')) |  | ||||||
| 	l = l ? l : 0 |  | ||||||
| 
 |  | ||||||
| 	// do the actual work... |  | ||||||
| 	return ribbons[mode]({ |  | ||||||
| 		'top': t - pos.top + (H - h)/2, |  | ||||||
| 		'left': l - pos.left + (W - w)/2 |  | ||||||
| 	}) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /********************************************************************** |  | ||||||
| * Infinite ribbon machinery |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| // XXX need mechanics to populate the images or to connect such  |  | ||||||
| //		functionality... |  | ||||||
| //		...this is to be done in the loader... |  | ||||||
| 
 |  | ||||||
| // NOTE: negative left or right will contract the ribbon... |  | ||||||
| function extendRibbon(left, right, ribbon){ |  | ||||||
| 	ribbon = ribbon == null ?  |  | ||||||
| 				$('.current.image').closest('.ribbon')  |  | ||||||
| 				: $(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) |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	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 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /********************************************************************** |  | ||||||
| * User actions |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| // basic navigation actions... |  | ||||||
| function nextImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').next('.image'))) |  | ||||||
| 			$('.current.image').next('.image:visible'))) |  | ||||||
| } |  | ||||||
| function prevImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').prev('.image'))) |  | ||||||
| 			$('.current.image').prev('.image:visible'))) |  | ||||||
| } |  | ||||||
| function firstImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').closest('.ribbon').find('.image').first())) |  | ||||||
| 			$('.current.image').closest('.ribbon').find('.image').filter(':visible').first())) |  | ||||||
| } |  | ||||||
| function lastImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').closest('.ribbon').find('.image').last())) |  | ||||||
| 			$('.current.image').closest('.ribbon').find('.image').filter(':visible').last())) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| function nextMarkedImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').next('.marked.image'))) |  | ||||||
| 			$('.current.image').next('.marked.image:visible'))) |  | ||||||
| } |  | ||||||
| function prevMarkedImage(){ |  | ||||||
| 	return centerImage( |  | ||||||
| 		focusImage( |  | ||||||
| 			// pre marked-only mode... |  | ||||||
| 			//$('.current.image').prev('.marked.image'))) |  | ||||||
| 			$('.current.image').prev('.marked.image:visible'))) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // 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. |  | ||||||
| // XXX get move direction... |  | ||||||
| function prevRibbon(moving){ |  | ||||||
| 	var cur = $('.current.image') |  | ||||||
| 	// pre marked-only mode... |  | ||||||
| 	//var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon')) |  | ||||||
| 	var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon:visible'), true) |  | ||||||
| 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ |  | ||||||
| 		var next = target.next('.image') |  | ||||||
| 		target = next.length > 0 ? next : target |  | ||||||
| 	} |  | ||||||
| 	return centerImage(focusImage(target)) |  | ||||||
| } |  | ||||||
| // XXX get move direction... |  | ||||||
| function nextRibbon(moving){ |  | ||||||
| 	var cur = $('.current.image') |  | ||||||
| 	// pre marked-only mode... |  | ||||||
| 	//var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon')) |  | ||||||
| 	var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon:visible'), true) |  | ||||||
| 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ |  | ||||||
| 		var next = target.next('.image') |  | ||||||
| 		target = next.length > 0 ? next : target |  | ||||||
| 	} |  | ||||||
| 	return centerImage(focusImage(target)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // XXX get move direction... |  | ||||||
| function _shiftImageTo(image, direction, moving, force_create_ribbon){ |  | ||||||
| 	if(image == null){ |  | ||||||
| 		image = $('.current.image') |  | ||||||
| 	} |  | ||||||
| 
 |  | ||||||
| 	// account move for direction... |  | ||||||
| 	// XXX get the value from some place more logical than the argument... |  | ||||||
| 	var a = moving == 'prev' ? 'prev' : 'next'  |  | ||||||
| 	var b = moving == 'prev' ? 'next' : 'prev'  |  | ||||||
| 	var target = image[a]('.image') |  | ||||||
| 
 |  | ||||||
| 	target = target.length == 0 ? image[b]() : target |  | ||||||
| 
 |  | ||||||
| 	// 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') |  | ||||||
| } |  | ||||||
| function shiftImageUp(image){ |  | ||||||
| 	return _shiftImageTo(image, 'prev') |  | ||||||
| } |  | ||||||
| function shiftImageDown(image){ |  | ||||||
| 	return _shiftImageTo(image, 'next') |  | ||||||
| } |  | ||||||
| function shiftImageUpNewRibbon(image){ |  | ||||||
| 	return _shiftImageTo(image, 'prev', true) |  | ||||||
| } |  | ||||||
| function shiftImageDownNewRibbon(image){ |  | ||||||
| 	return _shiftImageTo(image, 'prev', false) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| // TODO manual image ordering (shiftLeft/shiftRight functions) |  | ||||||
| // XXX |  | ||||||
| 
 |  | ||||||
| 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') |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| /********************************************************************** |  | ||||||
| * Event handlers... |  | ||||||
| */ |  | ||||||
| 
 |  | ||||||
| // NOTE: this is on purpose done relative... |  | ||||||
| function clickHandler(evt){ |  | ||||||
| 	var img = $(evt.target).closest('.image') |  | ||||||
| 
 |  | ||||||
| 	centerImage( |  | ||||||
| 		focusImage(img)) |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 |  | ||||||
| 
 | 
 | ||||||
| // setup... | // setup... | ||||||
| $(function(){ | $(function(){ | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user