| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | <html> | 
					
						
							|  |  |  | <head> | 
					
						
							|  |  |  | <title>ImageGrid.Viewer</title> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <style> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .viewer { | 
					
						
							|  |  |  | 	position: relative; | 
					
						
							|  |  |  | 	width: 800px; | 
					
						
							|  |  |  | 	height: 600px; | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 	overflow: hidden; | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	border: solid blue 1px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .ribbon-set { | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 	position: absolute; | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | .ribbon-set:empty:after { | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	top: 0px; | 
					
						
							|  |  |  | 	left: 0px; | 
					
						
							|  |  |  | 	width: 100%; | 
					
						
							|  |  |  | 	height: 100%; | 
					
						
							|  |  |  | 	content: "Empty"; | 
					
						
							|  |  |  | 	text-align: center; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .ribbon { | 
					
						
							|  |  |  | 	position: relative; | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	height: auto; | 
					
						
							|  |  |  | 	min-width: 0px; | 
					
						
							|  |  |  | 	overflow: visible; | 
					
						
							|  |  |  | 	white-space: nowrap; | 
					
						
							|  |  |  | 	font-size: 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	margin-top: 20px; | 
					
						
							|  |  |  | 	margin-bottom: 20px; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | .ribbon:empty { | 
					
						
							|  |  |  | 	display: none; | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | .ribbon:first-child { | 
					
						
							|  |  |  | 	margin-top: 0px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .ribbon:last-child { | 
					
						
							|  |  |  | 	margin-bottom: 0px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .image { | 
					
						
							|  |  |  | 	position: relative; | 
					
						
							|  |  |  | 	display: inline-block; | 
					
						
							|  |  |  | 	vertical-align: middle; | 
					
						
							|  |  |  | 	text-align;left; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 	width: 300px; | 
					
						
							|  |  |  | 	height: 300px; | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	font-size: 12pt; | 
					
						
							| 
									
										
										
										
											2013-04-29 23:07:47 +04:00
										 |  |  | 	overflow: hidden; | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	background: black; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 	box-sizing: border-box; | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	border: solid gray 1px; | 
					
						
							|  |  |  | 	color: white; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .current.image { | 
					
						
							|  |  |  | 	background: red; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:07:47 +04:00
										 |  |  | /* dot mark... */ | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | .marked.image:after { | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	position: absolute; | 
					
						
							|  |  |  | 	content: ""; | 
					
						
							|  |  |  | 	font-size: 0pt; | 
					
						
							|  |  |  | 	border: none; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:07:47 +04:00
										 |  |  | 	width: 15px; | 
					
						
							|  |  |  | 	height: 15px; | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	bottom: 5px; | 
					
						
							|  |  |  | 	right: 5px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	border-radius: 50%; | 
					
						
							|  |  |  | 	background: blue; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:07:47 +04:00
										 |  |  | /* corner mark... (a-la bookmarks in PortableMag) */ | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | .marked.image:after { | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	position: absolute; | 
					
						
							|  |  |  | 	content: ""; | 
					
						
							|  |  |  | 	font-size: 0pt; | 
					
						
							|  |  |  | 	border: none; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	width: 30px; | 
					
						
							|  |  |  | 	height: 30px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	top: -15px; | 
					
						
							|  |  |  | 	right: -15px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	background: blue; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	-webkit-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-moz-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-o-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-ms-transform: rotate(45deg); | 
					
						
							|  |  |  | 	transform: rotate(45deg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | */ | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | .marked-only.viewer:after { | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	position: absolute; | 
					
						
							|  |  |  | 	content: "Showing marked images only"; | 
					
						
							|  |  |  | 	font-size: 14pt; | 
					
						
							|  |  |  | 	border: none; | 
					
						
							|  |  |  | 	color: blue; | 
					
						
							|  |  |  | 	width: auto; | 
					
						
							|  |  |  | 	height: auto; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	top: 10px; | 
					
						
							|  |  |  | 	right: 10px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .marked-only .image:not(.marked) { | 
					
						
							|  |  |  | 	display: none; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .marked-only .marked.image:after { | 
					
						
							|  |  |  | 	display: none; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | .up-indicator, | 
					
						
							|  |  |  | .down-indicator { | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	position: absolute; | 
					
						
							|  |  |  | 	content: ""; | 
					
						
							|  |  |  | 	top: 0px; | 
					
						
							|  |  |  | 	left: 50%; | 
					
						
							|  |  |  | 	height: 50px; | 
					
						
							|  |  |  | 	width: 100px; | 
					
						
							|  |  |  | 	margin-left: -50px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	overflow: hidden; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cursor: hand; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .up-indicator:after, | 
					
						
							|  |  |  | .down-indicator:after { | 
					
						
							|  |  |  | 	display: inline-block; | 
					
						
							|  |  |  | 	position: absolute; | 
					
						
							|  |  |  | 	content: ""; | 
					
						
							|  |  |  | 	width: 50px; | 
					
						
							|  |  |  | 	height: 50px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	bottom: -25px; | 
					
						
							|  |  |  | 	left: 25px; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	background: yellow; | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	-webkit-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-moz-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-o-transform: rotate(45deg); | 
					
						
							|  |  |  | 	-ms-transform: rotate(45deg); | 
					
						
							|  |  |  | 	transform: rotate(45deg); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .down-indicator { | 
					
						
							|  |  |  | 	top: auto; | 
					
						
							|  |  |  | 	bottom: 0px; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .down-indicator:after { | 
					
						
							|  |  |  | 	top: -25px; | 
					
						
							|  |  |  | 	bottom: auto; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | /* default state */ | 
					
						
							|  |  |  | .up-indicator, | 
					
						
							|  |  |  | .down-indicator { | 
					
						
							|  |  |  | 	display: none | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | </style> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script src="jquery.js"></script> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 23:07:07 +04:00
										 |  |  | <script src="lib/jli.js"></script> | 
					
						
							|  |  |  | <script src="lib/keyboard.js"></script> | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | <script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Viewer Generation III | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Split the API into the following sections: | 
					
						
							|  |  |  | 	- main control actions | 
					
						
							|  |  |  | 		do main domain tasks like image and ribbon manipulation. | 
					
						
							|  |  |  | 	- serialization and deserialization | 
					
						
							|  |  |  | 		load and save data | 
					
						
							|  |  |  | 	- UI | 
					
						
							|  |  |  | 		basic align, animation and modes | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | function flashIndicator(direction){ | 
					
						
							|  |  |  | 	$(direction == 'prev' ? '.up-indicator' : '.down-indicator').fadeIn(200).fadeOut(200) | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | var toggleMarkedOnlyView = createCSSClassToggler('.viewer', 'marked-only', | 
					
						
							|  |  |  | 	function(){ | 
					
						
							|  |  |  | 		var cur = $('.current.image') | 
					
						
							|  |  |  | 		// current is marked... | 
					
						
							|  |  |  | 		if(cur.hasClass('marked')){ | 
					
						
							|  |  |  | 			centerImage(null, 'css') | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		}  | 
					
						
							|  |  |  | 		// there is a marked image in this ribbon... | 
					
						
							|  |  |  | 		var target = getImageBefore(cur, null, true) | 
					
						
							|  |  |  | 		if(target.length > 0){ | 
					
						
							|  |  |  | 			centerImage(focusImage(target), 'css') | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		// get marked image from other ribbons... | 
					
						
							|  |  |  | 		prevRibbon() | 
					
						
							|  |  |  | 		if($('.current.image').hasClass('marked')){ | 
					
						
							|  |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		nextRibbon() | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX add ability to take all marked images and open them in a separate view... | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | var toggleImageMark = createCSSClassToggler('.current.image', 'marked') | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | // mode can be: | 
					
						
							|  |  |  | //	- 'ribbon' | 
					
						
							|  |  |  | //	- 'all' | 
					
						
							|  |  |  | function removeImageMarks(mode){ | 
					
						
							|  |  |  | 	// remove marks from current ribbon (default)... | 
					
						
							|  |  |  | 	if(mode == 'ribbon' || mode == null){ | 
					
						
							|  |  |  | 		return $('.current.image') | 
					
						
							|  |  |  | 			.closest('.ribbon') | 
					
						
							|  |  |  | 				.find('.marked') | 
					
						
							|  |  |  | 					.removeClass('marked') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remove all marks... | 
					
						
							|  |  |  | 	} else if(mode == 'all'){ | 
					
						
							|  |  |  | 		return $('.marked') | 
					
						
							|  |  |  | 			.removeClass('marked') | 
					
						
							|  |  |  | 	}  | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function markAll(mode){ | 
					
						
							|  |  |  | 	// remove marks from current ribbon (default)... | 
					
						
							|  |  |  | 	if(mode == 'ribbon' || mode == null){ | 
					
						
							|  |  |  | 		return $('.current.image') | 
					
						
							|  |  |  | 			.closest('.ribbon') | 
					
						
							|  |  |  | 				.find('.image:not(.marked)') | 
					
						
							|  |  |  | 					.addClass('marked') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// remove all marks... | 
					
						
							|  |  |  | 	} else if(mode == 'all'){ | 
					
						
							|  |  |  | 		return $('.image:not(.marked)').addClass('marked') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:38:16 +04:00
										 |  |  | function invertImageMarks(){ | 
					
						
							|  |  |  | 	return $('.current.image') | 
					
						
							|  |  |  | 		.closest('.ribbon') | 
					
						
							|  |  |  | 			.find('.image') | 
					
						
							|  |  |  | 				.toggleClass('marked') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // this will toggle marks in the current continuous section of marked  | 
					
						
							|  |  |  | // or unmarked images... | 
					
						
							|  |  |  | function toggleImageMarkBlock(image){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// we need to invert this... | 
					
						
							|  |  |  | 	var state = toggleImageMark() | 
					
						
							|  |  |  | 	var _convert = function(){ | 
					
						
							|  |  |  | 		if(toggleImageMark(this, '?') == state){ | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		toggleImageMark(this, state) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	image.nextAll('.image').each(_convert) | 
					
						
							|  |  |  | 	image.prevAll('.image').each(_convert) | 
					
						
							|  |  |  | 	return state | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | function nextMarkedImage(){ | 
					
						
							|  |  |  | 	// XXX | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | function prevMarkedImage(){ | 
					
						
							|  |  |  | 	// XXX | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:38:16 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 23:38:16 +04:00
										 |  |  | // XXX should we use the createCSSClassToggler for this? | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | // XXX revise: does extra stuff... | 
					
						
							|  |  |  | function toggleImageProportions(mode){ | 
					
						
							|  |  |  | 	var image = $('.image') | 
					
						
							|  |  |  | 	var h = image.outerHeight(true) | 
					
						
							|  |  |  | 	var w = image.outerWidth(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if(mode == '?'){ | 
					
						
							|  |  |  | 		return h != w ? 'viewer' : 'square' | 
					
						
							| 
									
										
										
										
											2013-04-29 19:12:19 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	// square... | 
					
						
							|  |  |  | 	} else if(h != w || mode == 'square'){ | 
					
						
							|  |  |  | 		var size = Math.min(w, h) | 
					
						
							|  |  |  | 		image.css({ | 
					
						
							|  |  |  | 			width: size, | 
					
						
							|  |  |  | 			height: size | 
					
						
							|  |  |  | 		}) | 
					
						
							|  |  |  | 		centerImage(null, 'css') | 
					
						
							|  |  |  | 		return 'square' | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// viewer size... | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		var viewer = $('.viewer') | 
					
						
							|  |  |  | 		var W = viewer.innerWidth() | 
					
						
							|  |  |  | 		var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if(W > H){ | 
					
						
							|  |  |  | 			image.css('width', W * h/H) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			image.css('height', H * w/W) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		centerImage(null, 'css') | 
					
						
							|  |  |  | 		return 'viewer' | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: to avoid state sync problems this should clone an image if  | 
					
						
							|  |  |  | //		one is available... | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | function createImage(n){ | 
					
						
							|  |  |  | 	if(n == null){ | 
					
						
							|  |  |  | 		if(window._n == null){ | 
					
						
							|  |  |  | 			window._n = 0 | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		n = _n | 
					
						
							|  |  |  | 		_n += 1 | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	var img = $('.image') | 
					
						
							|  |  |  | 	if(img.length > 0){ | 
					
						
							|  |  |  | 		return img.first().clone() | 
					
						
							|  |  |  | 					.attr({ | 
					
						
							|  |  |  | 						'order': n, | 
					
						
							|  |  |  | 						// need to strip extra classes... | 
					
						
							|  |  |  | 						'class': 'image' | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		return $('<div order="'+n+'" class="image"/>') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function createRibbon(){ | 
					
						
							|  |  |  | 	return $('<div class="ribbon"/>') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: if this returns null, it means that the element is smallest in  | 
					
						
							|  |  |  | //		target ribbon -- first position. | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | function getImageBefore(image, ribbon, visible_only){ | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	image = $(image) | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 	if(ribbon == null){ | 
					
						
							|  |  |  | 		ribbon = image.closest('.ribbon') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// pre marked-only mode... | 
					
						
							|  |  |  | 	//var images = $(ribbon).find('.image') | 
					
						
							|  |  |  | 	if(visible_only){ | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 		var images = $(ribbon).find('.image').filter(':visible') | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		var images = $(ribbon).find('.image') | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	var order = image.attr('order') | 
					
						
							|  |  |  | 	var prev = null | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	images.each(function(){ | 
					
						
							|  |  |  | 		if(order < $(this).attr('order')){ | 
					
						
							|  |  |  | 			return false | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		prev = this | 
					
						
							|  |  |  | 	}) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	return $(prev) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // basic navigation actions... | 
					
						
							|  |  |  | function nextImage(){ | 
					
						
							|  |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			// pre marked-only mode... | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 			//$('.current.image').next('.image'))) | 
					
						
							|  |  |  | 			$('.current.image').next('.image:visible'))) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function prevImage(){ | 
					
						
							|  |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			// pre marked-only mode... | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 			//$('.current.image').prev('.image'))) | 
					
						
							|  |  |  | 			$('.current.image').prev('.image:visible'))) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function firstImage(){ | 
					
						
							|  |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			// pre marked-only mode... | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 			//$('.current.image').closest('.ribbon').find('.image').first())) | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			$('.current.image').closest('.ribbon').find('.image').filter(':visible').first())) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function lastImage(){ | 
					
						
							|  |  |  | 	return centerImage( | 
					
						
							|  |  |  | 		focusImage( | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			// pre marked-only mode... | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 			//$('.current.image').closest('.ribbon').find('.image').last())) | 
					
						
							| 
									
										
										
										
											2013-04-30 00:33:49 +04:00
										 |  |  | 			$('.current.image').closest('.ribbon').find('.image').filter(':visible').last())) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // NOTE: if moving is 'next' these will chose the image after the current's order. | 
					
						
							|  |  |  | // NOTE: if an image with the same order is found, moving argument has no effect. | 
					
						
							| 
									
										
										
										
											2013-04-30 01:34:26 +04:00
										 |  |  | // XXX get move direction... | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | function prevRibbon(moving){ | 
					
						
							|  |  |  | 	var cur = $('.current.image') | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 	// pre marked-only mode... | 
					
						
							|  |  |  | 	//var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon')) | 
					
						
							|  |  |  | 	var target = getImageBefore(cur, cur.closest('.ribbon').prev('.ribbon:visible'), true) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ | 
					
						
							|  |  |  | 		var next = target.next('.image') | 
					
						
							|  |  |  | 		target = next.length > 0 ? next : target | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return centerImage(focusImage(target)) | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-30 01:34:26 +04:00
										 |  |  | // XXX get move direction... | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | function nextRibbon(moving){ | 
					
						
							|  |  |  | 	var cur = $('.current.image') | 
					
						
							| 
									
										
										
										
											2013-04-30 00:28:47 +04:00
										 |  |  | 	// pre marked-only mode... | 
					
						
							|  |  |  | 	//var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon')) | 
					
						
							|  |  |  | 	var target = getImageBefore(cur, cur.closest('.ribbon').next('.ribbon:visible'), true) | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	if(moving == 'next' && cur.attr('order') != target.attr('order')){ | 
					
						
							|  |  |  | 		var next = target.next('.image') | 
					
						
							|  |  |  | 		target = next.length > 0 ? next : target | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return centerImage(focusImage(target)) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | function shiftTo(image, ribbon){ | 
					
						
							|  |  |  | 	var target = getImageBefore(image, ribbon) | 
					
						
							|  |  |  | 	var cur_ribbon = image.closest('.ribbon') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// insert before the first image if nothing is before the target... | 
					
						
							| 
									
										
										
										
											2013-04-30 01:46:49 +04:00
										 |  |  | 	if(target.length == 0){ | 
					
						
							|  |  |  | 		image.prependTo($(ribbon)) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		image.insertAfter(target) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// if removing last image out of a ribbon, remove the ribbon.... | 
					
						
							|  |  |  | 	if(cur_ribbon.find('.image').length == 0){ | 
					
						
							|  |  |  | 		cur_ribbon.remove() | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return image | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function shiftImage(direction, image, force_create_ribbon){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		// XXX need to make this context specific... | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		image = $(image) | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-30 01:46:49 +04:00
										 |  |  | 	var old_ribbon = image.closest('.ribbon') | 
					
						
							|  |  |  | 	var ribbon = old_ribbon[direction]('.ribbon') | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// need to create a new ribbon... | 
					
						
							|  |  |  | 	if(ribbon.length == 0 || force_create_ribbon == true){ | 
					
						
							|  |  |  | 		ribbon = createRibbon()['insert' + (direction == 'prev'  | 
					
						
							|  |  |  | 												? 'Before'  | 
					
						
							| 
									
										
										
										
											2013-04-30 01:46:49 +04:00
										 |  |  | 												: 'After')](old_ribbon) | 
					
						
							|  |  |  | 		shiftTo(image, ribbon) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	} else { | 
					
						
							|  |  |  | 		shiftTo(image, ribbon) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return image | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // short-hand methods... | 
					
						
							| 
									
										
										
										
											2013-04-30 01:34:26 +04:00
										 |  |  | // XXX get move direction... | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | function _shiftImageTo(image, direction, moving, force_create_ribbon){ | 
					
						
							|  |  |  | 	if(image == null){ | 
					
						
							|  |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:34:26 +04:00
										 |  |  | 	// account move for direction... | 
					
						
							|  |  |  | 	// XXX get the value from some place more logical than the argument... | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	var a = moving == 'prev' ? 'prev' : 'next'  | 
					
						
							|  |  |  | 	var b = moving == 'prev' ? 'next' : 'prev'  | 
					
						
							|  |  |  | 	var target = image[a]('.image') | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	target = target.length == 0 ? image[b]() : target | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// XXX should this be in here or coupled later via an event??? | 
					
						
							|  |  |  | 	flashIndicator(direction) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	shiftImage(direction, image, force_create_ribbon) | 
					
						
							| 
									
										
										
										
											2013-04-30 01:46:49 +04:00
										 |  |  | 	// XXX does this need to be animated??? | 
					
						
							|  |  |  | 	return centerImage(focusImage(target), 'css') | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | function shiftImageUp(image){ | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	return _shiftImageTo(image, 'prev') | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function shiftImageDown(image){ | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	return _shiftImageTo(image, 'next') | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function shiftImageUpNewRibbon(image){ | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	return _shiftImageTo(image, 'prev', true) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | function shiftImageDownNewRibbon(image){ | 
					
						
							| 
									
										
										
										
											2013-04-30 01:30:02 +04:00
										 |  |  | 	return _shiftImageTo(image, 'prev', false) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // TODO manual image ordering (shiftLeft/shiftRight functions) | 
					
						
							|  |  |  | // XXX | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:33:38 +04:00
										 |  |  | function focusImage(image){ | 
					
						
							|  |  |  | 	image.closest('.viewer').find('.current.image').removeClass('current') | 
					
						
							|  |  |  | 	return image.addClass('current') | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 23:07:07 +04:00
										 |  |  | // Alignment API... | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | // ...tried to make this as brain-dead-stupidly-simple as possible... | 
					
						
							|  |  |  | function relativeVisualPosition(outer, inner){ | 
					
						
							|  |  |  | 	outer = $(outer).offset() | 
					
						
							|  |  |  | 	inner = $(inner).offset() | 
					
						
							|  |  |  | 	return { | 
					
						
							|  |  |  | 		top: inner.top - outer.top, | 
					
						
							|  |  |  | 		left: inner.left - outer.left | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // This appears to work well with scaling... | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | // XXX make this more configurable... | 
					
						
							| 
									
										
										
										
											2013-04-29 02:57:11 +04:00
										 |  |  | // XXX this only works for square images... | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | function centerImage(image, mode){ | 
					
						
							|  |  |  | 	if(mode == null){ | 
					
						
							|  |  |  | 		//mode = 'css' | 
					
						
							|  |  |  | 		mode = 'animate' | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2013-04-29 22:54:04 +04:00
										 |  |  | 	if(image == null || image.length == 0){ | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 		image = $('.current.image') | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	var viewer = $('.viewer') | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | 	// XXX should these be "inner"??? | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 	var W = viewer.innerWidth() | 
					
						
							|  |  |  | 	var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var ribbons = $('.ribbon-set') | 
					
						
							|  |  |  | 	var scale = getElementScale(ribbons) | 
					
						
							| 
									
										
										
										
											2013-04-29 02:57:11 +04:00
										 |  |  | 	// NOTE: these are scalable, this needs to get normalized... | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | 	var w = image.outerWidth()*scale | 
					
						
							|  |  |  | 	var h = image.outerHeight()*scale | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	var pos = relativeVisualPosition(viewer, image) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// zero out top/left if set to anything other than a specific number... | 
					
						
							|  |  |  | 	var t = parseFloat(ribbons.css('top')) | 
					
						
							|  |  |  | 	t = t ? t : 0 | 
					
						
							|  |  |  | 	var l = parseFloat(ribbons.css('left')) | 
					
						
							|  |  |  | 	l = l ? l : 0 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// do the actual work... | 
					
						
							|  |  |  | 	return ribbons[mode]({ | 
					
						
							|  |  |  | 		'top': t - pos.top + (H - h)/2, | 
					
						
							| 
									
										
										
										
											2013-04-29 02:57:11 +04:00
										 |  |  | 		'left': l - pos.left + (W - w)/2 | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 	}) | 
					
						
							| 
									
										
										
										
											2013-04-26 23:07:07 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | function fitNImages(n){ | 
					
						
							|  |  |  | 	var image = $('.current.image') | 
					
						
							|  |  |  | 	var size = image.outerHeight(true) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var viewer = $('.viewer') | 
					
						
							|  |  |  | 	var W = viewer.innerWidth() | 
					
						
							|  |  |  | 	var H = viewer.innerHeight() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	var scale = Math.min(W / (size * n), H / size) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 02:57:11 +04:00
										 |  |  | 	// XXX if animating, the next two likes must be animated together... | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | 	setElementScale($('.ribbon-set'), scale) | 
					
						
							|  |  |  | 	centerImage(image, 'css') | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | // NOTE: this is on purpose done relative... | 
					
						
							|  |  |  | function clickHandler(evt){ | 
					
						
							|  |  |  | 	var img = $(evt.target).closest('.image') | 
					
						
							| 
									
										
										
										
											2013-04-29 01:59:59 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	centerImage( | 
					
						
							|  |  |  | 		focusImage(img)) | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-29 02:31:01 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | // setup... | 
					
						
							|  |  |  | $(function(){ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// populate the viewer... | 
					
						
							|  |  |  | 	var r = createRibbon() | 
					
						
							|  |  |  | 	var images = [] | 
					
						
							|  |  |  | 	for(var i=0; i < 40; i++){ | 
					
						
							|  |  |  | 		images.push(createImage().text(i)[0])  | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	r.append($(images)) | 
					
						
							|  |  |  | 	var rr = r.clone() | 
					
						
							|  |  |  | 	var rrr = r.clone() | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	$('.ribbon-set') | 
					
						
							|  |  |  | 		.append(r) | 
					
						
							|  |  |  | 		.append(rr) | 
					
						
							|  |  |  | 		.append(rrr) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// NOTE: this is global so as to not to add any extra complexity to  | 
					
						
							|  |  |  | 	//		the internal workings... | 
					
						
							|  |  |  | 	$('.viewer').click(clickHandler) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </head> | 
					
						
							|  |  |  | <body> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- This is the basic viewer structure...
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Unpopulated | 
					
						
							|  |  |  | NOTE: there can be only .ribbon-set element. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <div class="viewer"> | 
					
						
							|  |  |  | 	<div class="ribbon-set"></div> | 
					
						
							|  |  |  | </div> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | Populated | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <div class="viewer"> | 
					
						
							|  |  |  | 	<div class="ribbon-set"> | 
					
						
							|  |  |  | 		<div class="ribbon"> | 
					
						
							|  |  |  | 			<div class="image"></div> | 
					
						
							|  |  |  | 			<div class="image"></div> | 
					
						
							|  |  |  | 		</div> | 
					
						
							|  |  |  | 		<div class="ribbon"> | 
					
						
							|  |  |  | 			<div class="image"></div> | 
					
						
							|  |  |  | 			<div class="current image"></div> | 
					
						
							|  |  |  | 			<div class="image"></div> | 
					
						
							|  |  |  | 			<div class="image"></div> | 
					
						
							|  |  |  | 		</div> | 
					
						
							|  |  |  | 	</div> | 
					
						
							|  |  |  | </div> | 
					
						
							|  |  |  | --> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <div class="viewer"> | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | 	<div class="ribbon-set"></div> | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2013-04-30 01:34:26 +04:00
										 |  |  | 	<!-- XXX should these be here??? --> | 
					
						
							| 
									
										
										
										
											2013-04-30 00:54:32 +04:00
										 |  |  | 	<div class="up-indicator"></div> | 
					
						
							|  |  |  | 	<div class="down-indicator"></div> | 
					
						
							| 
									
										
										
										
											2013-04-26 05:30:56 +04:00
										 |  |  | </div> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- vim:set ts=4 sw=4 spell : --> | 
					
						
							|  |  |  | </body> | 
					
						
							|  |  |  | </html> |