| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | <!DOCTYPE html> | 
					
						
							|  |  |  | <html> | 
					
						
							|  |  |  | <style> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .ribbon { | 
					
						
							|  |  |  | 	position: relative; | 
					
						
							|  |  |  | 	display: block; | 
					
						
							|  |  |  | 	float: left; | 
					
						
							|  |  |  | 	clear: left; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	white-space: nowrap; | 
					
						
							|  |  |  | 	overflow: visible; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	margin: 5px 0px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	width: auto; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .base.ribbon { | 
					
						
							|  |  |  | 	border-bottom: solid 5px red; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | .mark, | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | .image { | 
					
						
							|  |  |  | 	position: relative; | 
					
						
							|  |  |  | 	display: inline-block; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	width: 100px; | 
					
						
							|  |  |  | 	height: 100px; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	outline: solid 1px blue; | 
					
						
							|  |  |  | 	background: silver; | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	vertical-align: middle; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .image:after { | 
					
						
							|  |  |  | 	content: attr(gid); | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | .current.image { | 
					
						
							|  |  |  | 	background: gray; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | .mark { | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 	margin-left: -100px; | 
					
						
							|  |  |  | 	background: none; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer-events: none; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | .mark:after { | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 	position: absolute; | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 	content: ""; | 
					
						
							|  |  |  | 	top: 0; | 
					
						
							|  |  |  | 	right: 0; | 
					
						
							|  |  |  | 	 | 
					
						
							|  |  |  | 	width: 0; | 
					
						
							|  |  |  | 	height: 0; | 
					
						
							|  |  |  | 	border: solid 10px red; | 
					
						
							|  |  |  | 	border-bottom-color: transparent; | 
					
						
							|  |  |  | 	border-left-color: transparent; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pointer-events: auto; | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | </style> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script src="../ext-lib/jquery.js"></script> | 
					
						
							|  |  |  | <script src="../ext-lib/jquery-ui.js"></script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <!-- preact.js --> | 
					
						
							|  |  |  | <script src="../node_modules/preact/dist/preact.min.js"></script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script src="../lib/jli.js"></script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var h = preact.h | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var stub_data = { | 
					
						
							|  |  |  | 	ribbon_order: ['ra', 'rb', 'rc'], | 
					
						
							|  |  |  | 	ribbons: { | 
					
						
							|  |  |  | 		ra: [].slice.call('abcde'), | 
					
						
							|  |  |  | 		rb: [].slice.call('fghijklm'), | 
					
						
							|  |  |  | 		rc: [].slice.call('opqrstuvwxyz'), | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 	order: [].slice.call('abcdefghijklmopqrstuvwxyz'), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	tags: { | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 		selected: [].slice.call('ahdtu'), | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 		b: [].slice.call('adxz'), | 
					
						
							|  |  |  | 	}, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	current: 'a', | 
					
						
							|  |  |  | 	base: 'rb', | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // XXX needs vertical align... | 
					
						
							|  |  |  | class IGRibbonSet extends preact.Component { | 
					
						
							|  |  |  | 	render(props, state){ | 
					
						
							|  |  |  | 		var data = props.data | 
					
						
							|  |  |  | 		var ribbons = data.ribbon_order.map(function(gid){ | 
					
						
							|  |  |  | 			return h(IGRibbon, { | 
					
						
							|  |  |  | 				gid: gid,  | 
					
						
							|  |  |  | 				current: data.current,  | 
					
						
							|  |  |  | 				base: data.base,  | 
					
						
							|  |  |  | 				data: data | 
					
						
							|  |  |  | 			}) }) | 
					
						
							|  |  |  | 		var s = props.scale || 1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return h('div', | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				className: 'ribbon-set',  | 
					
						
							|  |  |  | 				style: { | 
					
						
							|  |  |  | 					transform: 'scale('+ s +', '+ s +')', | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, [ | 
					
						
							|  |  |  | 				h('div', {className: 'current-marker'}), | 
					
						
							|  |  |  | 				h('div', {className: 'ribbon-locator'}, ribbons), | 
					
						
							|  |  |  | 			]) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // render: | 
					
						
							|  |  |  | // 	- ribbon | 
					
						
							|  |  |  | // 	- images | 
					
						
							|  |  |  | // 	- image marks | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // XXX needs horizontal align... | 
					
						
							|  |  |  | class IGRibbon extends preact.Component { | 
					
						
							|  |  |  | 	render(props, state){ | 
					
						
							|  |  |  | 		var data = props.data | 
					
						
							|  |  |  | 		var ribbon = props.gid | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 		var images = data.ribbons[ribbon] | 
					
						
							|  |  |  | 			.map(function(gid){ | 
					
						
							|  |  |  | 				var marks = data.tags.selected.indexOf(gid) >= 0 ? | 
					
						
							|  |  |  | 					h(IGImageMark, { | 
					
						
							|  |  |  | 						gid: gid, | 
					
						
							|  |  |  | 						type: 'selected', | 
					
						
							|  |  |  | 						data: data, | 
					
						
							|  |  |  | 					}) | 
					
						
							|  |  |  | 					: [] | 
					
						
							|  |  |  | 				return [ | 
					
						
							|  |  |  | 					h(IGImage, {  | 
					
						
							|  |  |  | 						gid: gid,  | 
					
						
							|  |  |  | 						data: data,  | 
					
						
							|  |  |  | 					})].concat(marks) | 
					
						
							|  |  |  | 				}) | 
					
						
							|  |  |  | 			.reduce(function(a, b){ return a.concat(b) }) | 
					
						
							|  |  |  | 			.filter(function(a){ return !!a }) | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		var base = data.base == ribbon ? ['base'] : []  | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return h('div', | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				classList: ['ribbon'].concat(base).join(' '), | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				gid: props.gid, | 
					
						
							|  |  |  | 				style: { | 
					
						
							|  |  |  | 					// XXX offset... | 
					
						
							|  |  |  | 				}, | 
					
						
							|  |  |  | 			}, images) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // render: | 
					
						
							|  |  |  | // 	- image | 
					
						
							|  |  |  | class IGImage extends preact.Component { | 
					
						
							|  |  |  | 	render(props, state){ | 
					
						
							|  |  |  | 		var data = props.data | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 		var gid = props.gid | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		return h('div', | 
					
						
							|  |  |  | 			{ | 
					
						
							|  |  |  | 				classList: ['image'] | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 					.concat(data.current == gid ? ['current'] : []) | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 					.join(' '), | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 				gid: gid || '', | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 				style: { | 
					
						
							|  |  |  | 					// XXX background-image... | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 				// XXX STUB | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 				onClick: function(evt){  | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 					// toggle tag... | 
					
						
							|  |  |  | 					if(data.current == gid){ | 
					
						
							|  |  |  | 						var selected = data.tags.selected = data.tags.selected || [] | 
					
						
							|  |  |  | 						selected.indexOf(gid) < 0 ? | 
					
						
							|  |  |  | 							selected.push(gid) | 
					
						
							|  |  |  | 							: selected.splice(selected.indexOf(gid), 1) | 
					
						
							|  |  |  | 					} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					// set current... | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 					data.current = gid  | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-28 17:55:09 +03:00
										 |  |  | 					render() | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 				}, | 
					
						
							|  |  |  | 			}) | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // render: | 
					
						
							|  |  |  | // 	- image mark | 
					
						
							|  |  |  | class IGImageMark extends preact.Component { | 
					
						
							|  |  |  | 	render(props, state){ | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 		var gid = props.gid | 
					
						
							|  |  |  | 		var type = props.type | 
					
						
							|  |  |  | 		var data = props.data | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 		return h('div', | 
					
						
							|  |  |  | 			{ | 
					
						
							| 
									
										
										
										
											2017-07-29 21:39:47 +03:00
										 |  |  | 				classList: ['mark'].concat([type]).join(' '), | 
					
						
							|  |  |  | 				gid: gid, | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				// XXX STUB... | 
					
						
							|  |  |  | 				//		...and there is no way to add the mark back... | 
					
						
							|  |  |  | 				onClick: function(evt){ | 
					
						
							|  |  |  | 					data.tags[type].splice(data.tags[type].indexOf(gid), 1) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 					render() | 
					
						
							|  |  |  | 				}, | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | 			}) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-07-27 11:38:05 +03:00
										 |  |  | // XXX HACK... | 
					
						
							| 
									
										
										
										
											2017-07-26 21:10:28 +03:00
										 |  |  | var ribbon_set_dom | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | function render(data, images, scale){ | 
					
						
							|  |  |  | 	//preact.render(ribbon_set, document.body) | 
					
						
							|  |  |  | 	ribbon_set_dom = preact.render( | 
					
						
							|  |  |  | 		h(IGRibbonSet, { | 
					
						
							|  |  |  | 			data: data || stub_data, | 
					
						
							|  |  |  | 			images: images || {}, | 
					
						
							|  |  |  | 			scale: scale || 1, | 
					
						
							|  |  |  | 		}),  | 
					
						
							|  |  |  | 		document.getElementById('viewer'), | 
					
						
							|  |  |  | 		ribbon_set_dom) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | $(function(){ render() }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </script> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | <body> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	<div id="viewer"/> | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | </body> | 
					
						
							|  |  |  | </html> | 
					
						
							|  |  |  | <!-- vim:set ts=4 sw=4 : --> |