| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | /******************************************* Actions (EXPERIMENTAL) **/ | 
					
						
							|  |  |  | // XXX this set of features is experimental...
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | // this gives us:
 | 
					
						
							|  |  |  | // 	- namespace cleanup
 | 
					
						
							|  |  |  | // 	- auto-generated help
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | // the main questions are:
 | 
					
						
							|  |  |  | // 	- is this overcomplicating things?
 | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | // 	- are the benefits worth the code bloat?
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | var ImageGrid = { | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	// this can be serialized...
 | 
					
						
							|  |  |  | 	// NOTE: to load a serialized set of options use ImageGrid.set(options)...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	actions: {}, | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	option: {}, | 
					
						
							|  |  |  | 	option_props: {}, | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	option_groups: [], | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// define an action...
 | 
					
						
							|  |  |  | 	// the two values that are obligatory are:
 | 
					
						
							| 
									
										
										
										
											2012-08-15 03:03:00 +04:00
										 |  |  | 	// 		title	- name of the action
 | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	// 		call	- callable
 | 
					
						
							|  |  |  | 	// XXX revise...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	ACTION: function(obj, func){ | 
					
						
							|  |  |  | 		if(func != null){ | 
					
						
							|  |  |  | 			obj = $.extend(obj, { | 
					
						
							|  |  |  | 				id: func.name != '' ? func.name : obj.id, | 
					
						
							|  |  |  | 				call: func  | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 		// add all the attrs to the function...
 | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 		if(this._type_handler[obj.type] != null){ | 
					
						
							|  |  |  | 			this._type_handler[obj.type](obj) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		var call = obj.call | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 		for(i in obj){ | 
					
						
							|  |  |  | 			if(i == 'doc' && call.doc != null){ | 
					
						
							|  |  |  | 				call.func_doc = call.doc  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			call[i] = obj[i] | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 		this[obj.id] = call | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		this.actions[obj.id] = call | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 		return call | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	// shorthand: each argument is an action, the group of each will be set the same...
 | 
					
						
							|  |  |  | 	GROUP: function(group){ | 
					
						
							|  |  |  | 		for(var i=1; i<arguments.length; i++){ | 
					
						
							|  |  |  | 			var obj = arguments[i] | 
					
						
							|  |  |  | 			obj.group = group | 
					
						
							|  |  |  | 			// if we have an option for this prop then fix it's group too...
 | 
					
						
							|  |  |  | 			if(this.option_props[obj.id] != null){ | 
					
						
							|  |  |  | 				this.option_props[obj.id].group = group | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(this.option_groups.indexOf(obj.group) < 0 && obj.group != null){ | 
					
						
							|  |  |  | 				this.option_groups.push(obj.group) | 
					
						
							|  |  |  | 				this.option_groups.sort() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	// define an option...
 | 
					
						
							|  |  |  | 	OPTION: function(obj){ | 
					
						
							|  |  |  | 		this.option[obj.name] = obj.value | 
					
						
							|  |  |  | 		this.option_props[obj.name] = obj | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 		if(this.option_groups.indexOf(obj.group) < 0 && obj.group != null){ | 
					
						
							|  |  |  | 			this.option_groups.push(obj.group) | 
					
						
							|  |  |  | 			this.option_groups.sort() | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		return obj | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 	TYPE: function(name, handler){ | 
					
						
							|  |  |  | 		this._type_handler[name] = handler | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-15 03:02:27 +04:00
										 |  |  | 	_type_handler: { | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | // system actions and handlers...
 | 
					
						
							|  |  |  | ImageGrid.GROUP('API', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			doc: 'Set option(s) value(s), calling apropriate callbacks.', | 
					
						
							| 
									
										
										
										
											2012-08-19 23:18:11 +04:00
										 |  |  | 			group: 'API', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function set(obj){ | 
					
						
							|  |  |  | 			for(var n in obj){ | 
					
						
							|  |  |  | 				this.option[n] = obj[n] | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 			// NOTE: this is separate so as to exclude the posibility of race 
 | 
					
						
							|  |  |  | 			// 		 conditions...
 | 
					
						
							|  |  |  | 			// 		 ...thogh there is still a posibility of conflicting 
 | 
					
						
							|  |  |  | 			// 		 modes, especially if one mode sets more modes...
 | 
					
						
							|  |  |  | 			for(var n in obj){ | 
					
						
							|  |  |  | 				// call the callback if it exists...
 | 
					
						
							|  |  |  | 				if(this.option_props[n].callback != null){ | 
					
						
							|  |  |  | 					this.option_props[n].callback() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			doc: 'Get documentation for name.', | 
					
						
							| 
									
										
										
										
											2012-08-19 23:18:11 +04:00
										 |  |  | 			group: 'API', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function doc(name){ | 
					
						
							|  |  |  | 			return { | 
					
						
							|  |  |  | 				action: this[name] != null ? this[name].doc : null, | 
					
						
							|  |  |  | 				action_func: this[name] != null ? this[name].func_doc : null, | 
					
						
							|  |  |  | 				option: this.option_props[name] != null ? this.option_props[name].doc : null, | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		})) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | ImageGrid.TYPE('toggle', function(obj){ | 
					
						
							|  |  |  | 	var call = obj.call | 
					
						
							|  |  |  | 	// wrap the call to set the option...
 | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 	// XXX this is context mirroring...
 | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 	obj.call = function(action){ | 
					
						
							|  |  |  | 		var res = call(action) | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 		ImageGrid.option[obj.id] = call('?') | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 		return res | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// add an option to store the state...
 | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 		name: obj.id, | 
					
						
							|  |  |  | 		title: obj.title, | 
					
						
							|  |  |  | 		group: obj.group, | 
					
						
							|  |  |  | 		display: obj.display, | 
					
						
							|  |  |  | 		doc: obj.doc == null ? 'Stores the state of '+obj.id+' action.' : obj.doc, | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 		value: obj.call('?'), | 
					
						
							|  |  |  | 		callback: function(){ | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | 			obj.call() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		click_handler: function(){ | 
					
						
							|  |  |  | 			obj.call() | 
					
						
							| 
									
										
										
										
											2012-08-15 03:30:35 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | }) | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 22:23:48 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-15 14:26:23 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | /******************************************* Setup Data and Globals **/ | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | var DEBUG = true | 
					
						
							| 
									
										
										
										
											2012-08-17 06:33:01 +04:00
										 |  |  | //var DEBUG = false
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-17 07:30:03 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | ImageGrid.GROUP('State', | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'BACKGROUND_MODES', | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			doc: 'list of available background styles.\n\n'+ | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				'NOTE: there is also a null mode that is what is set in the '+ | 
					
						
							|  |  |  | 				'main CSS.', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 			value: [ | 
					
						
							|  |  |  | 				'dark', | 
					
						
							|  |  |  | 				'black', | 
					
						
							|  |  |  | 				// this can be removed but when given it must be last.
 | 
					
						
							|  |  |  | 				null | 
					
						
							|  |  |  | 			] | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'NORMAL_MODE_BG', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 			value: null, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			doc: 'Background style in normal (ribbon) mode.\n\n'+ | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				'NOTE: This will get updated on background change in tuntime.\n'+ | 
					
						
							|  |  |  | 				'NOTE: null represents the default style.', | 
					
						
							|  |  |  | 			callback: function(){ | 
					
						
							|  |  |  | 				if(ImageGrid.toggleSingleImageMode('?') == 'off'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'SINGLE_IMAGE_MODE_BG', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 			value: 'black', | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			doc: 'Background style in single image mode.\n\n'+ | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				'NOTE: This will get updated on background change in tuntime.\n'+ | 
					
						
							|  |  |  | 				'NOTE: null represents the default style.', | 
					
						
							|  |  |  | 			callback: function(){ | 
					
						
							|  |  |  | 				if(ImageGrid.toggleSingleImageMode('?') == 'on'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'ORIGINAL_FIELD_SCALE', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 			value: 1.0, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			doc: 'Scale of view in image mode.\n\n'+ | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				'NOTE: this will change if changed at runtime.', | 
					
						
							|  |  |  | 			callback: function(){ | 
					
						
							|  |  |  | 				if(ImageGrid.toggleSingleImageMode('?') == 'off'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 					ImageGrid.setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-05 21:03:37 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | ImageGrid.GROUP('Mode: All', | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'ZOOM_FACTOR', | 
					
						
							|  |  |  | 			title: 'Zooming factor', | 
					
						
							|  |  |  | 			value: 2, | 
					
						
							|  |  |  | 			doc: 'Sets the zoom factor used for a manual zooming step.' | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'MOVE_DELTA', | 
					
						
							|  |  |  | 			title: 'Move step', | 
					
						
							|  |  |  | 			value: 50, | 
					
						
							|  |  |  | 			doc: 'Sets the move delta in pixels for keyboard view moving.' | 
					
						
							|  |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-20 01:06:08 +04:00
										 |  |  | if(DEBUG){ | 
					
						
							|  |  |  | 	ImageGrid.OPTION({ | 
					
						
							|  |  |  | 			name: 'TEST', | 
					
						
							|  |  |  | 			title: 'Test the Other group mechanics', | 
					
						
							|  |  |  | 			value: 0, | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | /************************************************ jQuery extensions **/ | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | jQuery.fn.reverseChildren = function(){ | 
					
						
							|  |  |  | 	return $(this).each(function(_, e){ | 
					
						
							|  |  |  | 		return $(e).append($(e).children().detach().get().reverse()) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | jQuery.fn.sortChildren = function(func){ | 
					
						
							|  |  |  | 	return $(this).each(function(_, e){ | 
					
						
							|  |  |  | 		return $(e).append($(e).children().detach().get().sort(func)) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 23:40:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************** Helpers **/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function getImageOrder(img){ | 
					
						
							|  |  |  | 	// XXX HACK need to parseInt this because '13' is less than '2'... 
 | 
					
						
							|  |  |  | 	// 	   ...figure a way out of this!!!
 | 
					
						
							|  |  |  | 	return parseInt($(img).attr('id')) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2012-08-14 18:08:45 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function setImageOrder(img, order){ | 
					
						
							|  |  |  | 	return $(img).attr({'id': order}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | function cmpImageOrder(a, b){ | 
					
						
							|  |  |  | 	return getImageOrder(a) - getImageOrder(b) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-20 02:12:33 +04:00
										 |  |  | // NOTE: don't understand why am I the one who has to write this...
 | 
					
						
							|  |  |  | var SPECIAL_KEYS = { | 
					
						
							|  |  |  | 	9:		'Tab', | 
					
						
							|  |  |  | 	13:		'Enter', | 
					
						
							|  |  |  | 	16:		'Shift', | 
					
						
							|  |  |  | 	17:		'Ctrl', | 
					
						
							|  |  |  | 	18:		'Alt', | 
					
						
							|  |  |  | 	20:		'Caps Lock', | 
					
						
							|  |  |  | 	27:		'Esc', | 
					
						
							|  |  |  | 	32:		'Space', | 
					
						
							|  |  |  | 	33:		'PgUp', | 
					
						
							|  |  |  | 	34:		'PgDown',	 | 
					
						
							|  |  |  | 	35:		'End', | 
					
						
							|  |  |  | 	36:		'Home', | 
					
						
							|  |  |  | 	37:		'Right', | 
					
						
							|  |  |  | 	38:		'Up', | 
					
						
							|  |  |  | 	39:		'Left', | 
					
						
							|  |  |  | 	40:		'Down', | 
					
						
							|  |  |  | 	45:		'Ins', | 
					
						
							|  |  |  | 	46:		'Del', | 
					
						
							|  |  |  | 	80:		'Backspace', | 
					
						
							|  |  |  | 	91:		'Win', | 
					
						
							|  |  |  | 	93:		'Menu', | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	112:	'F1', | 
					
						
							|  |  |  | 	113:	'F2', | 
					
						
							|  |  |  | 	114:	'F3', | 
					
						
							|  |  |  | 	115:	'F4', | 
					
						
							|  |  |  | 	116:	'F5', | 
					
						
							|  |  |  | 	117:	'F6', | 
					
						
							|  |  |  | 	118:	'F7', | 
					
						
							|  |  |  | 	119:	'F8', | 
					
						
							|  |  |  | 	120:	'F9', | 
					
						
							|  |  |  | 	121:	'F10', | 
					
						
							|  |  |  | 	122:	'F11', | 
					
						
							|  |  |  | 	123:	'F12', | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX some keys look really wrong...
 | 
					
						
							|  |  |  | function toKeyName(code){ | 
					
						
							|  |  |  | 	// check for special keys...
 | 
					
						
							|  |  |  | 	var k = SPECIAL_KEYS[code] | 
					
						
							|  |  |  | 	if(k != null){ | 
					
						
							|  |  |  | 		return k | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// chars...
 | 
					
						
							|  |  |  | 	k = String.fromCharCode(code) | 
					
						
							|  |  |  | 	if(k != ''){ | 
					
						
							|  |  |  | 		return k.toLowerCase() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return null | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | // show a jQuary opject in viewer overlay...
 | 
					
						
							| 
									
										
										
										
											2012-08-20 02:12:33 +04:00
										 |  |  | // XXX need to set .scrollTop(0) when showing different UI... 
 | 
					
						
							|  |  |  | // 		...and not set it when the UI is the same
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | function showInOverlay(obj){ | 
					
						
							| 
									
										
										
										
											2012-08-20 01:06:08 +04:00
										 |  |  | 	obj.click(function(){ return false }) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	// clean things up...
 | 
					
						
							|  |  |  | 	$('.overlay .content').children().remove() | 
					
						
							|  |  |  | 	// put it in the overlay...
 | 
					
						
							|  |  |  | 	$('.overlay .content').append(obj) | 
					
						
							|  |  |  | 	// prepare the overlay...
 | 
					
						
							|  |  |  | 	$('.overlay') | 
					
						
							|  |  |  | 		.one('click', function(){ | 
					
						
							|  |  |  | 			$('.overlay') | 
					
						
							|  |  |  | 				.fadeOut(function(){ | 
					
						
							|  |  |  | 					$('.overlay .content') | 
					
						
							|  |  |  | 						.children() | 
					
						
							|  |  |  | 							.remove() | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.fadeIn() | 
					
						
							|  |  |  | 	return obj | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-20 02:12:33 +04:00
										 |  |  | // XXX revise!!
 | 
					
						
							|  |  |  | function showOptionsUI(data, get_value, get_handler){ | 
					
						
							|  |  |  | 	var tree = {} | 
					
						
							|  |  |  | 	var groups = [] | 
					
						
							|  |  |  | 	var groups_ui = {} | 
					
						
							|  |  |  | 	// build the group/action structure...
 | 
					
						
							|  |  |  | 	for(var a in data){ | 
					
						
							|  |  |  | 		var group = data[a].group!=null?data[a].group:'Other' | 
					
						
							|  |  |  | 		if(groups.indexOf(group) == -1){ | 
					
						
							|  |  |  | 			groups.push(group) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(tree[group] == null){ | 
					
						
							|  |  |  | 			tree[group] = [] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		tree[group].push([ | 
					
						
							|  |  |  | 				data[a].title!=null?data[a].title:a,  | 
					
						
							|  |  |  | 				a | 
					
						
							|  |  |  | 		]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// sort things...
 | 
					
						
							|  |  |  | 	groups.sort() | 
					
						
							|  |  |  | 	for(var g in tree){ | 
					
						
							|  |  |  | 		tree[g].sort(function(a, b){ | 
					
						
							|  |  |  | 			a = a[0] | 
					
						
							|  |  |  | 			b = b[0] | 
					
						
							|  |  |  | 			return a > b ? 1 : a < b ? -1 : 0 | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// build the HTML...
 | 
					
						
							|  |  |  | 	var ui = $('<div class="options"/>') | 
					
						
							|  |  |  | 	for(var g in tree){ | 
					
						
							|  |  |  | 		var group = null | 
					
						
							|  |  |  | 		for(var i=0; i<tree[g].length; i++){ | 
					
						
							|  |  |  | 			// get the element...
 | 
					
						
							|  |  |  | 			var elem = data[tree[g][i][1]] | 
					
						
							|  |  |  | 			if(!DEBUG && elem.display == false){ | 
					
						
							|  |  |  | 				continue | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(group == null){ | 
					
						
							|  |  |  | 				group = $('<div class="group"/>') | 
					
						
							|  |  |  | 					.append($('<div class="title"/>').text(g)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var option | 
					
						
							|  |  |  | 			group.append( | 
					
						
							|  |  |  | 				option = $('<div class="option"/>').append($([ | 
					
						
							|  |  |  | 					$('<div class="title"/>').text(tree[g][i][0])[0], | 
					
						
							|  |  |  | 					$('<div class="doc"/>').html( | 
					
						
							|  |  |  | 						elem.doc?elem.doc.replace(/\n/g, '<br>'):'')[0], | 
					
						
							|  |  |  | 					$('<div class="value"/>').text(get_value(elem))[0] | 
					
						
							|  |  |  | 			]))) | 
					
						
							|  |  |  | 			if(elem.display == false){ | 
					
						
							|  |  |  | 				option.addClass('disabled') | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// handler...
 | 
					
						
							|  |  |  | 				var handler = get_handler(elem) | 
					
						
							|  |  |  | 				if(handler != null){ | 
					
						
							|  |  |  | 					option.click(handler) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(group != null){ | 
					
						
							|  |  |  | 			groups_ui[g] = group | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// put the Other group in the back...
 | 
					
						
							|  |  |  | 	var i = groups.indexOf('Other') | 
					
						
							|  |  |  | 	if(i != -1){ | 
					
						
							|  |  |  | 		groups.splice(i, 1) | 
					
						
							|  |  |  | 		groups.push('Other') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// buildup the sorted groups...
 | 
					
						
							|  |  |  | 	for(var i=0; i<groups.length; i++){ | 
					
						
							|  |  |  | 		ui.append(groups_ui[groups[i]]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// refresh...
 | 
					
						
							|  |  |  | 	ui.click(function(){ | 
					
						
							|  |  |  | 		// XXX is this a good way to do a refresh?
 | 
					
						
							|  |  |  | 		showOptionsUI(data, get_value, get_handler) | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	showInOverlay(ui) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | // Return a scale value for the given element(s).
 | 
					
						
							|  |  |  | // NOTE: this will only return a single scale value...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | function getElementScale(elem){ | 
					
						
							|  |  |  | 	//var transform = elem.css('transform')
 | 
					
						
							|  |  |  | 	var vendors = ['o', 'moz', 'ms', 'webkit'] | 
					
						
							|  |  |  | 	var transform = elem.css('transform') | 
					
						
							|  |  |  | 	var res | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// go through vendor prefixes... (hate this!)
 | 
					
						
							|  |  |  | 	if(!transform || transform == 'none'){ | 
					
						
							|  |  |  | 		for(var i in vendors){ | 
					
						
							|  |  |  | 			transform = elem.css('-' + vendors[i] + '-transform') | 
					
						
							|  |  |  | 			if(transform && transform != 'none'){ | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// no transform is set...
 | 
					
						
							|  |  |  | 	if(!transform || transform == 'none'){ | 
					
						
							|  |  |  | 		return 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// get the scale value -- first argument of scale/matrix...
 | 
					
						
							|  |  |  | 	return parseFloat((/(scale|matrix)\(([^,]*),.*\)/).exec(transform)[2]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setElementScale(elem, scale){ | 
					
						
							|  |  |  | 	return elem.css({ | 
					
						
							|  |  |  | 		'transform': 'scale('+scale+', '+scale+')', | 
					
						
							|  |  |  | 		'-moz-transform': 'scale('+scale+', '+scale+')', | 
					
						
							|  |  |  | 		'-o-transform': 'scale('+scale+', '+scale+')', | 
					
						
							|  |  |  | 		'-ms-transform': 'scale('+scale+', '+scale+')', | 
					
						
							|  |  |  | 		'-webkit-transform': 'scale('+scale+', '+scale+')', | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | // this will create a function that will add/remove a css_class to elem 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | // calling the optional callbacks before and/or after.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // elem is a jquery compatible object; default use-case: a css selector.
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | // the resulting function understands the folowing arguments:
 | 
					
						
							|  |  |  | // 	- 'on'			: switch mode on
 | 
					
						
							|  |  |  | // 	- 'off'			: switch mode off
 | 
					
						
							|  |  |  | // 	- '?'			: return current state ('on'|'off')
 | 
					
						
							|  |  |  | // 	- no arguments	: toggle the state
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // NOTE: of only one callback is given then it will be called after the 
 | 
					
						
							|  |  |  | // 		 class change...
 | 
					
						
							|  |  |  | // 		 a way around this is to pass an empty function as callback_b
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | function createCSSClassToggler(elem, css_class, callback_a, callback_b){ | 
					
						
							|  |  |  | 	// prepare the pre/post callbacks...
 | 
					
						
							|  |  |  | 	if(callback_b == null){ | 
					
						
							|  |  |  | 		var callback_pre = null | 
					
						
							|  |  |  | 		var callback_post = callback_a | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var callback_pre = callback_a | 
					
						
							|  |  |  | 		var callback_post = callback_b | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-08 06:21:00 +04:00
										 |  |  | 	// build the acual toggler function...
 | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	var func = function(action){ | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 		if(action == null || action == '?'){ | 
					
						
							|  |  |  | 			var getter = action == '?' ? true : false | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 			action = 'on' | 
					
						
							|  |  |  | 			// get current state...
 | 
					
						
							|  |  |  | 			if( $(elem).hasClass(css_class) ){ | 
					
						
							|  |  |  | 				action = 'off' | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 			if(getter){ | 
					
						
							|  |  |  | 				// as the above actions indicate intent and not state, 
 | 
					
						
							|  |  |  | 				// we'll need to swap the values...
 | 
					
						
							|  |  |  | 				return action == 'on' ? 'off' : 'on' | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if(callback_pre != null){ | 
					
						
							|  |  |  | 			callback_pre(action) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// play with the class...
 | 
					
						
							| 
									
										
										
										
											2012-08-08 01:57:04 +04:00
										 |  |  | 		if(action == 'on'){ | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 			$(elem).addClass(css_class) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			$(elem).removeClass(css_class) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if(callback_post != null){ | 
					
						
							|  |  |  | 			callback_post(action) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-15 02:15:37 +04:00
										 |  |  | 	func.doc = 'With no arguments this will toggle between "on" and '+ | 
					
						
							|  |  |  | 		'"off".\n'+ | 
					
						
							|  |  |  | 		'If either "on" or "off" are given then this will switch '+ | 
					
						
							|  |  |  | 		'to that mode.\n'+ | 
					
						
							|  |  |  | 		'If "?" is given, this will return either "on" or "off" '+ | 
					
						
							|  |  |  | 		'depending on the current state.' | 
					
						
							|  |  |  | 	return func | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // disable transitions on obj, call func then enable transitions back...
 | 
					
						
							|  |  |  | function doWithoutTransitions(obj, func){ | 
					
						
							|  |  |  | 	obj | 
					
						
							|  |  |  | 		.addClass('unanimated') | 
					
						
							|  |  |  | 		.one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", function(){ | 
					
						
							|  |  |  | 			func() | 
					
						
							|  |  |  | 			$('.viewer') | 
					
						
							|  |  |  | 				.one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", function(){ | 
					
						
							|  |  |  | 					obj.removeClass('unanimated') | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | function clickAfterTransitionsDone(img){ | 
					
						
							|  |  |  | 	if(img == null){ | 
					
						
							|  |  |  | 		img = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	$('.viewer') | 
					
						
							|  |  |  | 		.one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", function(){ | 
					
						
							|  |  |  | 			img.click() | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | // find an image object after which to position image ID...
 | 
					
						
							|  |  |  | // used for two main tasks:
 | 
					
						
							|  |  |  | // 	- positioning promoted/demoted images
 | 
					
						
							|  |  |  | // 	- centering ribbons
 | 
					
						
							|  |  |  | // returns:
 | 
					
						
							|  |  |  | // 	- null		- empty ribbon or no element greater id should be first
 | 
					
						
							|  |  |  | // 	- element
 | 
					
						
							|  |  |  | // XXX do we need to make ids numbers for this to work?
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function getImageBefore_lin(id, ribbon, get_order){ | 
					
						
							|  |  |  | 	if(get_order == null){ | 
					
						
							|  |  |  | 		get_order = getImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 	// walk the ribbon till we find two images one with an ID less and 
 | 
					
						
							|  |  |  | 	// another greater that id...
 | 
					
						
							|  |  |  | 	var images = ribbon.children('.image') | 
					
						
							|  |  |  | 	var prev = null | 
					
						
							|  |  |  | 	for(var i=0; i < images.length; i++){ | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | 		// XXX replace the id attr with a universal getter
 | 
					
						
							|  |  |  | 		if(get_order(images[i]) > id){ | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 			return prev | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		prev = $(images[i]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return prev | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // generic binery search for element just before the id...
 | 
					
						
							|  |  |  | // NOTE: if id is in lst, this will return the element just before it.
 | 
					
						
							|  |  |  | // NOTE: lst must be sorted.
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function binarySearch(id, lst, get_order){ | 
					
						
							|  |  |  | 	if(get_order == null){ | 
					
						
							|  |  |  | 		get_order = function(o){return o} | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// empty list...
 | 
					
						
							|  |  |  | 	if(lst.length == 0){ | 
					
						
							|  |  |  | 		return null | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	// current section length
 | 
					
						
							|  |  |  | 	var l = Math.round((lst.length-1)/2) | 
					
						
							|  |  |  | 	// current position...
 | 
					
						
							|  |  |  | 	var i = l | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	while(true){ | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | 		var i_id = get_order(lst[i]) | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 		// beginning of the array...
 | 
					
						
							|  |  |  | 		if(i == 0){ | 
					
						
							|  |  |  | 			if(id > i_id){ | 
					
						
							|  |  |  | 				return i | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return null | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// we got a hit...
 | 
					
						
							|  |  |  | 		if(i_id == id){ | 
					
						
							|  |  |  | 			return i-1 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// we are at the end...
 | 
					
						
							|  |  |  | 		if(i == lst.length-1 && id > i_id){ | 
					
						
							|  |  |  | 			return i | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | 		var ii_id = get_order(lst[i+1]) | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 		// test if id is between i and i+1...
 | 
					
						
							|  |  |  | 		if( i_id < id && id < ii_id ){ | 
					
						
							|  |  |  | 			return i | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// prepare for next iteration...
 | 
					
						
							|  |  |  | 		// NOTE: we saturate the values so we will never get out of bounds.
 | 
					
						
							|  |  |  | 		l = Math.round(l/2) | 
					
						
							|  |  |  | 		if(id < i_id){ | 
					
						
							|  |  |  | 			// lower half...
 | 
					
						
							|  |  |  | 			i = Math.max(0, i-l) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			// upper half...
 | 
					
						
							|  |  |  | 			i = Math.min(i+l, lst.length-1) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // wrapper around binarySearch.
 | 
					
						
							|  |  |  | // this is here to make binarySearch simpler to test and debug...
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function getImageBefore_bin(id, ribbon, get_order){ | 
					
						
							|  |  |  | 	if(get_order == null){ | 
					
						
							|  |  |  | 		get_order = getImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 	var images = ribbon.children('.image')  | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | 	var i = binarySearch(id, images, get_order) | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 	if(i == null){ | 
					
						
							|  |  |  | 		return null | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return $(images[i]) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // set the default search...
 | 
					
						
							|  |  |  | var getImageBefore = getImageBefore_bin | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | /* | 
					
						
							|  |  |  |  * The folowing two functions will get the vertical and horizontal  | 
					
						
							|  |  |  |  * distance components between the points a and A, centers of the small | 
					
						
							|  |  |  |  * and large squares respectively. | 
					
						
							|  |  |  |  * One of the squares is .field and the other is .container,  | 
					
						
							|  |  |  |  * which is small or big is not important. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *      +---------------+-------+ | 
					
						
							|  |  |  |  *      |               |       | | 
					
						
							|  |  |  |  *      |               |       | | 
					
						
							|  |  |  |  *      |       + a . . | . . . | . + | 
					
						
							|  |  |  |  *      |       .       |       |   +- getCurrentVerticalOffset(...) | 
					
						
							|  |  |  |  *      |       .   + A | . . . | . + | 
					
						
							|  |  |  |  *      +---------------+       | | 
					
						
							|  |  |  |  *      |       .   .           | | 
					
						
							|  |  |  |  *      |       .   .           | | 
					
						
							|  |  |  |  *      |       .   .           | | 
					
						
							|  |  |  |  *      +-----------------------+ | 
					
						
							|  |  |  |  *              .   . | 
					
						
							|  |  |  |  *              +-+-+ | 
					
						
							|  |  |  |  *                +------------------- getCurrentHorizontalOffset(...) | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Adding this distance to margins of one of the sqares will effectively  | 
					
						
							|  |  |  |  * allign the two points. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * NOTE: neither function accunts for field margins. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | // get the vertical offset of the center of square from center of container
 | 
					
						
							|  |  |  | // NOTE: this does not account for field margins
 | 
					
						
							|  |  |  | function getCurrentVerticalOffset(image){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.image.current') | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-06 16:24:20 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	var scale = getElementScale($('.field')) | 
					
						
							| 
									
										
										
										
											2012-08-06 16:24:20 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	var ribbons = $('.ribbon') | 
					
						
							|  |  |  | 	var ribbon = image.parents('.ribbon') | 
					
						
							|  |  |  | 	var images = ribbon.children('.image') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// vertical...
 | 
					
						
							|  |  |  | 	var H = $('.container').height() | 
					
						
							|  |  |  | 	var h = ribbons.outerHeight(true) | 
					
						
							|  |  |  | 	// margin...
 | 
					
						
							|  |  |  | 	var mh = h - ribbons.outerHeight() | 
					
						
							|  |  |  | 	// current ribbon position (1-based)
 | 
					
						
							|  |  |  | 	var rn = ribbons.index(ribbon) + 1 | 
					
						
							|  |  |  | 	// relative position to field... 
 | 
					
						
							|  |  |  | 	// XXX is there a better way to get this?
 | 
					
						
							|  |  |  | 	var t = rn * (h - mh/2) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	return -t + H/2 + h/2 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | // get the horizontal offset of the center of square from center of container
 | 
					
						
							|  |  |  | // NOTE: this does not account for field margins
 | 
					
						
							|  |  |  | function getCurrentHorizontalOffset(image){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.image.current') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	var ribbon = image.parents('.ribbon') | 
					
						
							|  |  |  | 	var images = ribbon.children('.image') | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	var W = $('.container').width() | 
					
						
							|  |  |  | 	var w = images.outerWidth(true) | 
					
						
							|  |  |  | 	// margin...
 | 
					
						
							|  |  |  | 	var mw = w - images.outerWidth() | 
					
						
							|  |  |  | 	// current square position (1-based)
 | 
					
						
							|  |  |  | 	var sn = images.index(image) + 1 | 
					
						
							|  |  |  | 	var l = sn * (w - mw/2) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return -l + W/2 + w/2 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-22 19:39:20 +04:00
										 |  |  | // XXX some minor inacuracies...
 | 
					
						
							|  |  |  | function centerIndicator(){ | 
					
						
							|  |  |  | 	// XXX something odd going on with the border here...
 | 
					
						
							|  |  |  | 	var i_border = Math.abs($('.current-indicator').outerHeight() - $('.current-indicator').height())/2 | 
					
						
							|  |  |  | 	$('.current-indicator').css({ | 
					
						
							|  |  |  | 		'top': ($('.ribbon').index($('.current.ribbon'))) * $('.ribbon').outerHeight() - i_border,  | 
					
						
							|  |  |  | 		'left': ($('.viewer').outerWidth() - $('.current-indicator').outerWidth())/2, | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | function centerSquare(){ | 
					
						
							|  |  |  | 	$('.field').css({ | 
					
						
							|  |  |  | 		'margin-top': getCurrentVerticalOffset() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// horizontal...
 | 
					
						
							|  |  |  | 	alignRibbon() | 
					
						
							|  |  |  | 	ImageGrid.centerCurrentImage() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function alignRibbon(image, position){ | 
					
						
							|  |  |  | 	// default values...
 | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.image.current') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if(position == null){ | 
					
						
							|  |  |  | 		position = 'center' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ribbon = image.parents('.ribbon') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// account for margined field...
 | 
					
						
							|  |  |  | 	// NOTE: this enables us to cheat and shift all the ribbons just
 | 
					
						
							|  |  |  | 	//       by changing field margin-left...
 | 
					
						
							|  |  |  | 	var cml = parseFloat($('.field').css('margin-left')) | 
					
						
							|  |  |  | 	if(!cml){ | 
					
						
							|  |  |  | 		cml = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var h_offset = getCurrentHorizontalOffset(image) - cml | 
					
						
							|  |  |  | 	var w = $('.image').outerWidth(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch(position){ | 
					
						
							|  |  |  | 		case 'before': | 
					
						
							|  |  |  | 			ribbon.css({'margin-left': h_offset - w/2}) | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		case 'center': | 
					
						
							|  |  |  | 			ribbon.css({'margin-left': h_offset}) | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		case 'after': | 
					
						
							|  |  |  | 			ribbon.css({'margin-left': h_offset + w/2}) | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // center other ribbons relative to current image...
 | 
					
						
							|  |  |  | // NOTE: only two ribbons are positioned at this point...
 | 
					
						
							|  |  |  | function alignRibbons(get_order){ | 
					
						
							|  |  |  | 	if(get_order == null){ | 
					
						
							|  |  |  | 		get_order = getImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// XXX might be good to move this to a more generic location...
 | 
					
						
							|  |  |  | 	var id = get_order($('.current.image')) | 
					
						
							|  |  |  | 	var directions = ['prev', 'next'] | 
					
						
							|  |  |  | 	for(var i in directions){ | 
					
						
							|  |  |  | 		var ribbon = $('.current.ribbon')[directions[i]]('.ribbon') | 
					
						
							|  |  |  | 		if(ribbon.length == 1){ | 
					
						
							|  |  |  | 			var img = getImageBefore(id, ribbon) | 
					
						
							|  |  |  | 			if(img != null){ | 
					
						
							|  |  |  | 				alignRibbon(img, 'before') | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				// there are no images before...
 | 
					
						
							|  |  |  | 				alignRibbon(ribbon.children('.image').first(), 'after') | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /************************************************** Setup Functions **/ | 
					
						
							|  |  |  | // XXX is this a correct place for these?
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setDefaultInitialState(){ | 
					
						
							|  |  |  | 	if($('.current.ribbon').length == 0){ | 
					
						
							|  |  |  | 		$('.ribbon').first().addClass('current') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if($('.current.image').length == 0){ | 
					
						
							|  |  |  | 		$('.current.ribbon').children('.image').first().addClass('current') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setupEvents(){ | 
					
						
							|  |  |  | 	// resize...
 | 
					
						
							|  |  |  | 	$(window).resize(function() { | 
					
						
							|  |  |  | 		// XXX HACK
 | 
					
						
							|  |  |  | 		$('.current.image').click() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 	// keyboard...
 | 
					
						
							|  |  |  | 	if(DEBUG){ | 
					
						
							|  |  |  | 		$(document) | 
					
						
							|  |  |  | 			.keydown(makeKeyboardHandler(keybindings, function(k){alert(k)})) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		$(document) | 
					
						
							|  |  |  | 			.keydown(makeKeyboardHandler(keybindings)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// swipe...
 | 
					
						
							|  |  |  | 	$('.viewer') | 
					
						
							|  |  |  | 		.swipe({ | 
					
						
							|  |  |  | 			swipeLeft: ImageGrid.nextImage, | 
					
						
							|  |  |  | 			swipeRight: ImageGrid.prevImage, | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 			swipeUp: ImageGrid.shiftImageUp, | 
					
						
							|  |  |  | 			swipeDown: ImageGrid.shiftImageDown | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 	// dragging...
 | 
					
						
							|  |  |  | 	// XXX make this work seamlessly with touchSwipe...
 | 
					
						
							|  |  |  | 	// XXX cancel clicks while dragging...
 | 
					
						
							|  |  |  | 	// XXX this does not work on android...
 | 
					
						
							|  |  |  | 	$('.field').draggable() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setupControlElements(){ | 
					
						
							|  |  |  | 	// images...
 | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 	// NOTE: when the images are loaded, the actual handlers will be set by the loader...
 | 
					
						
							|  |  |  | 	setupImageEventHandlers($(".image")) | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-22 21:46:37 +04:00
										 |  |  | 	// make the indicator active...
 | 
					
						
							|  |  |  | 	$(".current-indicator div") | 
					
						
							|  |  |  | 		.click(function(){ | 
					
						
							|  |  |  | 			$('.current.image').click() | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.dblclick(function(){ | 
					
						
							|  |  |  | 			ImageGrid.toggleSingleImageMode() | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 	// buttons...
 | 
					
						
							| 
									
										
										
										
											2012-08-22 00:06:54 +04:00
										 |  |  | 	$('.screen-button.next-image').mousedown(ImageGrid.nextImage) | 
					
						
							|  |  |  | 	$('.screen-button.prev-image').mousedown(ImageGrid.prevImage) | 
					
						
							| 
									
										
										
										
											2012-08-08 01:45:22 +04:00
										 |  |  | 	// XXX rename classes to "shift-image-up" and "shift-image-down"...
 | 
					
						
							| 
									
										
										
										
											2012-08-22 00:06:54 +04:00
										 |  |  | 	$('.screen-button.demote').mousedown(ImageGrid.shiftImageUp) | 
					
						
							|  |  |  | 	$('.screen-button.promote').mousedown(ImageGrid.shiftImageDown) | 
					
						
							|  |  |  | 	$('.screen-button.zoom-in').mousedown(ImageGrid.scaleContainerUp) | 
					
						
							|  |  |  | 	$('.screen-button.zoom-out').mousedown(ImageGrid.scaleContainerDown) | 
					
						
							| 
									
										
										
										
											2012-08-15 04:03:11 +04:00
										 |  |  | 	// XXX
 | 
					
						
							| 
									
										
										
										
											2012-08-22 00:06:54 +04:00
										 |  |  | 	$('.screen-button.toggle-wide').mousedown(function(){ImageGrid.scaleContainerBy(0.2)}) | 
					
						
							|  |  |  | 	$('.screen-button.toggle-single').mousedown(ImageGrid.toggleSingleImageMode) | 
					
						
							|  |  |  | 	$('.screen-button.fit-three').mousedown(ImageGrid.fitThreeImages) | 
					
						
							|  |  |  | 	$('.screen-button.show-controls').mousedown(function(){ImageGrid.toggleControls('on')}) | 
					
						
							|  |  |  | 	$('.screen-button.settings').mousedown(ImageGrid.showKeyboardBindings) | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-16 21:52:23 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | /**************************************************** Serialization **/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | // setup image event handlers...
 | 
					
						
							|  |  |  | function setupImageEventHandlers(image){ | 
					
						
							|  |  |  | 	return (image | 
					
						
							|  |  |  | 			.click(handleImageClick) | 
					
						
							|  |  |  | 			.dblclick(function(e){ | 
					
						
							|  |  |  | 				$(this).click() | 
					
						
							|  |  |  | 				ImageGrid.toggleSingleImageMode() | 
					
						
							|  |  |  | 			})) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // build an image element...
 | 
					
						
							|  |  |  | function makeImage(url, order, set_order){ | 
					
						
							|  |  |  | 	if(set_order == null){ | 
					
						
							|  |  |  | 		set_order = setImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return (setupImageEventHandlers( | 
					
						
							|  |  |  | 				set_order($('<div class="image"></div>') | 
					
						
							|  |  |  | 					.css({ 'background-image': 'url('+url+')' }), order))) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | function loadImages(json){ | 
					
						
							|  |  |  | 	var images = json.images | 
					
						
							|  |  |  | 	var ribbon = $('.ribbon').last() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	$('.image').remove() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	for(var i = 0; i < images.length; i++){ | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 		makeImage(images[i], i) | 
					
						
							|  |  |  | 			.appendTo(ribbon) | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ribbon.children().first().click() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-16 21:52:23 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-09 17:53:07 +04:00
										 |  |  | /* bulid a JSON object from current state... | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  |  * format: | 
					
						
							|  |  |  |  * 	{ | 
					
						
							|  |  |  |  * 		ribbons: [ | 
					
						
							| 
									
										
										
										
											2012-08-09 17:53:07 +04:00
										 |  |  |  * 			<image-id>: { | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  |  * 				url: <image-URL>, | 
					
						
							|  |  |  |  * 			},				 | 
					
						
							|  |  |  |  * 			... | 
					
						
							|  |  |  |  * 		] | 
					
						
							|  |  |  |  * 	} | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2012-08-11 03:38:42 +04:00
										 |  |  | // XXX add incremental or partial updates...
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | function buildJSON(get_order){ | 
					
						
							|  |  |  | 	if(get_order == null){ | 
					
						
							|  |  |  | 		get_order = getImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 	var ribbons = $('.ribbon') | 
					
						
							|  |  |  | 	res = { | 
					
						
							|  |  |  | 		ribbons: [] | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	for(var i=0; i < ribbons.length; i++){ | 
					
						
							|  |  |  | 		var images = $(ribbons[i]).children('.image') | 
					
						
							| 
									
										
										
										
											2012-08-09 17:53:07 +04:00
										 |  |  | 		var ribbon = {} | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 		res.ribbons[res.ribbons.length] = ribbon | 
					
						
							|  |  |  | 		for(var j=0; j < images.length; j++){ | 
					
						
							|  |  |  | 			var image = $(images[j]) | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | 			var id = get_order(image) | 
					
						
							| 
									
										
										
										
											2012-08-09 06:29:29 +04:00
										 |  |  | 			ribbon[id] = { | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 				// unwrap the url...
 | 
					
						
							| 
									
										
										
										
											2012-08-11 03:38:42 +04:00
										 |  |  | 				// XXX would be nice to make this a relative path... (???)
 | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 				url: /url\((.*)\)/.exec(image.css('background-image'))[1], | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  | // XXX use this instead of loadImages(...)
 | 
					
						
							| 
									
										
										
										
											2012-08-09 17:53:07 +04:00
										 |  |  | // XXX might be good to add images in packs here, not one by one...
 | 
					
						
							| 
									
										
										
										
											2012-08-11 02:59:11 +04:00
										 |  |  | function loadJSON(data, set_order){ | 
					
						
							|  |  |  | 	if(set_order == null){ | 
					
						
							|  |  |  | 		set_order = setImageOrder | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 	var ribbons = data.ribbons | 
					
						
							|  |  |  | 	var field = $('.field') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// drop all old content...
 | 
					
						
							| 
									
										
										
										
											2012-08-22 19:39:20 +04:00
										 |  |  | 	field.children('.ribbon').remove() | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	for(var i=0; i < ribbons.length; i++){ | 
					
						
							|  |  |  | 		var images = ribbons[i] | 
					
						
							|  |  |  | 		// create ribbon...
 | 
					
						
							|  |  |  | 		var ribbon = $('<div class="ribbon"></div>') | 
					
						
							|  |  |  | 			.appendTo(field) | 
					
						
							| 
									
										
										
										
											2012-08-09 17:53:07 +04:00
										 |  |  | 		for(var j in images){ | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 			var image = $(images[j]) | 
					
						
							|  |  |  | 			// create image...
 | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 			makeImage(image.attr('url'), j, set_order) | 
					
						
							|  |  |  | 				.appendTo(ribbon) | 
					
						
							| 
									
										
										
										
											2012-08-09 06:25:09 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	$('.image').first().click() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | /*************************************************** Event Handlers **/ | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | // handle click for images...
 | 
					
						
							|  |  |  | function handleImageClick(){ | 
					
						
							| 
									
										
										
										
											2012-07-24 15:38:54 +04:00
										 |  |  | 	// set classes...
 | 
					
						
							|  |  |  | 	$('.current').removeClass('current') | 
					
						
							|  |  |  | 	$(this) | 
					
						
							|  |  |  | 		.addClass('current') | 
					
						
							|  |  |  | 		.parents('.ribbon') | 
					
						
							|  |  |  | 			.addClass('current') | 
					
						
							|  |  |  | 	// position the field and ribbons...
 | 
					
						
							|  |  |  | 	centerSquare() | 
					
						
							| 
									
										
										
										
											2012-08-22 19:39:20 +04:00
										 |  |  | 	centerIndicator() | 
					
						
							| 
									
										
										
										
											2012-07-31 17:41:54 +04:00
										 |  |  | 	alignRibbons() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:42:14 +04:00
										 |  |  | // if set to false the event handlers will always return false...
 | 
					
						
							|  |  |  | var KEYBOARD_HANDLER_PROPAGATE = false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* Basic key format: | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  |  * 		<key-code> : <callback>, | 
					
						
							|  |  |  |  * 		<key-code> : { | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  |  * 			'default': <callback>, | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  |  *			// a modifier can be any single modifier, like shift or a 
 | 
					
						
							|  |  |  |  *			// combination of modifers like 'ctrl+shift', given in order 
 | 
					
						
							|  |  |  |  *			// of priority.
 | 
					
						
							|  |  |  |  *			// supported modifiers are (in order of priority):
 | 
					
						
							|  |  |  |  *			//	- ctrl
 | 
					
						
							|  |  |  |  *			//	- alt
 | 
					
						
							|  |  |  |  *			//	- shift
 | 
					
						
							|  |  |  |  * 			<modifer>: [...] | 
					
						
							|  |  |  |  * 		}, | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  |  * 		<key-code> : [ | 
					
						
							|  |  |  |  *			// this can be any type of handler except for an alias...
 | 
					
						
							|  |  |  |  * 			<handler>,  | 
					
						
							|  |  |  |  * 			<doc> | 
					
						
							|  |  |  |  * 		], | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  |  *		// alias...
 | 
					
						
							|  |  |  |  * 		<key-code-a> : <key-code-b>, | 
					
						
							| 
									
										
										
										
											2012-08-10 20:25:49 +04:00
										 |  |  |  * | 
					
						
							|  |  |  |  * XXX might need to add meta information to generate sensible help... | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  |  */ | 
					
						
							|  |  |  | function makeKeyboardHandler(keybindings, unhandled){ | 
					
						
							|  |  |  | 	if(unhandled == null){ | 
					
						
							|  |  |  | 		unhandled = function(){return false} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return function(evt){ | 
					
						
							|  |  |  | 		var key = evt.keyCode | 
					
						
							|  |  |  | 		// XXX ugly...
 | 
					
						
							|  |  |  | 		var modifers = evt.ctrlKey ? 'ctrl' : '' | 
					
						
							|  |  |  | 		modifers += evt.altKey ? (modifers != '' ? '+alt' : 'alt') : '' | 
					
						
							|  |  |  | 		modifers += evt.shiftKey ? (modifers != '' ? '+shift' : 'shift') : '' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		var handler = keybindings[key] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// alias...
 | 
					
						
							|  |  |  | 		while (typeof(handler) == typeof(123)) { | 
					
						
							|  |  |  | 			handler = keybindings[handler] | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// no handler...
 | 
					
						
							|  |  |  | 		if(handler == null){ | 
					
						
							|  |  |  | 			return unhandled(key) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 		// Array, lisp style with docs...
 | 
					
						
							|  |  |  | 		// XXX for some odd reason in chrome typeof([]) == typeof({})!!!
 | 
					
						
							|  |  |  | 		if(typeof(handler) == typeof([]) && handler.constructor.name == 'Array'){ | 
					
						
							|  |  |  | 			// we do not care about docs here, so just get the handler...
 | 
					
						
							|  |  |  | 			handler = handler[0] | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  | 		// complex handler...
 | 
					
						
							|  |  |  | 		if(typeof(handler) == typeof({})){ | 
					
						
							|  |  |  | 			var callback = handler[modifers] | 
					
						
							|  |  |  | 			if(callback == null){ | 
					
						
							|  |  |  | 				callback = handler['default'] | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  | 			if(callback != null){ | 
					
						
							| 
									
										
										
										
											2012-08-17 07:30:03 +04:00
										 |  |  | 				var res = callback() | 
					
						
							| 
									
										
										
										
											2012-08-19 21:42:14 +04:00
										 |  |  | 				return KEYBOARD_HANDLER_PROPAGATE&&res?true:false | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2012-08-10 19:40:26 +04:00
										 |  |  | 			// simple callback...
 | 
					
						
							| 
									
										
										
										
											2012-08-17 07:30:03 +04:00
										 |  |  | 			var res = handler()  | 
					
						
							| 
									
										
										
										
											2012-08-19 21:42:14 +04:00
										 |  |  | 			return KEYBOARD_HANDLER_PROPAGATE&&res?true:false | 
					
						
							| 
									
										
										
										
											2012-08-08 23:19:40 +04:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return unhandled(key) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-16 21:52:23 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | /************************************************ Mode & UI Actions **/ | 
					
						
							| 
									
										
										
										
											2012-08-14 22:08:18 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | ImageGrid.GROUP('Mode: All', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Get the background mode', | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function getBackgroundMode(){ | 
					
						
							|  |  |  | 			var mode = null | 
					
						
							|  |  |  | 			var BACKGROUND_MODES = ImageGrid.option.BACKGROUND_MODES | 
					
						
							|  |  |  | 			// find a mode to set...
 | 
					
						
							|  |  |  | 			for(var i = 0; i < BACKGROUND_MODES.length; i++){ | 
					
						
							|  |  |  | 				// we found our mode...
 | 
					
						
							|  |  |  | 				if( $('.' + BACKGROUND_MODES[i]).length > 0 ){ | 
					
						
							|  |  |  | 					return BACKGROUND_MODES[i] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return mode | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Set the background mode', | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			doc: 'NOTE: passing null will set the default.', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function setBackgroundMode(mode){ | 
					
						
							|  |  |  | 			var BACKGROUND_MODES = ImageGrid.option.BACKGROUND_MODES | 
					
						
							|  |  |  | 			var cur = BACKGROUND_MODES.indexOf(mode) | 
					
						
							| 
									
										
										
										
											2012-08-05 22:06:52 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 			// invalid mode...
 | 
					
						
							|  |  |  | 			if( cur == -1 && mode != null ){ | 
					
						
							|  |  |  | 				return null | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// set the mode...
 | 
					
						
							|  |  |  | 			if(mode != null){ | 
					
						
							|  |  |  | 				$('.viewer').addClass(mode) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// remove all others...
 | 
					
						
							|  |  |  | 			for(var i = 0; i < BACKGROUND_MODES.length; i++){ | 
					
						
							|  |  |  | 				if( i == cur ){ | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				mode = BACKGROUND_MODES[i] | 
					
						
							|  |  |  | 				$('.' + mode).removeClass(mode) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Toggle background modes', | 
					
						
							|  |  |  | 			doc: 'Toggle through background theems: none -> dark -> black\n\n'+ | 
					
						
							|  |  |  | 				'NOTE: modes are toggled independently for single image and '+ | 
					
						
							|  |  |  | 				'rinbon modes', | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 			type: 'toggle', | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 		function toggleBackgroundModes(action){ | 
					
						
							|  |  |  | 			if(action == '?'){ | 
					
						
							|  |  |  | 				return ImageGrid.getBackgroundMode() | 
					
						
							|  |  |  | 			} else if(action != null){ | 
					
						
							|  |  |  | 				return ImageGrid.setBackgroundMode(action) | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 				var BACKGROUND_MODES = ImageGrid.option.BACKGROUND_MODES | 
					
						
							|  |  |  | 				var mode = ImageGrid.getBackgroundMode() | 
					
						
							|  |  |  | 				// default -> first
 | 
					
						
							|  |  |  | 				if(mode == null){ | 
					
						
							|  |  |  | 					ImageGrid.setBackgroundMode(BACKGROUND_MODES[0]) | 
					
						
							|  |  |  | 				// last -> default...
 | 
					
						
							|  |  |  | 				} else if(mode == BACKGROUND_MODES[BACKGROUND_MODES.length-1]){ | 
					
						
							|  |  |  | 					ImageGrid.setBackgroundMode() | 
					
						
							|  |  |  | 				// next...
 | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					ImageGrid.setBackgroundMode(BACKGROUND_MODES[BACKGROUND_MODES.indexOf(mode)+1]) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-05 22:06:52 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleControls', | 
					
						
							| 
									
										
										
										
											2012-08-19 23:18:11 +04:00
										 |  |  | 			title: 'Toggle keyboard-oriented interface', | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 			doc: 'Toggle Touch/Keyboard UI controls.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'hidden-controls')), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleTransitions', | 
					
						
							|  |  |  | 			title: 'Global transitions', | 
					
						
							|  |  |  | 			doc: 'Toggle global transitions.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 		createCSSClassToggler('.viewer', 'transitions-enabled'))) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | ImageGrid.GROUP('Configuration and Help', | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Close overlay' | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function closeOverlay(){ $('.overlay').click() }), | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 	// XXX use order and priority of options...
 | 
					
						
							|  |  |  | 	// XXX make history work for this...
 | 
					
						
							|  |  |  | 	// XXX should this be a toggle??
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Settings', | 
					
						
							|  |  |  | 			doc: 'Show setup interface.', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function showSetup(){ | 
					
						
							| 
									
										
										
										
											2012-08-20 02:12:33 +04:00
										 |  |  | 			showOptionsUI(ImageGrid.option_props,  | 
					
						
							| 
									
										
										
										
											2012-08-22 02:00:23 +04:00
										 |  |  | 					function(e){ | 
					
						
							|  |  |  | 						// XXX need to update a value here...
 | 
					
						
							|  |  |  | 						return ImageGrid.option[e.name] | 
					
						
							|  |  |  | 					},  | 
					
						
							| 
									
										
										
										
											2012-08-20 01:06:08 +04:00
										 |  |  | 					function(e){return e.click_handler}) | 
					
						
							| 
									
										
										
										
											2012-08-20 02:12:33 +04:00
										 |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Keyboard configuration', | 
					
						
							|  |  |  | 			doc: 'Show keyboard configuration interface.', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function showKeyboardBindings(){ | 
					
						
							|  |  |  | 			// build reverse key index...
 | 
					
						
							|  |  |  | 			var bindings = {} | 
					
						
							|  |  |  | 			for(var k in keybindings){ | 
					
						
							|  |  |  | 				var id | 
					
						
							|  |  |  | 				var v = keybindings[k] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// alias...
 | 
					
						
							|  |  |  | 				while (typeof(v) == typeof(123)) { | 
					
						
							|  |  |  | 					v = keybindings[v] | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// Array, lisp style with docs...
 | 
					
						
							|  |  |  | 				if(typeof(v) == typeof([]) && v.constructor.name == 'Array'){ | 
					
						
							|  |  |  | 					// XXX what do we do here???
 | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// function...
 | 
					
						
							|  |  |  | 				if(typeof(v) == typeof(function(){})){ | 
					
						
							|  |  |  | 					id = v.id != null ? v.id : v.name | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// complex handler...
 | 
					
						
							|  |  |  | 				// NOTE: this can contain several key bindings...
 | 
					
						
							|  |  |  | 				if(typeof(v) == typeof({})){ | 
					
						
							|  |  |  | 					for(var m in v){ | 
					
						
							|  |  |  | 						id = v[m].id != null ? v[m].id : v[m].name | 
					
						
							|  |  |  | 						if(bindings[id] == null){ | 
					
						
							|  |  |  | 							bindings[id] = [] | 
					
						
							|  |  |  | 						}  | 
					
						
							|  |  |  | 						bindings[id].push((m=='default'?'':m+'+') + toKeyName(k)) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					continue | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(bindings[id] == null){ | 
					
						
							|  |  |  | 					bindings[id] = [] | 
					
						
							|  |  |  | 				}  | 
					
						
							|  |  |  | 				bindings[id].push(toKeyName(k)) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			showOptionsUI(ImageGrid.actions,  | 
					
						
							|  |  |  | 					function(e){  | 
					
						
							|  |  |  | 						return (bindings[e.id]!=null?bindings[e.id]:'None') | 
					
						
							|  |  |  | 									.toString() | 
					
						
							|  |  |  | 									.replace(/,/g, ', ')  | 
					
						
							|  |  |  | 					},  | 
					
						
							|  |  |  | 					// XXX
 | 
					
						
							|  |  |  | 					function(e){}) | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | ImageGrid.GROUP('Mode: Single Image', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleSingleImageMode', | 
					
						
							|  |  |  | 			title: 'Single image mode', | 
					
						
							|  |  |  | 			doc: 'Toggle single image mode.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'single-image-mode',  | 
					
						
							|  |  |  | 			// pre...
 | 
					
						
							|  |  |  | 			function(action){ | 
					
						
							|  |  |  | 				if(action == 'on'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.option.NORMAL_MODE_BG = ImageGrid.getBackgroundMode() | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 					ImageGrid.option.ORIGINAL_FIELD_SCALE = getElementScale($('.field')) | 
					
						
							|  |  |  | 				// do this only when coming out of single image mode...
 | 
					
						
							|  |  |  | 				} else if(ImageGrid.toggleSingleImageMode('?') == 'on'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.option.SINGLE_IMAGE_MODE_BG = ImageGrid.getBackgroundMode() | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 			}, | 
					
						
							|  |  |  | 			// post...
 | 
					
						
							|  |  |  | 			function(action){ | 
					
						
							|  |  |  | 				if(action == 'on'){ | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 					ImageGrid.fitImage() | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.setBackgroundMode(ImageGrid.option.SINGLE_IMAGE_MODE_BG) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 					ImageGrid.setContainerScale(ImageGrid.option.ORIGINAL_FIELD_SCALE) | 
					
						
							| 
									
										
										
										
											2012-08-19 20:32:37 +04:00
										 |  |  | 					ImageGrid.setBackgroundMode(ImageGrid.option.NORMAL_MODE_BG) | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 				clickAfterTransitionsDone() | 
					
						
							|  |  |  | 			})), | 
					
						
							|  |  |  | 	// XXX for some reason this is backwords... (says 'on' when it's off ans 'off' when on)
 | 
					
						
							|  |  |  | 	// 		...and needs an extra click to sync with state...
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleSingleImageModeTransitions', | 
					
						
							|  |  |  | 			title: 'Disable single image mode transitions', | 
					
						
							|  |  |  | 			doc: 'Toggle transitions in single image mode.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'no-single-image-transitions'))) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | ImageGrid.GROUP('Mode: Ribbon', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleSingleRibbonMode', | 
					
						
							|  |  |  | 			title: 'Single ribbon mode', | 
					
						
							|  |  |  | 			doc: 'Show/hide other ribbons.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		},  | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'single-ribbon-mode')), | 
					
						
							| 
									
										
										
										
											2012-08-22 19:39:20 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleCurrentRibbonOpacity', | 
					
						
							|  |  |  | 			title: 'Current ribbon opacity', | 
					
						
							|  |  |  | 			doc: 'Toggle other image transparancy/opacity in current ribbon.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		},  | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'opaque-current-ribbon')), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleIndicatorDot', | 
					
						
							|  |  |  | 			title: 'Dot indicator', | 
					
						
							|  |  |  | 			doc: 'Toggle indicator between dot and frame modes.\n\n'+ | 
					
						
							|  |  |  | 					'NOTE: this is visible only when the indicator is visible.', | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		},  | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'dot-indicator')), | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX this can be done in two ways:
 | 
					
						
							|  |  |  | 	// 		- keep all images when promoting, just add a class to them that 
 | 
					
						
							|  |  |  | 	// 		  will hide them until we enable their display...
 | 
					
						
							|  |  |  | 	// 		  	+ very fast to show/hide
 | 
					
						
							|  |  |  | 	// 		  	- will complicate reversing ribbons allot
 | 
					
						
							|  |  |  | 	// 		- add/remove these images on demand
 | 
					
						
							|  |  |  | 	// 			+ a tad complicated...
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			id: 'toggleDisplayShiftedUpImages', | 
					
						
							|  |  |  | 			title: 'Display shifted up images', | 
					
						
							|  |  |  | 			doc: 'Toggle display of shifted images.', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 			type: 'toggle', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		createCSSClassToggler('.viewer', 'show-shifted-up-images'))) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-02 17:54:40 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | /********************************************************* Movement **/ | 
					
						
							| 
									
										
										
										
											2012-08-02 17:54:40 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | ImageGrid.GROUP('Movement', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Center origin', | 
					
						
							|  |  |  | 			doc: 'Set the transform-origin to the center of the current view.', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function centerOrigin(){ | 
					
						
							|  |  |  | 			var mt = parseFloat($('.field').css('margin-top')) | 
					
						
							|  |  |  | 			var ml = parseFloat($('.field').css('margin-left')) | 
					
						
							|  |  |  | 			var cml = parseFloat($('.current.ribbon').css('margin-left')) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var t = parseFloat($('.field').css('top')) | 
					
						
							|  |  |  | 			var l = parseFloat($('.field').css('left')) | 
					
						
							|  |  |  | 			var w = $('.field').width() | 
					
						
							|  |  |  | 			var h = $('.field').height() | 
					
						
							|  |  |  | 			var W = $('.container').width() | 
					
						
							|  |  |  | 			var H = $('.container').height() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var ot = -getCurrentVerticalOffset() + H/2 - t | 
					
						
							|  |  |  | 			var ol = -ml + W/2 - l | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			$('.field').css({ | 
					
						
							|  |  |  | 				'transform-origin': ol + 'px ' + ot + 'px', | 
					
						
							|  |  |  | 				'-o-transform-origin': ol + 'px ' + ot + 'px', | 
					
						
							|  |  |  | 				'-moz-transform-origin': ol + 'px ' + ot + 'px', | 
					
						
							|  |  |  | 				'-webkit-transform-origin': ol + 'px ' + ot + 'px', | 
					
						
							|  |  |  | 				'-ms-transform-origin': ol + 'px ' + ot + 'px' | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 			// XXX for debugging...
 | 
					
						
							|  |  |  | 			$('.origin-marker').css({ | 
					
						
							|  |  |  | 				'top': ot, | 
					
						
							|  |  |  | 				'left': ol | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	// XXX these work oddly when page is scaled in maxthon... 
 | 
					
						
							|  |  |  | 	// XXX virtually identical, see of can be merged...
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Move view up', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function moveViewUp(){ | 
					
						
							|  |  |  | 			var t = parseInt($('.field').css('top')) | 
					
						
							|  |  |  | 			$('.field').css({'top': t-(ImageGrid.option.MOVE_DELTA)}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Move view down', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function moveViewDown(){ | 
					
						
							|  |  |  | 			var t = parseInt($('.field').css('top')) | 
					
						
							|  |  |  | 			$('.field').css({'top': t+(ImageGrid.option.MOVE_DELTA)}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Move view left', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function moveViewLeft(){ | 
					
						
							|  |  |  | 			var l = parseInt($('.field').css('left')) | 
					
						
							|  |  |  | 			$('.field').css({'left': l-(ImageGrid.option.MOVE_DELTA)}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Move view right', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function moveViewRight(){ | 
					
						
							|  |  |  | 			var l = parseInt($('.field').css('left')) | 
					
						
							|  |  |  | 			$('.field').css({'left': l+(ImageGrid.option.MOVE_DELTA)}) | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Center current image', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function centerCurrentImage(){ | 
					
						
							|  |  |  | 			$('.field') | 
					
						
							|  |  |  | 				.css({ | 
					
						
							|  |  |  | 					'top': 0, | 
					
						
							|  |  |  | 					'left': 0 | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 				// do this after animations are done...
 | 
					
						
							|  |  |  | 				.one("webkitTransitionEnd oTransitionEnd msTransitionEnd transitionend", ImageGrid.centerOrigin) | 
					
						
							|  |  |  | 			// this is repeated intentionally...
 | 
					
						
							|  |  |  | 			// ...needed for small shifts, while the after-animation event 
 | 
					
						
							|  |  |  | 			// is for large moves.
 | 
					
						
							|  |  |  | 			ImageGrid.centerOrigin() | 
					
						
							|  |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-04 20:26:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | /******************************************************* Navigation **/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | ImageGrid.GROUP('Navigation', | 
					
						
							|  |  |  | 	// basic navigation...
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Go to first image', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function firstImage(){ | 
					
						
							|  |  |  | 			return $('.current.ribbon').children('.image').first().click() | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Go to previous image', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function prevImage(){ | 
					
						
							|  |  |  | 			return $('.current.image').prev('.image').click() | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Go to next image', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function nextImage(){ | 
					
						
							|  |  |  | 			return $('.current.image').next('.image').click() | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Go to last image', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function lastImage(){ | 
					
						
							|  |  |  | 			return $('.current.ribbon').children('.image').last().click() | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Skip screen images', | 
					
						
							|  |  |  | 			doc: 'Skip screen-width images in specified direction', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function skipScreenImages(direction){ | 
					
						
							|  |  |  | 			// calculate screen width in images...
 | 
					
						
							|  |  |  | 			var W = $('.viewer').width() | 
					
						
							|  |  |  | 			var w = $('.current.image').width() | 
					
						
							|  |  |  | 			var scale = getElementScale($('.field')) | 
					
						
							|  |  |  | 			var n = Math.max(Math.floor(W/(w*scale))-1, 0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			var img = $('.current.image')[direction + 'All']('.image').eq(n) | 
					
						
							|  |  |  | 			if(img.length > 0){ | 
					
						
							|  |  |  | 				return img.click() | 
					
						
							|  |  |  | 			} else if(direction == 'next'){ | 
					
						
							|  |  |  | 				return ImageGrid.lastImage() | 
					
						
							|  |  |  | 			} else if(direction == 'prev'){ | 
					
						
							|  |  |  | 				return ImageGrid.firstImage() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Skip next screen images', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function nextScreenImages(){ return ImageGrid.skipScreenImages('next') }), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Skip screen images backwards', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function prevScreenImages(){ return ImageGrid.skipScreenImages('prev') }), | 
					
						
							| 
									
										
										
										
											2012-08-04 18:57:54 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 19:30:59 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Focus ribbon', | 
					
						
							|  |  |  | 			doc: 'Focus ribbon in specified direction', | 
					
						
							|  |  |  | 			display: false, | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function focusRibbon(direction, get_order){ | 
					
						
							|  |  |  | 			if(get_order == null){ | 
					
						
							|  |  |  | 				get_order = getImageOrder | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var id = get_order($('.current.image')) | 
					
						
							|  |  |  | 			var prev = getImageBefore(id, $('.current.ribbon')[direction]('.ribbon')) | 
					
						
							|  |  |  | 			if(prev){ | 
					
						
							|  |  |  | 				var next = prev.next() | 
					
						
							|  |  |  | 				// NOTE: direction is accounted for to make the up/down shifts 
 | 
					
						
							|  |  |  | 				// 		 symmetrical in the general case...
 | 
					
						
							|  |  |  | 				if(next.length == 0 || direction == 'next'){ | 
					
						
							|  |  |  | 					return prev.click() | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					return next.click() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return $('.current.ribbon')[direction]('.ribbon').children('.image').first().click() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Focus ribbon above', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function focusAboveRibbon(){ return ImageGrid.focusRibbon('prev') }), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Focus ribbon below', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function focusBelowRibbon(){ return ImageGrid.focusRibbon('next') })) | 
					
						
							| 
									
										
										
										
											2012-08-02 17:54:40 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-06-17 16:46:46 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | /********************************************************** Zooming **/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | ImageGrid.GROUP('Zooming', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Scale container by factor', | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function scaleContainerBy(factor){ | 
					
						
							|  |  |  | 			return ImageGrid.setContainerScale(getElementScale($('.field'))*factor) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Scale container up', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function scaleContainerUp(){ | 
					
						
							|  |  |  | 			return ImageGrid.scaleContainerBy(ImageGrid.option.ZOOM_FACTOR) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Scale container down', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function scaleContainerDown(){ | 
					
						
							|  |  |  | 			return ImageGrid.scaleContainerBy(1/ImageGrid.option.ZOOM_FACTOR) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Set container scale', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function setContainerScale(scale){ | 
					
						
							|  |  |  | 			return setElementScale($('.field'), scale) | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Fit N images to container width/height', | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function fitNImages(n){ | 
					
						
							|  |  |  | 			var H = $('.container').height() | 
					
						
							|  |  |  | 			var W = $('.container').width() | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			var h = $('.image.current').height() | 
					
						
							|  |  |  | 			// NOTE: this is cheating, need to get actual three widths...
 | 
					
						
							|  |  |  | 			var w = $('.image.current').width()*n | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			var f = Math.min(H/h, W/w) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | 			ImageGrid.setContainerScale(f) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	// the fit N image pack, for 1 <= N <= 9
 | 
					
						
							| 
									
										
										
										
											2012-08-20 01:06:08 +04:00
										 |  |  | 	ImageGrid.ACTION({ title: 'Fit 1 image' }, function fitImage(){ImageGrid.fitNImages(1)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 2 images' }, function fitTwoImages(){ImageGrid.fitNImages(2)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 3 images' }, function fitThreeImages(){ImageGrid.fitNImages(3)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 4 images' }, function fitFourImages(){ImageGrid.fitNImages(4)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 5 images' }, function fitFiveImages(){ImageGrid.fitNImages(5)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 6 images' }, function fitSixImages(){ImageGrid.fitNImages(6)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 7 images' }, function fitSevenImages(){ImageGrid.fitNImages(7)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 8 images' }, function fitEightImages(){ImageGrid.fitNImages(8)}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Fit 9 images' }, function fitNineImages(){ImageGrid.fitNImages(9)}) | 
					
						
							| 
									
										
										
										
											2012-08-19 20:12:40 +04:00
										 |  |  | ) | 
					
						
							| 
									
										
										
										
											2012-08-10 18:31:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | /*************************************************** Ribbon Actions **/ | 
					
						
							| 
									
										
										
										
											2012-06-16 21:52:23 +04:00
										 |  |  | // basic actions...
 | 
					
						
							| 
									
										
										
										
											2012-08-04 19:47:13 +04:00
										 |  |  | // NOTE: below 'direction' argument is meant in the html sence, 
 | 
					
						
							|  |  |  | //       i.e. next/prev...
 | 
					
						
							| 
									
										
										
										
											2012-06-16 21:52:23 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | ImageGrid.GROUP('Ribbon manipulations', | 
					
						
							|  |  |  | 	// XXX adding a ribbon above the current is still jumpy, need to devise 
 | 
					
						
							|  |  |  | 	// 		a cleaner way to do this...
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							| 
									
										
										
										
											2012-08-19 21:42:14 +04:00
										 |  |  | 			title: 'Create a ribbon above/below current', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function createRibbon(direction){ | 
					
						
							|  |  |  | 			if(direction == 'next'){ | 
					
						
							|  |  |  | 				var insert = 'insertAfter' | 
					
						
							|  |  |  | 			} else if(direction == 'prev') { | 
					
						
							|  |  |  | 				var insert = 'insertBefore' | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				return false | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 			// adding a new ribbon above the current effectively pushes the 
 | 
					
						
							|  |  |  | 			// whole view down, so we need to compensate for this.
 | 
					
						
							|  |  |  | 			// NOTE: the problem is partly caused by clicks fiering BEFORE the 
 | 
					
						
							|  |  |  | 			// 		 animation is done...
 | 
					
						
							|  |  |  | 			$('.field').addClass('unanimated')	 | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			if(direction == 'prev'){ | 
					
						
							|  |  |  | 				$('.field').css({ | 
					
						
							|  |  |  | 					'margin-top': parseInt($('.field').css('margin-top')) - $('.ribbon').outerHeight() | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// the actual insert...
 | 
					
						
							|  |  |  | 			var res = $('<div class="ribbon"></div>')[insert]('.current.ribbon') | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 			// restore the animated state...
 | 
					
						
							|  |  |  | 			$('.field').removeClass('unanimated')	 | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 			return res | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	// XXX this uses jquery animation...
 | 
					
						
							|  |  |  | 	// XXX one way to optimise this is to add the lesser ribbon to the 
 | 
					
						
							|  |  |  | 	//     greater disregarding their actual order...
 | 
					
						
							|  |  |  | 	// XXX think about using $(...).sortChildren(...) / sortImages()
 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Merge current and direction ribbon.', | 
					
						
							|  |  |  | 			doc: 'NOTE: this will take all the elements from direction '+ | 
					
						
							| 
									
										
										
										
											2012-08-19 21:42:14 +04:00
										 |  |  | 				'ribbon and add them to current.', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function mergeRibbons(direction, get_order){ | 
					
						
							|  |  |  | 			if(get_order == null){ | 
					
						
							|  |  |  | 				get_order = getImageOrder | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			var current_ribbon = $('.current.ribbon') | 
					
						
							|  |  |  | 			var images = $('.current.ribbon')[direction]('.ribbon').children() | 
					
						
							|  |  |  | 			for(var i=0; i < images.length; i++){ | 
					
						
							|  |  |  | 				var image = $(images[i]) | 
					
						
							|  |  |  | 				// get previous element after which we need to put the current...
 | 
					
						
							|  |  |  | 				var prev_elem = getImageBefore(get_order(image), current_ribbon) | 
					
						
							|  |  |  | 				// check if we need to be before the first element...
 | 
					
						
							|  |  |  | 				if(prev_elem == null){ | 
					
						
							|  |  |  | 					image | 
					
						
							|  |  |  | 						.detach() | 
					
						
							|  |  |  | 						.insertBefore(current_ribbon.children('.image').first()) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					image | 
					
						
							|  |  |  | 						.detach() | 
					
						
							|  |  |  | 						.insertAfter(prev_elem) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// animate...
 | 
					
						
							|  |  |  | 			$('.current.ribbon')[direction]('.ribbon') | 
					
						
							|  |  |  | 					.slideUp(function(){ | 
					
						
							|  |  |  | 						$(this).remove() | 
					
						
							|  |  |  | 						$('.current.image').click() | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 		 | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Reverse ribbon order', | 
					
						
							|  |  |  | 			doc: 'NOTE: this is like flipping the field vertically.', | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		function reverseRibbons(){ | 
					
						
							|  |  |  | 			// reverse...
 | 
					
						
							|  |  |  | 			$('.field').reverseChildren() | 
					
						
							|  |  |  | 			// compensate for offset cange...
 | 
					
						
							|  |  |  | 			$('.current.image').click() | 
					
						
							|  |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | /**************************************************** Image Actions **/ | 
					
						
							|  |  |  | ImageGrid.GROUP('Image manipulation', | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ | 
					
						
							|  |  |  | 			title: 'Shift image in direction', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		function shiftImage(direction, get_order){ | 
					
						
							|  |  |  | 			if(get_order == null){ | 
					
						
							|  |  |  | 				get_order = getImageOrder | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if($('.current.ribbon')[direction]('.ribbon').length == 0){ | 
					
						
							|  |  |  | 				ImageGrid.createRibbon(direction) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2012-08-14 20:13:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 			// get previous element after which we need to put the current...
 | 
					
						
							|  |  |  | 			var prev_elem = getImageBefore( | 
					
						
							|  |  |  | 							get_order($('.current.image')),  | 
					
						
							|  |  |  | 							$('.current.ribbon')[direction]('.ribbon')) | 
					
						
							| 
									
										
										
										
											2012-08-14 20:13:36 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 			// last image in ribbon, merge...
 | 
					
						
							|  |  |  | 			if($('.current.ribbon').children('.image').length == 1){ | 
					
						
							|  |  |  | 				ImageGrid.mergeRibbons(direction) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				img = $('.current.image') | 
					
						
							|  |  |  | 				if(img.next('.image').length == 0){ | 
					
						
							|  |  |  | 					ImageGrid.prevImage() | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					ImageGrid.nextImage() | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 				// do the actual move...
 | 
					
						
							|  |  |  | 				if(prev_elem){ | 
					
						
							|  |  |  | 					// insert element after current...
 | 
					
						
							|  |  |  | 					img | 
					
						
							|  |  |  | 						.detach() | 
					
						
							|  |  |  | 						.insertAfter(prev_elem) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					// empty ribbon or fisrt element...
 | 
					
						
							|  |  |  | 					img | 
					
						
							|  |  |  | 						.detach() | 
					
						
							|  |  |  | 						.prependTo($('.current.ribbon')[direction]('.ribbon')) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			$('.current.image').click() | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 	// shift image...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 	ImageGrid.ACTION({ title: 'Shift image up', },  | 
					
						
							|  |  |  | 		function shiftImageUp(){ return ImageGrid.shiftImage('prev') }), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({ title: 'Shift image down', },  | 
					
						
							|  |  |  | 		function shiftImageDown(){ return ImageGrid.shiftImage('next') }), | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// shift image to new ribbon...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 	ImageGrid.ACTION({  | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			title: 'Shift image up to new ribbon',  | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		},  | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 		function shiftImageUpNewRibbon(){ | 
					
						
							|  |  |  | 			ImageGrid.createRibbon('prev') | 
					
						
							|  |  |  | 			ImageGrid.shiftImageUp() | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 	ImageGrid.ACTION({  | 
					
						
							|  |  |  | 			title: 'Shift image down to new ribbon',  | 
					
						
							|  |  |  | 		},  | 
					
						
							|  |  |  | 		function shiftImageDownNewRibbon(){ | 
					
						
							|  |  |  | 			ImageGrid.createRibbon('next') | 
					
						
							|  |  |  | 			ImageGrid.shiftImageDown() | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 			 | 
					
						
							|  |  |  | 	// sorting...
 | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 	ImageGrid.ACTION({  | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			title: 'Sort images via criteria', | 
					
						
							|  |  |  | 			doc: 'Use the cmp function to update image id\'s and resort.', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 			display: false, | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		},  | 
					
						
							|  |  |  | 		function sortImagesVia(cmp){ | 
					
						
							|  |  |  | 			// reverse ID order...
 | 
					
						
							|  |  |  | 			$($('.image').get().sort(cmp)) | 
					
						
							|  |  |  | 				.each(function(i, e){$(e).attr({'id': i})}) | 
					
						
							|  |  |  | 			// resort the images...
 | 
					
						
							|  |  |  | 			ImageGrid.sortImages() | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 	ImageGrid.ACTION({  | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			title: 'Sort images', | 
					
						
							|  |  |  | 			doc: 'Sort images in all ribbons\n\n'+ | 
					
						
							|  |  |  | 				'NOTE: this will only realign three ribbons.' | 
					
						
							| 
									
										
										
										
											2012-08-19 21:34:31 +04:00
										 |  |  | 		},  | 
					
						
							|  |  |  | 		function sortImages(){ | 
					
						
							|  |  |  | 			$('.ribbon').sortChildren(cmpImageOrder) | 
					
						
							|  |  |  | 			// compensate for offset cange...
 | 
					
						
							|  |  |  | 			$('.current.image').click() | 
					
						
							|  |  |  | 		}), | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 	ImageGrid.ACTION({  | 
					
						
							| 
									
										
										
										
											2012-08-20 14:21:01 +04:00
										 |  |  | 			title: 'Reverse order of images', | 
					
						
							|  |  |  | 			doc: 'this will reverse image order in all ribbons.', | 
					
						
							| 
									
										
										
										
											2012-08-19 21:23:29 +04:00
										 |  |  | 		},  | 
					
						
							|  |  |  | 		function reverseImageOrder(){ | 
					
						
							|  |  |  | 			// this is done by reversing their id attr
 | 
					
						
							|  |  |  | 			ImageGrid.sortImagesVia(function(a, b){return cmpImageOrder(b, a)}) | 
					
						
							|  |  |  | 		}), | 
					
						
							|  |  |  | 	ImageGrid.ACTION({  | 
					
						
							|  |  |  | 			title: 'Sort images by their full path', | 
					
						
							|  |  |  | 		},  | 
					
						
							|  |  |  | 		// XXX this should use a normalized path...
 | 
					
						
							|  |  |  | 		function sortImagesByPath(){ | 
					
						
							|  |  |  | 			ImageGrid.sortImagesVia(function(a, b){  | 
					
						
							|  |  |  | 				a = $(a).css('background-image') | 
					
						
							|  |  |  | 				b = $(b).css('background-image')  | 
					
						
							|  |  |  | 				return a > b ? 1 : a < b ? -1 : 0 | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 		})) | 
					
						
							| 
									
										
										
										
											2012-08-14 20:12:30 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 18:08:45 +04:00
										 |  |  | // XXX group images in ribbon and merge down/up
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		grouping will make the images in a ribbon adjacent to each 
 | 
					
						
							|  |  |  | // 		other...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // 		the group's position will be the same as current images i.e. 
 | 
					
						
							|  |  |  | // 		between the below/above two images...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX shift group/image right/left...
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-14 17:26:46 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-07 21:12:22 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-08-15 04:03:11 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-14 00:00:16 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							| 
									
										
										
										
											2012-06-08 18:30:54 +04:00
										 |  |  | // vim:set ts=4 sw=4 nowrap :
 |