| 
									
										
										
										
											2013-05-14 18:10:33 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | *  | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | * | 
					
						
							|  |  |  | **********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | //var DEBUG = DEBUG != null ? DEBUG : true
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 21:44:49 +04:00
										 |  |  | var CURSOR_SHOW_THRESHOLD = 20 | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | var CURSOR_HIDE_TIMEOUT = 1000 | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 01:48:22 +04:00
										 |  |  | var STATUS_QUEUE = [] | 
					
						
							|  |  |  | var STATUS_QUEUE_TIME = 200 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:33:26 +04:00
										 |  |  | var CONTEXT_INDICATOR_UPDATERS = [] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 01:48:22 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2012-07-24 14:40:15 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | // XXX revise...
 | 
					
						
							| 
									
										
										
										
											2013-06-01 18:43:14 +04:00
										 |  |  | // NOTE: to catch the click event correctly while the cursor is hidden
 | 
					
						
							|  |  |  | //		this must be the first to get the event...
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | // NOTE: this uses element.data to store the timer and cursor position...
 | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | function autoHideCursor(elem){ | 
					
						
							|  |  |  | 	elem = $(elem) | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 	var data = elem.data() | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 	elem | 
					
						
							|  |  |  | 		.on('mousemove', function(evt){ | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | 			var cursor = elem.css('cursor') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 			data._cursor_pos = data._cursor_pos == null || cursor != 'none' ? | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 						[evt.clientX, evt.clientY]  | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 					: data._cursor_pos | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | 			// cursor visible -- extend visibility...
 | 
					
						
							|  |  |  | 			if(cursor != 'none'){ | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 				if(data._cursor_timeout != null){ | 
					
						
							|  |  |  | 					clearTimeout(data._cursor_timeout) | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 				data._cursor_timeout = setTimeout(function(){ | 
					
						
							|  |  |  | 						if(Math.abs(evt.clientX - data._cursor_pos[0]) < CURSOR_SHOW_THRESHOLD  | 
					
						
							|  |  |  | 								|| Math.abs(evt.clientY - data._cursor_pos[1]) < CURSOR_SHOW_THRESHOLD){ | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | 							elem.css('cursor', 'none') | 
					
						
							|  |  |  | 						} | 
					
						
							|  |  |  | 					}, CURSOR_HIDE_TIMEOUT) | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// cursor hidden -- if outside the threshold, show...
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 			} else if(Math.abs(evt.clientX - data._cursor_pos[0]) > CURSOR_SHOW_THRESHOLD  | 
					
						
							|  |  |  | 				|| Math.abs(evt.clientY - data._cursor_pos[1]) > CURSOR_SHOW_THRESHOLD){ | 
					
						
							| 
									
										
										
										
											2013-06-01 21:33:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				elem.css('cursor', '') | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-06-01 18:43:14 +04:00
										 |  |  | 		.click(function(evt){ | 
					
						
							|  |  |  | 			if(elem.css('cursor') == 'none'){ | 
					
						
							|  |  |  | 				//event.stopImmediatePropagation()
 | 
					
						
							|  |  |  | 				//event.preventDefault()
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 				if(data._cursor_timeout != null){ | 
					
						
							|  |  |  | 					clearTimeout(data._cursor_timeout) | 
					
						
							|  |  |  | 					data._cursor_timeout = null | 
					
						
							| 
									
										
										
										
											2013-06-01 18:43:14 +04:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				elem.css('cursor', '') | 
					
						
							|  |  |  | 				//return false
 | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-06-01 18:26:06 +04:00
										 |  |  | 	return elem | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | /* | 
					
						
							|  |  |  | // XXX does not work...
 | 
					
						
							|  |  |  | // 		...does not show the cursor without moving it...
 | 
					
						
							|  |  |  | function showCursor(elem){ | 
					
						
							|  |  |  | 	elem = $(elem) | 
					
						
							|  |  |  | 	var data = elem.data() | 
					
						
							|  |  |  | 	if(data._cursor_timeout != null){ | 
					
						
							|  |  |  | 		clearTimeout(data._cursor_timeout) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	elem.css('cursor', '') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:33:26 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | function setupIndicators(){ | 
					
						
							|  |  |  | 	showGlobalIndicator( | 
					
						
							|  |  |  | 			'single-ribbon-mode',  | 
					
						
							|  |  |  | 			'Single ribbon mode (F3)') | 
					
						
							|  |  |  | 		.css('cursor', 'hand') | 
					
						
							|  |  |  | 		.click(function(){ toggleSingleRibbonMode() }) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function makeContextIndicatorUpdater(image_class){ | 
					
						
							|  |  |  | 	var _updater = function(image){ | 
					
						
							|  |  |  | 		var indicator = $('.context-mode-indicators .current-image-'+image_class) | 
					
						
							|  |  |  | 		if(image.hasClass(image_class)){ | 
					
						
							|  |  |  | 			indicator.addClass('shown') | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			indicator.removeClass('shown') | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	CONTEXT_INDICATOR_UPDATERS.push(_updater) | 
					
						
							|  |  |  | 	return _updater | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function updateContextIndicators(image){ | 
					
						
							|  |  |  | 	image = image == null ? getImage() : $(image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	CONTEXT_INDICATOR_UPDATERS.map(function(update){ | 
					
						
							|  |  |  | 		update(image) | 
					
						
							|  |  |  | 	})	 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-02 08:50:43 +04:00
										 |  |  | function showCurrentMarker(){ | 
					
						
							|  |  |  | 	return $('<div/>') | 
					
						
							|  |  |  | 		.addClass('current-marker') | 
					
						
							|  |  |  | 		.css({ | 
					
						
							|  |  |  | 			opacity: '0', | 
					
						
							|  |  |  | 			top: '0px', | 
					
						
							|  |  |  | 			left: '0px', | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.appendTo($('.ribbon-set')) | 
					
						
							|  |  |  | 		.animate({ | 
					
						
							|  |  |  | 			'opacity': 1 | 
					
						
							|  |  |  | 		}, 500) | 
					
						
							|  |  |  | 		.mouseover(function(){ | 
					
						
							|  |  |  | 			$('.current.image') | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function updateCurrentMarker(){ | 
					
						
							|  |  |  | 	var scale = getElementScale($('.ribbon-set')) | 
					
						
							|  |  |  | 	var marker = $('.current-marker') | 
					
						
							| 
									
										
										
										
											2013-12-18 21:48:40 +04:00
										 |  |  | 	var cur = $('.current.image') | 
					
						
							|  |  |  | 	var w = cur.outerWidth(true) | 
					
						
							|  |  |  | 	var h = cur.outerHeight(true) | 
					
						
							| 
									
										
										
										
											2013-12-02 08:50:43 +04:00
										 |  |  | 	marker = marker.length == 0 ? showCurrentMarker() : marker  | 
					
						
							| 
									
										
										
										
											2013-12-18 21:48:40 +04:00
										 |  |  | 	var d = getRelativeVisualPosition(marker, cur) | 
					
						
							| 
									
										
										
										
											2013-12-02 08:50:43 +04:00
										 |  |  | 	return marker.css({ | 
					
						
							|  |  |  | 		top: parseFloat(marker.css('top')) + d.top/scale, | 
					
						
							|  |  |  | 		left: parseFloat(marker.css('left')) + d.left/scale, | 
					
						
							| 
									
										
										
										
											2013-12-18 21:48:40 +04:00
										 |  |  | 		// keep size same as the image...
 | 
					
						
							|  |  |  | 		width: w, | 
					
						
							|  |  |  | 		height: h, | 
					
						
							| 
									
										
										
										
											2013-12-02 08:50:43 +04:00
										 |  |  | 	}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 20:04:27 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | function flashIndicator(direction){ | 
					
						
							|  |  |  | 	var cls = { | 
					
						
							| 
									
										
										
										
											2013-06-08 02:29:14 +04:00
										 |  |  | 		// shift up/down...
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 		prev: '.up-indicator', | 
					
						
							|  |  |  | 		next: '.down-indicator', | 
					
						
							| 
									
										
										
										
											2013-06-08 05:46:57 +04:00
										 |  |  | 		// hit start/end/top/bottom of view...
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 		start: '.start-indicator', | 
					
						
							|  |  |  | 		end: '.end-indicator', | 
					
						
							| 
									
										
										
										
											2013-06-08 02:29:14 +04:00
										 |  |  | 		top: '.top-indicator', | 
					
						
							|  |  |  | 		bottom: '.bottom-indicator', | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 	}[direction] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var indicator = $(cls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(indicator.length == 0){ | 
					
						
							|  |  |  | 		indicator = $('<div>') | 
					
						
							|  |  |  | 			.addClass(cls.replace('.', '')) | 
					
						
							|  |  |  | 			.appendTo($('.viewer')) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return indicator | 
					
						
							|  |  |  | 		// NOTE: this needs to be visible in all cases and key press 
 | 
					
						
							|  |  |  | 		// 		rhythms... 
 | 
					
						
							|  |  |  | 		.show() | 
					
						
							|  |  |  | 		.delay(100) | 
					
						
							|  |  |  | 		.fadeOut(300) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | function showRibbonIndicator(){ | 
					
						
							|  |  |  | 	var cls = '.ribbon-indicator' | 
					
						
							|  |  |  | 	var indicator = $(cls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(indicator.length == 0){ | 
					
						
							|  |  |  | 		indicator = $('<div>') | 
					
						
							|  |  |  | 			.addClass(cls.replace('.', '')) | 
					
						
							|  |  |  | 			.appendTo($('.viewer')) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var r = getRibbonIndex() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// get the base ribbon...
 | 
					
						
							| 
									
										
										
										
											2013-09-27 21:45:31 +04:00
										 |  |  | 	var base = getBaseRibbonIndex() | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var r =  r == base ? r+'*' : r | 
					
						
							|  |  |  | 	return indicator.text(r) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-27 21:45:31 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | function flashRibbonIndicator(){ | 
					
						
							|  |  |  | 	var indicator = showRibbonIndicator() | 
					
						
							|  |  |  | 	var cls = '.flashing-ribbon-indicator' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var flashing_indicator = $(cls) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(flashing_indicator.length == 0){ | 
					
						
							|  |  |  | 		flashing_indicator = indicator | 
					
						
							|  |  |  | 			.clone() | 
					
						
							|  |  |  | 			.addClass(cls.replace('.', '')) | 
					
						
							|  |  |  | 			.appendTo($('.viewer')) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return flashing_indicator | 
					
						
							| 
									
										
										
										
											2013-09-21 03:09:19 +04:00
										 |  |  | //		.stop()
 | 
					
						
							|  |  |  | //		.show()
 | 
					
						
							|  |  |  | //		.delay(200)
 | 
					
						
							|  |  |  | //		.fadeOut(500)
 | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | 		.show() | 
					
						
							| 
									
										
										
										
											2013-09-21 03:09:19 +04:00
										 |  |  | 		.delay(100) | 
					
						
							|  |  |  | 		.fadeOut(300) | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | // Update an info element
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // align can be:
 | 
					
						
							|  |  |  | // 	- top
 | 
					
						
							|  |  |  | // 	- bottom
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // If target is an existing info container (class: overlay-info) then 
 | 
					
						
							|  |  |  | // just fill that.
 | 
					
						
							|  |  |  | function updateInfo(elem, data, target){ | 
					
						
							|  |  |  | 	var viewer = $('.viewer') | 
					
						
							|  |  |  | 	target = target == null ? viewer : $(target) | 
					
						
							|  |  |  | 	elem = elem == null ? $('.overlay-info') : $(elem) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(elem.length == 0){ | 
					
						
							|  |  |  | 		elem = $('<div/>') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	elem | 
					
						
							|  |  |  | 		.addClass('overlay-info') | 
					
						
							|  |  |  | 		.html('') | 
					
						
							|  |  |  | 		.off() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(typeof(data) == typeof('abc')){ | 
					
						
							|  |  |  | 		elem.html(data) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		elem.append(data) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return elem  | 
					
						
							|  |  |  | 		.appendTo(target) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function showInfo(elem, data, target){ | 
					
						
							|  |  |  | 	elem = elem == null ? $('.overlay-info') : elem | 
					
						
							|  |  |  | 	elem = data == null ? elem : updateInfo(elem, data, traget) | 
					
						
							|  |  |  | 	return elem.fadeIn() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function hideInfo(elem){ | 
					
						
							|  |  |  | 	elem = elem == null ? $('.overlay-info') : elem | 
					
						
							|  |  |  | 	return elem.fadeOut() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Update status message
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this will update message content and return it as-is, things 
 | 
					
						
							|  |  |  | // 		like showing the message are to be done manually...
 | 
					
						
							|  |  |  | // 		see: showStatus(...) and showErrorStatus(...) for a higher level
 | 
					
						
							|  |  |  | // 		API...
 | 
					
						
							|  |  |  | // NOTE: in addition to showing user status, this will also log the 
 | 
					
						
							|  |  |  | // 		satus to browser console...
 | 
					
						
							|  |  |  | // NOTE: the message will be logged to console via either console.log(...)
 | 
					
						
							|  |  |  | // 		or console.error(...), if the message starts with "Error".
 | 
					
						
							|  |  |  | // NOTE: if message is null, then just return the status element...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX add abbility to append and clear status...
 | 
					
						
							|  |  |  | function updateStatus(message){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var elem = $('.global-status') | 
					
						
							|  |  |  | 	if(elem.length == 0){ | 
					
						
							|  |  |  | 		elem = $('<div class="global-status"/>') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if(message == null){ | 
					
						
							|  |  |  | 		return elem | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(typeof(message) == typeof('s') && /^error.*/i.test(message)){ | 
					
						
							|  |  |  | 		console.error.apply(console, arguments) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		console.log.apply(console, arguments) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(arguments.length > 1){ | 
					
						
							|  |  |  | 		message = Array.apply(Array, arguments).join(' ') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return updateInfo(elem, message) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Same as updateInfo(...) but will aslo show and animate-close the message
 | 
					
						
							| 
									
										
										
										
											2013-06-04 16:32:33 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // XXX the next call will not reset the animation of the previous, rather 
 | 
					
						
							|  |  |  | // 		it will pause it and rezume...
 | 
					
						
							|  |  |  | // 		...not sure if this is correct.
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | function showStatus(message){ | 
					
						
							|  |  |  | 	return updateStatus.apply(null, arguments) | 
					
						
							| 
									
										
										
										
											2013-06-04 16:32:33 +04:00
										 |  |  | 		//.stop()
 | 
					
						
							|  |  |  | 		.stop(true, false) | 
					
						
							|  |  |  | 		//.finish()
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 		.show() | 
					
						
							|  |  |  | 		.delay(500) | 
					
						
							|  |  |  | 		.fadeOut(800) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-08 01:48:22 +04:00
										 |  |  | // Same as showStatus(...) but queue the message so as to display it for
 | 
					
						
							|  |  |  | // a meaningful amount of time...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //	- This will print the first message right away.
 | 
					
						
							|  |  |  | //	- Each consecutive message if STATUS_QUEUE_TIME has not passed yet 
 | 
					
						
							|  |  |  | //		will get queued.
 | 
					
						
							|  |  |  | //	- Once the STATUS_QUEUE_TIME has passed the next message is reported 
 | 
					
						
							|  |  |  | // 		and so on until the queue is empty.
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: for very a fast and large sequence of messages the reporting 
 | 
					
						
							|  |  |  | // 		may (will) take longer (significantly) than the actual "job"...
 | 
					
						
							|  |  |  | // NOTE: this will delay the logging also...
 | 
					
						
							|  |  |  | function showStatusQ(message){ | 
					
						
							|  |  |  | 	if(STATUS_QUEUE.length == 0){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// end marker...
 | 
					
						
							|  |  |  | 		STATUS_QUEUE.push(0) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		showStatus.apply(null, arguments) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		function _printer(){ | 
					
						
							|  |  |  | 			// if queue is empty we have nothing to do...
 | 
					
						
							|  |  |  | 			if(STATUS_QUEUE.length == 1){ | 
					
						
							|  |  |  | 				STATUS_QUEUE.pop() | 
					
						
							|  |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			// if not empty show a status and repeat...
 | 
					
						
							|  |  |  | 			showStatus.apply(null, STATUS_QUEUE.pop()) | 
					
						
							|  |  |  | 			setTimeout(_printer, STATUS_QUEUE_TIME) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		setTimeout(_printer, STATUS_QUEUE_TIME) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// queue not empty...
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		STATUS_QUEUE.splice(1, 0, Array.apply(Array, arguments)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | // Same as showStatus(...) but will always add 'Error: ' to the start 
 | 
					
						
							|  |  |  | // of the message
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: this will show the message but will not hide it.
 | 
					
						
							|  |  |  | function showErrorStatus(message){ | 
					
						
							|  |  |  | 	message = Array.apply(Array, arguments) | 
					
						
							|  |  |  | 	message.splice(0, 0, 'Error:') | 
					
						
							|  |  |  | 	return updateStatus.apply(null, message) | 
					
						
							|  |  |  | 		.one('click', function(){ $(this).fadeOut() }) | 
					
						
							| 
									
										
										
										
											2013-06-04 16:32:33 +04:00
										 |  |  | 		//.stop()
 | 
					
						
							|  |  |  | 		.stop(true, false) | 
					
						
							|  |  |  | 		//.finish()
 | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 		.show() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // shorthand methods...
 | 
					
						
							|  |  |  | function hideStatus(){ | 
					
						
							|  |  |  | 	// yes, this indeed looks funny -- to hide a status you need to show
 | 
					
						
							|  |  |  | 	// it without any arguments... ;)
 | 
					
						
							|  |  |  | 	return showStatus() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function getStatus(){ | 
					
						
							|  |  |  | 	return updateStatus() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function makeIndicator(text){ | 
					
						
							| 
									
										
										
										
											2013-06-08 02:29:14 +04:00
										 |  |  | 	return $('<span class="indicator expanding-text">'+ | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 				'<span class="hidden">'+ text +'</span>'+ | 
					
						
							|  |  |  | 				'<span class="shown">'+ text[0] +'</span>'+ | 
					
						
							|  |  |  | 			'</span>') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function showGlobalIndicator(cls, text){ | 
					
						
							|  |  |  | 	var c = $('.global-mode-indicators') | 
					
						
							|  |  |  | 	if(c.length == 0){ | 
					
						
							|  |  |  | 		c = $('<div>') | 
					
						
							|  |  |  | 			.addClass('global-mode-indicators') | 
					
						
							| 
									
										
										
										
											2013-06-08 02:29:14 +04:00
										 |  |  | 			.append('<span class="mode-tip">Global status</span>') | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 			.appendTo($('.viewer')) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return makeIndicator(text) | 
					
						
							|  |  |  | 			.addClass(cls) | 
					
						
							|  |  |  | 			.appendTo(c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function showContextIndicator(cls, text){ | 
					
						
							|  |  |  | 	var c = $('.context-mode-indicators') | 
					
						
							|  |  |  | 	if(c.length == 0){ | 
					
						
							|  |  |  | 		c = $('<div>') | 
					
						
							|  |  |  | 			.addClass('context-mode-indicators') | 
					
						
							| 
									
										
										
										
											2013-06-08 02:29:14 +04:00
										 |  |  | 			.append('<span class="mode-tip">Context status</span>') | 
					
						
							| 
									
										
										
										
											2013-06-04 09:29:38 +04:00
										 |  |  | 			.appendTo($('.viewer')) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return makeIndicator(text) | 
					
						
							|  |  |  | 			.addClass(cls) | 
					
						
							|  |  |  | 			.appendTo(c) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-10 19:20:35 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /********************************************************************** | 
					
						
							|  |  |  | * Modal dialogs... | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-27 17:15:19 +04:00
										 |  |  | /********************************************************* Helpers ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Set element text and tooltip
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // NOTE: when text is a list, we will only use the first and the last 
 | 
					
						
							|  |  |  | // 		elements...
 | 
					
						
							|  |  |  | // NOTE: if tip_elem is not given then both the text and tip will be set
 | 
					
						
							|  |  |  | // 		on text_elem
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX add support for quoted '|'...
 | 
					
						
							|  |  |  | function setTextWithTooltip(text, text_elem, tip_elem){ | 
					
						
							|  |  |  | 	text_elem = $(text_elem) | 
					
						
							|  |  |  | 	tip_elem = tip_elem == null ? text_elem : tip_elem | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(typeof(text) != typeof('str')){ | 
					
						
							|  |  |  | 		tip = text | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var tip = text.split(/\s*\|\s*/) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// set elemnt text...
 | 
					
						
							|  |  |  | 	text_elem | 
					
						
							|  |  |  | 		.html(tip[0]) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// do the tooltip...
 | 
					
						
							|  |  |  | 	tip = tip.slice(1) | 
					
						
							|  |  |  | 	tip = tip[tip.length-1] | 
					
						
							|  |  |  | 	if(tip != null && tip.trim().length > 0){ | 
					
						
							|  |  |  | 		$('<span class="tooltip-icon tooltip-right"> *</span>') | 
					
						
							|  |  |  | 			.attr('tooltip', tip) | 
					
						
							|  |  |  | 			.appendTo(tip_elem) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return text_elem | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-10 17:28:32 +04:00
										 |  |  | function getOverlay(root){ | 
					
						
							|  |  |  | 	root = $(root) | 
					
						
							|  |  |  | 	var overlay = root.find('.overlay-block') | 
					
						
							|  |  |  | 	if(overlay.length == 0){ | 
					
						
							|  |  |  | 		return $('<div class="overlay-block">'+ | 
					
						
							|  |  |  | 					'<div class="background"/>'+ | 
					
						
							|  |  |  | 					'<div class="content"/>'+ | 
					
						
							|  |  |  | 				'</div>').appendTo(root) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return overlay | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function showInOverlay(root, data){ | 
					
						
							|  |  |  | 	root = $(root) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var overlay = getOverlay(root) | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(data != null){ | 
					
						
							|  |  |  | 		var container = $('<table width="100%" height="100%"><tr><td align="center" valign="center">'+ | 
					
						
							|  |  |  | 								'<div class="dialog"/>'+ | 
					
						
							|  |  |  | 							'</td></tr></table>') | 
					
						
							|  |  |  | 		var dialog = container.find('.dialog') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//overlay.find('.background')
 | 
					
						
							|  |  |  | 		//	.click(function(){ hideOverlay(root) })
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		dialog | 
					
						
							|  |  |  | 			.append(data) | 
					
						
							| 
									
										
										
										
											2013-12-04 23:55:52 +04:00
										 |  |  | 			.on('click', function(evt){  | 
					
						
							|  |  |  | 				evt.stopPropagation()  | 
					
						
							| 
									
										
										
										
											2013-06-10 19:20:35 +04:00
										 |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2013-06-10 17:28:32 +04:00
										 |  |  | 		overlay.find('.content') | 
					
						
							| 
									
										
										
										
											2013-06-10 19:20:35 +04:00
										 |  |  | 			.on('click', function(){  | 
					
						
							|  |  |  | 				overlay.trigger('close') | 
					
						
							|  |  |  | 				hideOverlay(root)  | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | 			.on('close accept', function(){ | 
					
						
							|  |  |  | 				//hideOverlay(root) 
 | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2013-06-10 17:28:32 +04:00
										 |  |  | 			.append(container) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	root.addClass('overlay') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return overlay | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function hideOverlay(root){ | 
					
						
							|  |  |  | 	root.removeClass('overlay') | 
					
						
							| 
									
										
										
										
											2013-06-10 19:20:35 +04:00
										 |  |  | 	root.find('.overlay-block') | 
					
						
							|  |  |  | 		.trigger('close') | 
					
						
							|  |  |  | 		.remove() | 
					
						
							| 
									
										
										
										
											2013-06-10 17:28:32 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-01 05:44:00 +04:00
										 |  |  | function isOverlayVisible(root){ | 
					
						
							|  |  |  | 	return getOverlay(root).css('display') != 'none' | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-10 17:28:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | var FIELD_TYPES = { | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | 	// a simple hr...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// format:
 | 
					
						
							|  |  |  | 	// 		'---'
 | 
					
						
							|  |  |  | 	// 		Three or more '-'s
 | 
					
						
							|  |  |  | 	hr: { | 
					
						
							|  |  |  | 		type: 'hr', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<hr>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return /\-\-\-+/.test(val) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// a simple br...
 | 
					
						
							|  |  |  | 	//
 | 
					
						
							|  |  |  | 	// format:
 | 
					
						
							|  |  |  | 	// 		'   '
 | 
					
						
							|  |  |  | 	// 		Three or more spaces
 | 
					
						
							|  |  |  | 	br: { | 
					
						
							|  |  |  | 		type: 'br', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<br>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return /\s\s\s+/.test(val) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	// format:
 | 
					
						
							|  |  |  | 	// 	{
 | 
					
						
							|  |  |  | 	// 		html: <html-block>
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	html: { | 
					
						
							|  |  |  | 		type: 'html', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="html-block"/>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return val.html != null | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			if(typeof(value.html) == typeof('str')){ | 
					
						
							|  |  |  | 				field.html(value.html) | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				field.append(value.html) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 		string
 | 
					
						
							| 
									
										
										
										
											2013-07-07 03:19:41 +04:00
										 |  |  | 	// XXX add datalist option...
 | 
					
						
							| 
									
										
										
										
											2013-09-09 15:56:39 +04:00
										 |  |  | 	// XXX make this textarea compatible...
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 	text: { | 
					
						
							|  |  |  | 		type: 'text', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: '', | 
					
						
							| 
									
										
										
										
											2013-06-13 02:02:24 +04:00
										 |  |  | 		html: '<div class="field string">'+ | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 				'<span class="text"></span>'+ | 
					
						
							|  |  |  | 				'<input type="text" class="value">'+ | 
					
						
							|  |  |  | 			'</div>', | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return typeof(val) == typeof('abc') | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			$(field).find('.value').attr('value', value)  | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		get: function(field){  | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 			return $(field).find('.value').attr('value')  | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	},	 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 		true | false
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 	bool: { | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		type: 'bool', | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							| 
									
										
										
										
											2013-06-13 02:02:24 +04:00
										 |  |  | 		html: '<div class="field checkbox">'+ | 
					
						
							| 
									
										
										
										
											2013-06-22 19:30:56 +04:00
										 |  |  | 				'<label><input type="checkbox" class="value">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span></label>'+ | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 			'</div>', | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return val === true || val === false | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			if(value){ | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 				$(field).find('.value').attr('checked', '')  | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				$(field).find('.value').removeAttr('checked')  | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		get: function(field){  | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 			return $(field).find('.value').attr('checked') == 'checked' | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | 	// NOTE: this will not work without node-webkit...
 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 		{ dir: <default-path> }
 | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 	dir: { | 
					
						
							|  |  |  | 		type: 'dir', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="field checkbox">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span>'+ | 
					
						
							|  |  |  | 				'<input type="file" class="value" nwdirectory />'+ | 
					
						
							|  |  |  | 			'</div>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return typeof(val) == typeof({}) && 'dir' in val | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			field.find('.value').attr('nwworkingdir', value.dir) | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		get: function(field){  | 
					
						
							|  |  |  | 			var f = $(field).find('.value')[0].files | 
					
						
							|  |  |  | 			if(f.length == 0){ | 
					
						
							|  |  |  | 				return '' | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			return f[0].path | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | 	// NOTE: this will not work without node-webkit...
 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 		{ dir: <default-path> }
 | 
					
						
							| 
									
										
										
										
											2013-07-07 03:19:41 +04:00
										 |  |  | 	// XXX add datalist option...
 | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 	ndir: { | 
					
						
							|  |  |  | 		type: 'ndir', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="field dir">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span>'+ | 
					
						
							|  |  |  | 				'<input type="text" class="path"/>'+ | 
					
						
							|  |  |  | 				'<button class="browse">Browse</button>'+ | 
					
						
							|  |  |  | 			'</div>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return typeof(val) == typeof({}) && 'ndir' in val | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			var that = this | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// NOTE: we are attaching the file browser to body to avoid 
 | 
					
						
							|  |  |  | 			// 		click events on it closing the dialog...
 | 
					
						
							|  |  |  | 			// 		...for some reason stopPropagation(...) does not do 
 | 
					
						
							|  |  |  | 			// 		the job...
 | 
					
						
							|  |  |  | 			var file = $('<input type="file" class="value" nwdirectory/>') | 
					
						
							|  |  |  | 				.attr('nwworkingdir', value.ndir) | 
					
						
							|  |  |  | 				.change(function(){ | 
					
						
							|  |  |  | 					var p = file[0].files | 
					
						
							|  |  |  | 					if(p.length != 0){ | 
					
						
							|  |  |  | 						field.find('.path').val(p[0].path) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 					file.detach() | 
					
						
							| 
									
										
										
										
											2013-08-02 01:25:28 +04:00
										 |  |  | 					// focus+select the path field...
 | 
					
						
							| 
									
										
										
										
											2013-08-01 03:19:42 +04:00
										 |  |  | 					// NOTE: this is here to enable fast select-open 
 | 
					
						
							|  |  |  | 					// 		keyboard cycle (tab, enter, <select path>, 
 | 
					
						
							|  |  |  | 					// 		enter, enter)...
 | 
					
						
							| 
									
										
										
										
											2013-08-01 03:16:41 +04:00
										 |  |  | 					field.find('.path') | 
					
						
							|  |  |  | 						.focus() | 
					
						
							|  |  |  | 						.select() | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 				}) | 
					
						
							|  |  |  | 				.hide() | 
					
						
							|  |  |  | 			field.find('.path').val(value.ndir) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			field.find('.browse').click(function(){ | 
					
						
							|  |  |  | 				file | 
					
						
							| 
									
										
										
										
											2013-06-15 03:04:06 +04:00
										 |  |  | 					// load user input path...
 | 
					
						
							|  |  |  | 					.attr('nwworkingdir', field.find('.path').val()) | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 					.appendTo($('body')) | 
					
						
							|  |  |  | 					.click() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		get: function(field){  | 
					
						
							|  |  |  | 			return field.find('.path').val() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 		['a', 'b', 'c', ...]
 | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// an item can be of the folowing format:
 | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | 	// 		<text> ['|' 'default' | 'disabled' ] [ '|' <tool-tip> ]
 | 
					
						
							| 
									
										
										
										
											2013-11-26 19:16:27 +04:00
										 |  |  | 	//
 | 
					
						
							|  |  |  | 	// NOTE: only one 'default' item should be present.
 | 
					
						
							|  |  |  | 	// NOTE: if no defaults are set, then the first item is checked.
 | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 	choice: { | 
					
						
							|  |  |  | 		type: 'choice', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="field choice">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span>'+ | 
					
						
							| 
									
										
										
										
											2013-06-22 19:30:56 +04:00
										 |  |  | 				'<div class="item"><label>'+ | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 					'<input type="radio" class="value"/>'+ | 
					
						
							|  |  |  | 					'<span class="item-text"></span>'+ | 
					
						
							| 
									
										
										
										
											2013-06-22 19:30:56 +04:00
										 |  |  | 				'</label></div>'+ | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 			'</div>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return typeof(val) == typeof([]) && val.constructor.name == 'Array' | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 			var t = field.find('.text').html() | 
					
						
							| 
									
										
										
										
											2013-06-22 19:30:56 +04:00
										 |  |  | 			t = t == '' ? Math.random()+'' : t | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 			var item = field.find('.item').last() | 
					
						
							|  |  |  | 			for(var i=0; i < value.length; i++){ | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 				// get options...
 | 
					
						
							| 
									
										
										
										
											2013-11-26 19:42:08 +04:00
										 |  |  | 				var opts = value[i] | 
					
						
							|  |  |  | 					.split(/\|/g) | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 					.map(function(e){ return e.trim() }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				var val = item.find('.value') | 
					
						
							| 
									
										
										
										
											2013-11-26 19:42:08 +04:00
										 |  |  | 				val.val(opts[0]) | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				// set checked state...
 | 
					
						
							| 
									
										
										
										
											2013-11-26 19:42:08 +04:00
										 |  |  | 				if(opts.slice(1).indexOf('default') >= 0){ | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 					val.prop('checked', true) | 
					
						
							|  |  |  | 					opts.splice(opts.indexOf('default'), 1) | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					val.prop('checked', false) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | 				// set disabled state...
 | 
					
						
							|  |  |  | 				if(opts.slice(1).indexOf('disabled') >= 0){ | 
					
						
							|  |  |  | 					val.prop('disabled', true) | 
					
						
							|  |  |  | 					opts.splice(opts.indexOf('disabled'), 1) | 
					
						
							|  |  |  | 					item.addClass('disabled') | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					val.prop('disabled', false) | 
					
						
							|  |  |  | 					item.removeClass('disabled') | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-27 17:15:19 +04:00
										 |  |  | 				setTextWithTooltip(opts, item.find('.item-text')) | 
					
						
							| 
									
										
										
										
											2013-11-26 19:16:27 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 				item.appendTo(field) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				item = item.clone() | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 			var values = field.find('.value') | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 				.attr('name', t) | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 			// set the default...
 | 
					
						
							| 
									
										
										
										
											2013-12-13 04:55:57 +04:00
										 |  |  | 			if(values.filter(':checked:not([disabled])').length == 0){ | 
					
						
							|  |  |  | 				values.filter(':not([disabled])').first() | 
					
						
							| 
									
										
										
										
											2013-11-26 18:34:56 +04:00
										 |  |  | 					.prop('checked', true) | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 		}, | 
					
						
							|  |  |  | 		get: function(field){  | 
					
						
							|  |  |  | 			return $(field).find('.value:checked').val() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-08 07:07:26 +04:00
										 |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 	{ 
 | 
					
						
							|  |  |  | 	// 		select: ['a', 'b', 'c', ...] 
 | 
					
						
							|  |  |  | 	// 		// default option (optional)...
 | 
					
						
							|  |  |  | 	// 		default: <number> | <text>
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	select: { | 
					
						
							|  |  |  | 		type: 'select', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="field choice">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span>'+ | 
					
						
							|  |  |  | 				'<select>'+ | 
					
						
							|  |  |  | 					'<option class="option"></option>'+ | 
					
						
							|  |  |  | 				'</select>'+ | 
					
						
							|  |  |  | 			'</div>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return 'select' in val | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			var t = field.find('.text').text() | 
					
						
							|  |  |  | 			var item = field.find('.option').last() | 
					
						
							|  |  |  | 			var select = field.find('select') | 
					
						
							|  |  |  | 			for(var i=0; i < value.select.length; i++){ | 
					
						
							|  |  |  | 				item | 
					
						
							|  |  |  | 					.text(value.select[i]) | 
					
						
							|  |  |  | 					.val(value.select[i]) | 
					
						
							|  |  |  | 				item.appendTo(select) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				item = item.clone() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			if(value.default != null){ | 
					
						
							|  |  |  | 				if(typeof(value.default) == typeof(123)){ | 
					
						
							|  |  |  | 					field.find('.option') | 
					
						
							|  |  |  | 						.eq(value.default) | 
					
						
							|  |  |  | 							.attr('selected', '') | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					field.find('.option[value="'+ value.default +'"]') | 
					
						
							|  |  |  | 						.attr('selected', '') | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		get: function(field){  | 
					
						
							|  |  |  | 			return $(field).find('.option:selected').val() | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-04 19:00:38 +04:00
										 |  |  | 	// NOTE: a button can have state...
 | 
					
						
							|  |  |  | 	// format: 
 | 
					
						
							|  |  |  | 	// 	{ 
 | 
					
						
							|  |  |  | 	// 		// click event handler...
 | 
					
						
							|  |  |  | 	// 		button: <function>, 
 | 
					
						
							|  |  |  | 	// 		// optional, button text (default 'OK')...
 | 
					
						
							|  |  |  | 	// 		text: <button-label>,
 | 
					
						
							|  |  |  | 	// 		// optional, initial state setup...
 | 
					
						
							|  |  |  | 	// 		default: <function>,
 | 
					
						
							|  |  |  | 	// 	}
 | 
					
						
							|  |  |  | 	button: { | 
					
						
							|  |  |  | 		type: 'button', | 
					
						
							|  |  |  | 		text: null, | 
					
						
							|  |  |  | 		default: false, | 
					
						
							|  |  |  | 		html: '<div class="field button">'+ | 
					
						
							|  |  |  | 				'<span class="text"></span>'+ | 
					
						
							|  |  |  | 				'<button class="button"></button>'+ | 
					
						
							|  |  |  | 			'</div>', | 
					
						
							|  |  |  | 		test: function(val){ | 
					
						
							|  |  |  | 			return 'button' in val | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		set: function(field, value){ | 
					
						
							|  |  |  | 			var btn = $(field).find('button') | 
					
						
							|  |  |  | 				.click(value.button) | 
					
						
							|  |  |  | 				.html(value.text == null ? 'OK' : value.text) | 
					
						
							|  |  |  | 			if('default' in value){ | 
					
						
							|  |  |  | 				value.default(btn) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 		get: function(field){  | 
					
						
							|  |  |  | 			return $(field).attr('state') | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	}, | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | // Show a complex form dialog
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // This will build a form and collect it's data on "accept" specified by
 | 
					
						
							|  |  |  | // the config object...
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // config format:
 | 
					
						
							|  |  |  | //	{
 | 
					
						
							|  |  |  | //		// simple field...
 | 
					
						
							|  |  |  | //		<field-description>: <default-value>,
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | //		...
 | 
					
						
							|  |  |  | //	}	
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-07-01 17:16:12 +04:00
										 |  |  | // <field-description> and split in two with a "|" the section before will
 | 
					
						
							|  |  |  | // show as the field text and the text after as the tooltip.
 | 
					
						
							|  |  |  | // Example:
 | 
					
						
							|  |  |  | // 		"field text | field tooltip..."
 | 
					
						
							|  |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | // field's default value determines it's type:
 | 
					
						
							|  |  |  | // 	bool		- checkbox
 | 
					
						
							|  |  |  | // 	string		- textarea
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | //
 | 
					
						
							|  |  |  | // see FIELD_TYPES for supported field types.
 | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-06-20 02:41:29 +04:00
										 |  |  | // NOTE: if btn is set to false explicitly then no button will be 
 | 
					
						
							|  |  |  | // 		rendered in the form dialog.
 | 
					
						
							| 
									
										
										
										
											2013-07-01 17:16:12 +04:00
										 |  |  | // NOTE: to include a literal "|" in <field-description> just escape it
 | 
					
						
							|  |  |  | // 		like this: "\|"
 | 
					
						
							| 
									
										
										
										
											2013-06-20 02:41:29 +04:00
										 |  |  | //
 | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | // XXX add form testing...
 | 
					
						
							|  |  |  | // XXX add undefined field handling/reporting...
 | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | function formDialog(root, message, config, btn, cls){ | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 	cls = cls == null ? '' : cls | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 	btn = btn == null ? 'OK' : btn | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | 	root = root == null ? $('.viewer') : root | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 	var form = $('<div class="form"/>') | 
					
						
							|  |  |  | 	var data = {} | 
					
						
							|  |  |  | 	var res = $.Deferred() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 	// handle message and btn...
 | 
					
						
							| 
									
										
										
										
											2013-11-27 17:15:19 +04:00
										 |  |  | 	if(message.trim().length > 0){ | 
					
						
							|  |  |  | 		setTextWithTooltip(message, $('<div class="text"/>')) | 
					
						
							|  |  |  | 			.appendTo(form) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// build the form...
 | 
					
						
							|  |  |  | 	for(var t in config){ | 
					
						
							|  |  |  | 		var did_handling = false | 
					
						
							|  |  |  | 		for(var f in FIELD_TYPES){ | 
					
						
							|  |  |  | 			if(FIELD_TYPES[f].test(config[t])){ | 
					
						
							|  |  |  | 				var field = FIELD_TYPES[f] | 
					
						
							|  |  |  | 				var html = $(field.html) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-01 17:16:12 +04:00
										 |  |  | 				// setup text and data...
 | 
					
						
							| 
									
										
										
										
											2013-11-27 17:15:19 +04:00
										 |  |  | 				setTextWithTooltip(t, html.find('.text'), html) | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | 				if(field.set != null){ | 
					
						
							|  |  |  | 					field.set(html, config[t]) | 
					
						
							|  |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				if(field.get != null){ | 
					
						
							|  |  |  | 					// NOTE: this is here to isolate t and field.get values...
 | 
					
						
							|  |  |  | 					// 		...is there a better way???
 | 
					
						
							|  |  |  | 					var _ = (function(title, getter){ | 
					
						
							|  |  |  | 						html.on('resolve', function(evt, e){ | 
					
						
							|  |  |  | 							data[title] = getter(e) | 
					
						
							|  |  |  | 						}) | 
					
						
							|  |  |  | 					})(t, field.get) | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 				form.append(html) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				did_handling = true | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 				break | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// handle unresolved fields...
 | 
					
						
							|  |  |  | 		if(!did_handling){ | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | 			console.warn('formDialog: not all fields understood.') | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 			// XXX skipping field...
 | 
					
						
							|  |  |  | 			// XXX
 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 	// add button...
 | 
					
						
							| 
									
										
										
										
											2013-06-20 02:41:29 +04:00
										 |  |  | 	if(btn !== false){ | 
					
						
							|  |  |  | 		var button = $('<button class="accept">'+btn+'</button>') | 
					
						
							|  |  |  | 		form.append(button) | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		var button = null | 
					
						
							| 
									
										
										
										
											2013-06-20 02:41:29 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var overlay = showInOverlay(root, form) | 
					
						
							|  |  |  | 		.addClass('dialog ' + cls) | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		.on('accept', function(){ | 
					
						
							|  |  |  | 			form.find('.field').each(function(_, e){ | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 				$(e).trigger('resolve', [$(e)]) | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// XXX test if all required stuff is filled...
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:30:34 +04:00
										 |  |  | 			res.resolve(data, form) | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			hideOverlay(root) | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.on('close', function(){ | 
					
						
							|  |  |  | 			res.reject() | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 	if(button != null){ | 
					
						
							|  |  |  | 		button.click(function(){ | 
					
						
							|  |  |  | 			overlay.trigger('accept') | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-06-12 17:25:13 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-26 19:16:27 +04:00
										 |  |  | 	// focus an element...
 | 
					
						
							|  |  |  | 	// NOTE: if first element is a radio button set, focus the checked
 | 
					
						
							|  |  |  | 	//		element, else focus the first input...
 | 
					
						
							|  |  |  | 	form.ready(function(){  | 
					
						
							| 
									
										
										
										
											2013-11-26 19:42:08 +04:00
										 |  |  | 		// NOTE: we are using a timeout to avoid the user input that opened
 | 
					
						
							|  |  |  | 		// 		the dialog to end up in the first field...
 | 
					
						
							|  |  |  | 		setTimeout(function(){ | 
					
						
							|  |  |  | 			var elem = form.find('.field input').first() | 
					
						
							|  |  |  | 			if(elem.attr('type') == 'radio'){ | 
					
						
							|  |  |  | 				form.find('.field input:checked') | 
					
						
							|  |  |  | 					.focus() | 
					
						
							|  |  |  | 					.select() | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				elem | 
					
						
							|  |  |  | 					.focus() | 
					
						
							|  |  |  | 					.select() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}, 100) | 
					
						
							| 
									
										
										
										
											2013-11-26 19:16:27 +04:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | /************************************************ Standard dialogs ***/ | 
					
						
							| 
									
										
										
										
											2013-07-03 20:18:00 +04:00
										 |  |  | // NOTE: these return a deferred that will reflect the state of the 
 | 
					
						
							|  |  |  | // 		dialog, and the progress of the operations that it riggers...
 | 
					
						
							|  |  |  | //
 | 
					
						
							|  |  |  | // XXX might be a good idea to be able to block the ui (overlay + progress
 | 
					
						
							|  |  |  | // 		bar?) until some long/critical operations finish, to prevent the
 | 
					
						
							|  |  |  | // 		user from breaking things while the ui is inconsistent...
 | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | var _alert = alert | 
					
						
							|  |  |  | function alert(){ | 
					
						
							|  |  |  | 	var message = Array.apply(null, arguments).join(' ') | 
					
						
							| 
									
										
										
										
											2013-06-20 02:41:29 +04:00
										 |  |  | 	return formDialog(null, String(message), {}, false, 'alert') | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var _prompt = prompt | 
					
						
							|  |  |  | function prompt(message, dfl, btn){ | 
					
						
							|  |  |  | 	btn = btn == null ? 'OK' : btn | 
					
						
							|  |  |  | 	var res = $.Deferred() | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | 	formDialog(null, message, {'': ''+(dfl == null ? '' : dfl)}, btn, 'prompt') | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | 		.done(function(data){ res.resolve(data['']) }) | 
					
						
							|  |  |  | 		.fail(function(){ res.reject() }) | 
					
						
							| 
									
										
										
										
											2013-06-12 16:11:19 +04:00
										 |  |  | 	return res | 
					
						
							| 
									
										
										
										
											2013-06-12 14:45:48 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 01:37:30 +04:00
										 |  |  | /* | 
					
						
							|  |  |  | function confirm(){ | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-05 05:50:26 +04:00
										 |  |  | function detailedAlert(text, description, button){ | 
					
						
							|  |  |  | 	return formDialog(null, '', {'': { | 
					
						
							|  |  |  | 		html: $('<details/>') | 
					
						
							|  |  |  | 			.append($('<summary/>') | 
					
						
							|  |  |  | 				.html(text)) | 
					
						
							|  |  |  | 			.append($('<span/>') | 
					
						
							|  |  |  | 				.html(description)) | 
					
						
							|  |  |  | 	}}, button == null ? false : button, 'detailed-alert') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-13 19:42:42 +04:00
										 |  |  | // NOTE: this will not work without node-webkit...
 | 
					
						
							| 
									
										
										
										
											2013-06-13 17:25:38 +04:00
										 |  |  | function getDir(message, dfl, btn){ | 
					
						
							|  |  |  | 	btn = btn == null ? 'OK' : btn | 
					
						
							|  |  |  | 	dfl = dfl == null ? '' : dfl | 
					
						
							|  |  |  | 	var res = $.Deferred() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	formDialog(null, message, {'': {ndir: dfl}}, btn, 'getDir') | 
					
						
							|  |  |  | 		.done(function(data){ res.resolve(data['']) }) | 
					
						
							|  |  |  | 		.fail(function(){ res.reject() }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | /***************************************** Domain-specific dialogs ***/ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | // XXX do reporting...
 | 
					
						
							| 
									
										
										
										
											2013-07-07 02:20:22 +04:00
										 |  |  | // XXX would be nice to save settings...
 | 
					
						
							| 
									
										
										
										
											2013-07-07 03:19:41 +04:00
										 |  |  | // 		...might be good to use datalist...
 | 
					
						
							| 
									
										
										
										
											2013-06-27 17:29:53 +04:00
										 |  |  | function exportPreviewsDialog(state, dfl){ | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | 	dfl = dfl == null ? BASE_URL : dfl | 
					
						
							| 
									
										
										
										
											2013-06-27 17:29:53 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// XXX make this more generic...
 | 
					
						
							| 
									
										
										
										
											2013-07-03 07:03:46 +04:00
										 |  |  | 	// tell the user what state are we exporting...
 | 
					
						
							| 
									
										
										
										
											2013-06-27 17:29:53 +04:00
										 |  |  | 	if(state == null){ | 
					
						
							| 
									
										
										
										
											2013-12-01 06:12:57 +04:00
										 |  |  | 		var imgs = 0 | 
					
						
							|  |  |  | 		// NOTE: we are not using order or image count as these sets may
 | 
					
						
							|  |  |  | 		// 		be larger that the current crop...
 | 
					
						
							|  |  |  | 		DATA.ribbons.map(function(e){ | 
					
						
							|  |  |  | 			imgs += e.length | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 		state = toggleSingleImageMode('?') == 'on' ? 'current image' : state | 
					
						
							| 
									
										
										
										
											2013-12-01 06:12:57 +04:00
										 |  |  | 		state = state == null && isViewCropped() ?  | 
					
						
							|  |  |  | 			'cropped view: '+ | 
					
						
							|  |  |  | 				imgs+' images in '+ | 
					
						
							|  |  |  | 				DATA.ribbons.length+' ribbons'  | 
					
						
							|  |  |  | 			: state | 
					
						
							|  |  |  | 		state = state == null ? | 
					
						
							|  |  |  | 			'all: '+ | 
					
						
							|  |  |  | 				imgs+' images in '+ | 
					
						
							|  |  |  | 				DATA.ribbons.length+' ribbons'  | 
					
						
							|  |  |  | 			: state | 
					
						
							| 
									
										
										
										
											2013-06-27 17:29:53 +04:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | 	var res = $.Deferred() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-21 20:02:54 +04:00
										 |  |  | 	updateStatus('Export...').show() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-01 18:05:50 +04:00
										 |  |  | 	// NOTE: we are not defining the object in-place here because some 
 | 
					
						
							|  |  |  | 	// 		keys become unreadable with JS syntax preventing us from 
 | 
					
						
							|  |  |  | 	// 		splitting the key into several lines...
 | 
					
						
							|  |  |  | 	var cfg = {} | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 	// multiple images...
 | 
					
						
							|  |  |  | 	if(state != 'current image'){ | 
					
						
							|  |  |  | 		cfg['Image name pattern | '+ | 
					
						
							|  |  |  | 				'%f - full filename\n'+ | 
					
						
							|  |  |  | 				'%n - filename\n'+ | 
					
						
							|  |  |  | 				'%e - extension (with leading dot)\n'+ | 
					
						
							|  |  |  | 				'%(abc)m - if marked insert "abc"\n'+ | 
					
						
							|  |  |  | 				'%gid - log gid\n'+ | 
					
						
							|  |  |  | 				'%g - short gid\n'+ | 
					
						
							|  |  |  | 				'%I - global order\n'+ | 
					
						
							|  |  |  | 				'%i - current selection order'] = '%f' | 
					
						
							|  |  |  | 		cfg['Level directory name'] = 'fav' | 
					
						
							|  |  |  | 	// single image...
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		cfg['Image name pattern | '+ | 
					
						
							|  |  |  | 				'%f - full filename\n'+ | 
					
						
							|  |  |  | 				'%n - filename\n'+ | 
					
						
							|  |  |  | 				'%e - extension (with leading dot)\n'+ | 
					
						
							|  |  |  | 				'%(abc)m - if marked insert "abc"\n'+ | 
					
						
							|  |  |  | 				'%gid - log gid\n'+ | 
					
						
							| 
									
										
										
										
											2013-11-07 02:24:30 +04:00
										 |  |  | 				'%g - short gid\n'+ | 
					
						
							|  |  |  | 				'\n'+ | 
					
						
							|  |  |  | 				'NOTE: %i and %I are not supported for single\n'+ | 
					
						
							|  |  |  | 				'image exporting.'] = '%f' | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-08 07:07:26 +04:00
										 |  |  | 	cfg['Size | '+ | 
					
						
							|  |  |  | 			'The selected size is aproximate, the actual\n'+ | 
					
						
							| 
									
										
										
										
											2013-11-07 02:24:30 +04:00
										 |  |  | 			'preview will be copied from cache.\n'+ | 
					
						
							|  |  |  | 			'\n'+ | 
					
						
							| 
									
										
										
										
											2013-07-08 07:18:43 +04:00
										 |  |  | 			'NOTE: if not all previews are yet generated,\n'+ | 
					
						
							|  |  |  | 			'this will save the available previews, not all\n'+ | 
					
						
							|  |  |  | 			'of which may be of the right size, if this\n'+ | 
					
						
							|  |  |  | 			'happens wait till all the previews are done\n'+ | 
					
						
							|  |  |  | 			'and export again.'] = { | 
					
						
							| 
									
										
										
										
											2013-07-08 07:07:26 +04:00
										 |  |  | 		select: ['Original image'].concat(PREVIEW_SIZES.slice().sort()), | 
					
						
							|  |  |  | 		default: 1 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-07-08 07:37:57 +04:00
										 |  |  | 	cfg['Destination | '+ | 
					
						
							|  |  |  | 			'Relative paths are supported.\n\n'+ | 
					
						
							|  |  |  | 			'NOTE: All paths are relative to the curent\n'+ | 
					
						
							|  |  |  | 			'directory.'] = {ndir: dfl} | 
					
						
							| 
									
										
										
										
											2013-07-01 18:05:50 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var keys = Object.keys(cfg) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-21 04:11:33 +04:00
										 |  |  | 	formDialog(null, 'Export: <b>'+ state +'</b>.', cfg, 'OK', 'exportPreviewsDialog') | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | 		.done(function(data){ | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 			// get the form data...
 | 
					
						
							|  |  |  | 			var name = data[keys[0]] | 
					
						
							|  |  |  | 			if(state != 'current image'){ | 
					
						
							|  |  |  | 				var size = data[keys[2]] | 
					
						
							|  |  |  | 				var path = normalizePath(data[keys[3]])  | 
					
						
							|  |  |  | 				var dir = data[keys[1]] | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			} else { | 
					
						
							|  |  |  | 				var size = data[keys[1]] | 
					
						
							|  |  |  | 				var path = normalizePath(data[keys[2]]) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			size = size == 'Original image' ? Math.max.apply(null, PREVIEW_SIZES)*2 : parseInt(size)-5 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// do the actual exporting...
 | 
					
						
							| 
									
										
										
										
											2013-11-07 02:26:11 +04:00
										 |  |  | 			// full state...
 | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 			if(state != 'current image'){ | 
					
						
							|  |  |  | 				exportImagesTo(path, name, dir, size) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-07 02:26:11 +04:00
										 |  |  | 			// single image...
 | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 			} else { | 
					
						
							|  |  |  | 				exportImageTo(getImageGID(), path, name, size) | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-21 20:02:54 +04:00
										 |  |  | 			// XXX do real reporting...
 | 
					
						
							|  |  |  | 			showStatusQ('Copying data...') | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | 			res.resolve(data['']) | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-06-21 20:02:54 +04:00
										 |  |  | 		.fail(function(){  | 
					
						
							|  |  |  | 			showStatusQ('Export: canceled.') | 
					
						
							|  |  |  | 			res.reject()  | 
					
						
							|  |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-06-21 17:47:44 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return res | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-22 17:54:15 +04:00
										 |  |  | function loadDirectoryDialog(dfl){ | 
					
						
							| 
									
										
										
										
											2013-06-21 20:02:54 +04:00
										 |  |  | 	dfl = dfl == null ? BASE_URL : dfl | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	updateStatus('Open...').show() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-11-27 17:15:19 +04:00
										 |  |  | 	formDialog(null, 'Path to open | To see list of previously loaded urls press ctrl-H.', { | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 		'': {ndir: dfl}, | 
					
						
							| 
									
										
										
										
											2013-07-05 05:33:54 +04:00
										 |  |  | 		'Precess previews': true, | 
					
						
							| 
									
										
										
										
											2013-07-03 06:58:28 +04:00
										 |  |  | 	}, 'OK', 'loadDirectoryDialog') | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 		.done(function(data){ | 
					
						
							| 
									
										
										
										
											2013-07-03 06:58:28 +04:00
										 |  |  | 			var path = normalizePath(data[''].trim()) | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 			var process_previews = data['Precess previews'] | 
					
						
							| 
									
										
										
										
											2013-07-03 06:58:28 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-21 22:57:16 +04:00
										 |  |  | 			// reset the modes...
 | 
					
						
							|  |  |  | 			toggleSingleImageMode('off') | 
					
						
							|  |  |  | 			toggleSingleRibbonMode('off') | 
					
						
							| 
									
										
										
										
											2013-06-23 03:14:04 +04:00
										 |  |  | 			toggleMarkedOnlyView('off') | 
					
						
							| 
									
										
										
										
											2013-06-21 22:57:16 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-07-03 06:58:28 +04:00
										 |  |  | 			// do the loading...
 | 
					
						
							| 
									
										
										
										
											2013-07-08 04:11:04 +04:00
										 |  |  | 			statusNotify(loadDir(path, !process_previews)) | 
					
						
							|  |  |  | 				/* | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 				.done(function(){ | 
					
						
							| 
									
										
										
										
											2013-07-05 05:33:54 +04:00
										 |  |  | 					if(process_previews){  | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 						showStatusQ('Previews: processing started...') | 
					
						
							| 
									
										
										
										
											2013-07-03 06:58:28 +04:00
										 |  |  | 						// generate/attach previews...
 | 
					
						
							| 
									
										
										
										
											2013-07-03 06:42:14 +04:00
										 |  |  | 						makeImagesPreviewsQ(DATA.order)  | 
					
						
							|  |  |  | 							.done(function(){  | 
					
						
							|  |  |  | 								showStatusQ('Previews: processing done.') | 
					
						
							|  |  |  | 							}) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2013-07-08 04:11:04 +04:00
										 |  |  | 				*/ | 
					
						
							| 
									
										
										
										
											2013-11-25 07:43:15 +04:00
										 |  |  | 				.done(function(){ | 
					
						
							|  |  |  | 					// XXX is this the right place for this???
 | 
					
						
							|  |  |  | 					pushURLHistory(BASE_URL) | 
					
						
							|  |  |  | 				}) | 
					
						
							| 
									
										
										
										
											2013-06-21 20:02:54 +04:00
										 |  |  | 		}) | 
					
						
							|  |  |  | 		.fail(function(){ | 
					
						
							|  |  |  | 			showStatusQ('Open: canceled.') | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | // XXX get EXIF, IPTC...
 | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | function showImageInfo(){ | 
					
						
							|  |  |  | 	var gid = getImageGID(getImage()) | 
					
						
							|  |  |  | 	var r = getRibbonIndex(getRibbon()) | 
					
						
							|  |  |  | 	var data = IMAGES[gid] | 
					
						
							|  |  |  | 	var orientation = data.orientation | 
					
						
							|  |  |  | 	orientation = orientation == null ? 0 : orientation | 
					
						
							|  |  |  | 	var flipped = data.flipped | 
					
						
							|  |  |  | 	flipped = flipped == null ? '' : ', flipped '+flipped+'ly' | 
					
						
							|  |  |  | 	var order = DATA.order.indexOf(gid) | 
					
						
							| 
									
										
										
										
											2013-10-18 05:03:11 +04:00
										 |  |  | 	var name = getImageFileName(gid) | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 	var date = new Date(data.ctime * 1000) | 
					
						
							| 
									
										
										
										
											2013-09-09 15:56:39 +04:00
										 |  |  | 	var comment = data.comment | 
					
						
							|  |  |  | 	comment = comment == null ? '' : comment | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 	comment = comment.replace(/\n/g, '<br>') | 
					
						
							| 
									
										
										
										
											2013-12-08 21:53:05 +04:00
										 |  |  | 	var tags = data.tags | 
					
						
							|  |  |  | 	tags = tags == null ? '' : tags.join(', ') | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | 	return formDialog(null, | 
					
						
							|  |  |  | 			('<div>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 				'<h2>"'+ name +'"</h2>'+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				'<table>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | 					// basic info...
 | 
					
						
							|  |  |  | 					'<tr><td colspan="2"><hr></td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 					'<tr><td>GID: </td><td>'+ gid +'</td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-11-07 02:20:20 +04:00
										 |  |  | 					'<tr><td>Date: </td><td>'+ date +'</td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-10-18 05:03:11 +04:00
										 |  |  | 					'<tr><td>Path: </td><td>"'+ unescape(data.path) +'"</td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 					'<tr><td>Orientation: </td><td>'+ orientation +'°'+flipped+'</td></tr>'+ | 
					
						
							|  |  |  | 					'<tr><td>Order: </td><td>'+ order +'</td></tr>'+ | 
					
						
							|  |  |  | 					'<tr><td>Position (ribbon): </td><td>'+ (DATA.ribbons[r].indexOf(gid)+1) + | 
					
						
							|  |  |  | 						'/'+ DATA.ribbons[r].length +'</td></tr>'+ | 
					
						
							|  |  |  | 					'<tr><td>Position (global): </td><td>'+ (order+1) +'/'+ DATA.order.length +'</td></tr>'+ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// editable fields...
 | 
					
						
							|  |  |  | 					'<tr><td colspan="2"><hr></td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:30:34 +04:00
										 |  |  | 					// XXX this expanding to a too big size will mess up the screen...
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 					// 		add per editable and global dialog max-height and overflow
 | 
					
						
							|  |  |  | 					'<tr><td>Comment: </td><td class="comment" contenteditable>'+ comment +'</td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-12-08 21:53:05 +04:00
										 |  |  | 					'<tr><td>Tags: </td><td class="tags" contenteditable>'+ tags +'</td></tr>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 				'</table>'+ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | 				'<br>'+ | 
					
						
							|  |  |  | 			'</div>'), | 
					
						
							|  |  |  | 			// NOTE: without a save button, there will be no way to accept the 
 | 
					
						
							|  |  |  | 			// 		form on a touch-only device...
 | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | 			{}, 'OK', 'showImageInfoDialog') | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		// save the form data...
 | 
					
						
							| 
									
										
										
										
											2013-09-13 17:30:34 +04:00
										 |  |  | 		.done(function(_, form){ | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | 			// comment...
 | 
					
						
							| 
									
										
										
										
											2013-09-13 21:51:58 +04:00
										 |  |  | 			var ncomment = form.find('.comment').html() | 
					
						
							|  |  |  | 			if(ncomment != comment){ | 
					
						
							|  |  |  | 				ncomment = ncomment.replace(/<br>/ig, '\n') | 
					
						
							|  |  |  | 				if(ncomment.trim() == ''){ | 
					
						
							|  |  |  | 					delete data.comment | 
					
						
							|  |  |  | 				} else { | 
					
						
							|  |  |  | 					data.comment = ncomment | 
					
						
							|  |  |  | 				} | 
					
						
							| 
									
										
										
										
											2013-12-15 03:38:15 +04:00
										 |  |  | 				imageUpdated(gid) | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-09-13 17:44:14 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-08 21:53:05 +04:00
										 |  |  | 			// tags...
 | 
					
						
							|  |  |  | 			var ntags = form.find('.tags').text().trim() | 
					
						
							|  |  |  | 			if(ntags != tags){ | 
					
						
							|  |  |  | 				ntags = ntags.split(/\s*,\s*/) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-08 22:14:51 +04:00
										 |  |  | 				updateTags(ntags, gid) | 
					
						
							| 
									
										
										
										
											2013-12-08 21:53:05 +04:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2013-09-13 17:21:14 +04:00
										 |  |  | 		}) | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-10 19:20:35 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2014-01-01 05:27:16 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX need a propper:
 | 
					
						
							|  |  |  | // 		- update mechanics...
 | 
					
						
							|  |  |  | // 		- save mechanics
 | 
					
						
							|  |  |  | function makeCommentPanel(panel){ | 
					
						
							|  |  |  | 	return makeSubPanel( | 
					
						
							|  |  |  | 			'Info: Comment',  | 
					
						
							|  |  |  | 			$('Comment: <div class="comment" contenteditable/>'), | 
					
						
							|  |  |  | 			panel,  | 
					
						
							|  |  |  | 			true,  | 
					
						
							|  |  |  | 			true) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:24:00 +04:00
										 |  |  | /*********************************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function setupUI(viewer){ | 
					
						
							|  |  |  | 	console.log('UI: setup...') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:33:26 +04:00
										 |  |  | 	setupIndicators() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:24:00 +04:00
										 |  |  | 	return viewer | 
					
						
							|  |  |  | 		.click(function(){ | 
					
						
							|  |  |  | 			if($('.ribbon').length == 0){ | 
					
						
							|  |  |  | 				loadDirectoryDialog() | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		.on([ | 
					
						
							|  |  |  | 				'focusingImage', | 
					
						
							| 
									
										
										
										
											2013-12-18 21:48:40 +04:00
										 |  |  | 				'fittingImages', | 
					
						
							|  |  |  | 				//'updatingImageProportions',
 | 
					
						
							| 
									
										
										
										
											2013-12-15 14:24:00 +04:00
										 |  |  | 			].join(' '),  | 
					
						
							|  |  |  | 			function(){ | 
					
						
							|  |  |  | 				updateCurrentMarker() | 
					
						
							|  |  |  | 			}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | SETUP_BINDINGS.push(setupUI) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-06-11 03:10:01 +04:00
										 |  |  | /********************************************************************** | 
					
						
							|  |  |  | * vim:set ts=4 sw=4 nowrap :										 */ |