Index: other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/ext-kiwiana.js
===================================================================
--- other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/ext-kiwiana.js	(revision 29959)
+++ other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/ext-kiwiana.js	(revision 29959)
@@ -0,0 +1,535 @@
+/*globals svgEditor, svgCanvas, $*/
+/*jslint vars: true, eqeq: true*/
+/*
+ * ext-helloworld.js
+ *
+ * Licensed under the MIT License
+ *
+ * Copyright(c) 2010 Alexis Deveria
+ *
+ */
+var kiwianaClicked = false;
+
+svgEditor.addExtension("Kiwiana", function() {'use strict';                                     
+
+
+
+	var uiStrings = svgEditor.uiStrings;
+
+	$.extend(uiStrings, {
+		imagelib: {
+			select_lib: 'Select an image library',
+			show_list: 'Show library list',
+			import_single: 'Import single',
+			import_multi: 'Import multiple',
+			open: 'Open as new document'
+		}
+	});
+
+	var kimg_libs = [
+		{
+			name: 'Kiwiana library',
+			url: svgEditor.curConfig.extPath + '../../../kiwiana/index.jsp',
+			description: 'A library of Kiwiana SVG files to provide some inspiration to design'
+		},
+		{
+			name: 'Openclipart',
+			url: 'http://openclipart.org/svgedit',
+			description: 'Share and Use Images. Over 50,000 Public Domain SVG Images and Growing.'
+		}
+	];
+
+	function closeBrowser() {
+		$('#kimgbrowse_holder').hide();
+	}
+
+	function importImage(url) {
+		var newImage = svgCanvas.addSvgElementFromJson({
+			"element": "image",
+			"attr": {
+				"x": 0,
+				"y": 0,
+				"width": 0,
+				"height": 0,
+				"id": svgCanvas.getNextId(),
+				"style": "pointer-events:inherit"
+			}
+		});
+		svgCanvas.clearSelection();
+		svgCanvas.addToSelection([newImage]);
+		svgCanvas.setImageURL(url);
+	}
+
+	var mode = 's';
+	var multi_arr = [];
+	var tranfer_stopped = false;
+	var pending = {};
+	var preview, submit;
+
+	window.addEventListener("message", function(evt) {
+		// Receive postMessage data
+		var response = evt.data;
+		
+		if (!response || typeof response !== "string") { // Todo: Should namespace postMessage API for this extension and filter out here
+			// Do nothing
+			return;
+		}
+		try { // This block can be removed if embedAPI moves away from a string to an object (if IE9 support not needed)
+			var res = JSON.parse(response);
+			if (res.namespace) { // Part of embedAPI communications
+				return;
+			}
+		}
+		catch (e) {}
+		
+		var char1 = response.charAt(0);
+		var id;
+		var svg_str;
+		var img_str;
+		
+		if (char1 != "{" && tranfer_stopped) {
+			tranfer_stopped = false;
+			return;
+		}
+		
+		if (char1 == '|') {
+			var secondpos = response.indexOf('|', 1);
+			id = response.substr(1, secondpos-1);
+			response = response.substr(secondpos+1);
+			char1 = response.charAt(0);
+		}
+		
+		
+		// Hide possible transfer dialog box
+		$('#dialog_box').hide();
+		var entry, cur_meta;
+		switch (char1) {
+			case '{':
+				// Metadata
+				tranfer_stopped = false;
+				cur_meta = JSON.parse(response);
+				
+				pending[cur_meta.id] = cur_meta;
+				
+				var name = (cur_meta.name || 'file');
+				
+				var message = uiStrings.notification.retrieving.replace('%s', name);
+				
+				if (mode != 'm') {
+					$.process_cancel(message, function() {
+						tranfer_stopped = true;
+						// Should a message be sent back to the frame?
+						
+						$('#dialog_box').hide();
+					});
+				} else {
+					entry = $('<div>' + message + '</div>').data('id', cur_meta.id);
+					preview.append(entry);
+					cur_meta.entry = entry;
+				}
+				
+				return;
+			case '<':
+				svg_str = true;
+				break;
+			case 'd':
+				if (response.indexOf('data:image/svg+xml') === 0) {
+					var pre = 'data:image/svg+xml;base64,';
+					var src = response.substring(pre.length);
+					response = svgedit.utilities.decode64(src);
+					svg_str = true;
+					break;
+				} else if (response.indexOf('data:image/') === 0) {
+					img_str = true;
+					break;
+				}
+				// Else fall through
+			default:
+				// TODO: See if there's a way to base64 encode the binary data stream
+//				var str = 'data:;base64,' + svgedit.utilities.encode64(response, true);
+			
+				// Assume it's raw image data
+//				importImage(str);
+			
+				// Don't give warning as postMessage may have been used by something else
+				if (mode !== 'm') {
+					closeBrowser();
+				} else {
+					pending[id].entry.remove();
+				}
+//				$.alert('Unexpected data was returned: ' + response, function() {
+//					if (mode !== 'm') {
+//						closeBrowser();
+//					} else {
+//						pending[id].entry.remove();
+//					}
+//				});
+				return;
+		}
+		
+		switch (mode) {
+			case 's':
+				// Import one
+				if (svg_str) {
+					svgCanvas.importSvgString(response);
+				} else if (img_str) {
+					importImage(response);
+				}
+				closeBrowser();
+				break;
+			case 'm':
+				// Import multiple
+				multi_arr.push([(svg_str ? 'svg' : 'img'), response]);
+				var title;
+				cur_meta = pending[id];
+				if (svg_str) {
+					if (cur_meta && cur_meta.name) {
+						title = cur_meta.name;
+					} else {
+						// Try to find a title
+						var xml = new DOMParser().parseFromString(response, 'text/xml').documentElement;
+						title = $(xml).children('title').first().text() || '(SVG #' + response.length + ')';
+					}
+					if (cur_meta) {
+						preview.children().each(function() {
+							if ($(this).data('id') == id) {
+								if (cur_meta.preview_url) {
+									$(this).html('<img src="' + cur_meta.preview_url + '">' + title);
+								} else {
+									$(this).text(title);
+								}
+								submit.removeAttr('disabled');
+							}
+						});
+					} else {
+						preview.append('<div>'+title+'</div>');
+						submit.removeAttr('disabled');
+					}
+				} else {
+					if (cur_meta && cur_meta.preview_url) {
+						title = cur_meta.name || '';
+					}
+					if (cur_meta && cur_meta.preview_url) {
+						entry = '<img src="' + cur_meta.preview_url + '">' + title;
+					} else {
+						entry = '<img src="' + response + '">';
+					}
+				
+					if (cur_meta) {
+						preview.children().each(function() {
+							if ($(this).data('id') == id) {
+								$(this).html(entry);
+								submit.removeAttr('disabled');
+							}
+						});
+					} else {
+						preview.append($('<div>').append(entry));
+						submit.removeAttr('disabled');
+					}
+
+				}
+				break;
+			case 'o':
+				// Open
+				if (!svg_str) {break;}
+				svgEditor.openPrep(function(ok) {
+					if (!ok) {return;}
+					svgCanvas.clear();
+					svgCanvas.setSvgString(response);
+					// updateCanvas();
+				});
+				closeBrowser();
+				break;
+		}
+	}, true);
+
+	function toggleMulti(show) {
+	
+		$('#lib_framewrap, #kimglib_opts').css({right: (show ? 200 : 10)});
+		if (!preview) {
+			preview = $('<div id=kimglib_preview>').css({
+				position: 'absolute',
+				top: 45,
+				right: 10,
+				width: 180,
+				bottom: 45,
+				background: '#fff',
+				overflow: 'auto'
+			}).insertAfter('#lib_framewrap');
+			
+			submit = $('<button disabled>Import selected</button>')
+				.appendTo('#kimgbrowse')
+				.on("click touchend", function() {
+				$.each(multi_arr, function(i) {
+					var type = this[0];
+					var data = this[1];
+					if (type == 'svg') {
+						svgCanvas.importSvgString(data);
+					} else {
+						importImage(data);
+					}
+					svgCanvas.moveSelectedElements(i*20, i*20, false);
+				});
+				preview.empty();
+				multi_arr = [];
+				$('#kimgbrowse_holder').hide();
+			}).css({
+				position: 'absolute',
+				bottom: 10,
+				right: -10
+			});
+
+		}
+		
+		preview.toggle(show);
+		submit.toggle(show);
+	}
+
+	function showBrowser() {
+
+		var browser = $('#kimgbrowse');
+		if (!browser.length) {
+			$('<div id=kimgbrowse_holder><div id=kimgbrowse class=toolbar_button>\
+			</div></div>').insertAfter('#svg_docprops');
+			browser = $('#kimgbrowse');
+
+			var all_libs = uiStrings.imagelib.select_lib;
+
+			var lib_opts = $('<ul id=kimglib_opts>').appendTo(browser);
+			var frame = $('<iframe/>').prependTo(browser).hide().wrap('<div id=lib_framewrap>');
+			
+			var header = $('<h1>').prependTo(browser).text(all_libs).css({
+				position: 'absolute',
+				top: 0,
+				left: 0,
+				width: '100%'
+			});
+			
+			var cancel = $('<button>' + uiStrings.common.cancel + '</button>')
+				.appendTo(browser)
+				.on("click touchend", function() {
+				$('#kimgbrowse_holder').hide();
+			}).css({
+				position: 'absolute',
+				top: 5,
+				right: -10
+			});
+			
+			var leftBlock = $('<span>').css({position:'absolute',top:5,left:10}).appendTo(browser);
+			
+			var back = $('<button hidden>' + uiStrings.imagelib.show_list + '</button>')
+				.appendTo(leftBlock)
+				.on("click touchend", function() {
+				frame.attr('src', 'about:blank').hide();
+				lib_opts.show();
+				header.text(all_libs);
+				back.hide();
+			}).css({
+				'margin-right': 5
+			}).hide();
+			
+			var type = $('<select><option value=s>' + 
+			uiStrings.imagelib.import_single + '</option><option value=m>' +
+			uiStrings.imagelib.import_multi + '</option><option value=o>' +
+			uiStrings.imagelib.open + '</option></select>').appendTo(leftBlock).change(function() {
+				mode = $(this).val();
+				switch (mode) {
+					case 's':
+					case 'o':
+						toggleMulti(false);
+						break;
+					
+					case 'm':
+						// Import multiple
+						toggleMulti(true);
+						break;
+				}
+			}).css({
+				'margin-top': 10
+			});
+			
+			cancel.prepend($.getSvgIcon('cancel', true));
+			back.prepend($.getSvgIcon('tool_imagelib', true));
+			
+			$.each(kimg_libs, function(i, opts) {
+				$('<li>')
+					.appendTo(lib_opts)
+					.text(opts.name)
+					.on("click touchend", function() {
+					frame.attr('src', opts.url).show();
+					header.text(opts.name);
+					lib_opts.hide();
+					back.show();
+				}).append('<span>' + opts.description + '</span>');
+			});
+			
+		} else {
+			$('#kimgbrowse_holder').show();
+		}
+	}
+
+
+                                               
+		return {
+			name: "Kiwiana",
+			// The icon for 'Kiwiana library'
+			svgicons: svgEditor.curConfig.extPath + "kiwiana-icon.xml",
+			
+			// Multiple buttons can be added in this array
+			buttons: [{
+				// Must match the icon ID in kiwiana-icon.xml
+				id: "kiwiana", 
+				
+				// This indicates that the button will be added independently to the buttons in the button
+				// panel on the left side (it will not be unselected when one of the other buttons is selected)
+				type: "context",
+
+                panel: "tools_left",
+				
+				// Tooltip text
+				title: "Access the Kiwiana Shape Library", 
+				
+				// Events
+				events: {
+					'click': function() {
+
+	                        console.log("**** ext-kiwiana click()");
+				showBrowser();
+
+                        // Toggle the Kiwiana button
+                        if (kiwianaClicked == true)
+                        {
+                            kiwianaClicked = false;
+                            // Hide advanced features
+                            kiwianaButton(kiwianaClicked);
+                        }
+                        else
+                        {
+                            kiwianaClicked = true; 
+                            // Hide advanced features
+                            kiwianaButton(kiwianaClicked);
+                        }
+					}
+				}
+			}],
+			// This is triggered when the main mouse button is pressed down 
+			// on the editor canvas (not the tool panels)
+			mouseDownXX: function() {
+		                kiwianaButton(kiwianaClicked);
+
+                		// The returned object must include "started" with 
+		                // a value of true in order for mouseUp to be triggered
+                		return {started: true};
+			},
+			
+			// This is triggered from anywhere, but "started" must have been set
+			// to true (see above). Note that "opts" is an object with event info
+			mouseUpXX: function(opts) {
+	                        console.log("**** ext-kiwiana mouseUp()");
+				showBrowser();
+                //advancedButton(kiwianaClicked);
+			},
+            
+            elementChangedXX: function(opts)
+            {
+                //kiwianaButton(kiwianaClicked);
+            },
+            
+            callback: function(opts) {
+                //kiwianaClicked = false;
+                //kiwianaButton(kiwianaClicked);
+	        console.log("**** ext-kiwiana callback()");
+
+				$('<style>').text('\
+				#kimgbrowse_holder {\
+					position: absolute;\
+					top: 0;\
+					left: 0;\
+					width: 100%;\
+					height: 100%;\
+					background-color: rgba(0, 0, 0, .5);\
+					z-index: 5;\
+				}\
+				\
+				#kimgbrowse {\
+					position: absolute;\
+					top: 25px;\
+					left: 25px;\
+					right: 25px;\
+					bottom: 25px;\
+					min-width: 300px;\
+					min-height: 200px;\
+					background: #B0B0B0;\
+					border: 1px outset #777;\
+				}\
+				#kimgbrowse h1 {\
+					font-size: 20px;\
+					margin: .4em;\
+					text-align: center;\
+				}\
+				#lib_framewrap,\
+				#kimgbrowse > ul {\
+					position: absolute;\
+					top: 45px;\
+					left: 10px;\
+					right: 10px;\
+					bottom: 10px;\
+					background: white;\
+					margin: 0;\
+					padding: 0;\
+				}\
+				#kimgbrowse > ul {\
+					overflow: auto;\
+				}\
+				#kimgbrowse > div {\
+					border: 1px solid #666;\
+				}\
+				#kimglib_preview > div {\
+					padding: 5px;\
+					font-size: 12px;\
+				}\
+				#kimglib_preview img {\
+					display: block;\
+					margin: 0 auto;\
+					max-height: 100px;\
+				}\
+				#kimgbrowse li {\
+					list-style: none;\
+					padding: .5em;\
+					background: #E8E8E8;\
+					border-bottom: 1px solid #B0B0B0;\
+					line-height: 1.2em;\
+					font-style: sans-serif;\
+					}\
+				#kimgbrowse li > span {\
+					color: #666;\
+					font-size: 15px;\
+					display: block;\
+					}\
+				#kimgbrowse li:hover {\
+					background: #FFC;\
+					cursor: pointer;\
+					}\
+				#kimgbrowse iframe {\
+					width: 100%;\
+					height: 100%;\
+					border: 0;\
+				}\
+			').appendTo('head');
+
+
+            }
+		};
+});
+
+// Function: kiwianaButton
+// Unless kiwiana button is selected, advanced features will be hidden
+this.kiwianaButton = function() {
+    
+    console.log("kiwianaButton");
+	//showBrowser();
+}
+
+
+
+
Index: other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/kiwiana-icon.xml
===================================================================
--- other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/kiwiana-icon.xml	(revision 29959)
+++ other-projects/nz-flag-design/trunk/main-form/svg-edit-local/extensions/kiwiana-icon.xml	(revision 29959)
@@ -0,0 +1,20 @@
+<svg xmlns="http://www.w3.org/2000/svg">
+<!-- 
+	Sample icons file. This file looks like an SVG file with groups as its
+	children. Each group element has an ID that must match the ID of the button given
+	in the extension. The SVG inside the group makes up the actual icon, and
+	needs use a viewBox instead of width/height for it to scale	properly.
+	
+	Multiple icons can be included, each within their own group.
+-->
+    <g id="kiwiana"> 
+<svg xmlns:svg="http://www.w3.org/2000/svg" xmlns="http://www.w3.org/2000/svg" version="1.0" width="500" height="400" id="svg2">
+  <defs id="defs5"/>
+  <path d="M 21,373 L 194,373 C 23.932184,373 -42.207346,116.84573 106.01988,45.503798 C 149.05506,24.790918 303.58634,-2.4856847 442.31747,108.73473 C 509.1916,162.34756 476.04152,360.68999 459,373 C 459,373 459,277 459,245 C 459,99.466366 21,206.77046 21,373 z " style="fill:#993400;fill-opacity:1;fill-rule:evenodd;stroke:black;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" id="path1891"/>
+  <g transform="matrix(1.28125,0,0,1.28125,-74.8438,-24.34375)" id="g2783">
+    <path d="M 460 144 A 16 16 0 1 1  428,144 A 16 16 0 1 1  460 144 z" transform="translate(-41,-13)" style="opacity:1;fill:white;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:12.5;stroke-opacity:1" id="path2779"/>
+    <path d="M 460 144 A 16 16 0 1 1  428,144 A 16 16 0 1 1  460 144 z" transform="matrix(0.5,0,0,0.5,184,67)" style="opacity:1;fill:black;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:10;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:12.5;stroke-opacity:1" id="path2781"/>
+  </g>
+</svg>
+    </g>
+</svg>
