You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jspwiki.apache.org by br...@apache.org on 2015/06/22 22:11:44 UTC

svn commit: r1686927 [4/11] - in /jspwiki/trunk: ./ jspwiki-war/src/main/config/wro/ jspwiki-war/src/main/java/org/apache/wiki/ jspwiki-war/src/main/resources/templates/ jspwiki-war/src/main/scripts/behaviors/ jspwiki-war/src/main/scripts/dialog/ jspwi...

Added: jspwiki/trunk/jspwiki-war/src/main/scripts/lib/mootools-more-1.5.1.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/lib/mootools-more-1.5.1.js?rev=1686927&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/lib/mootools-more-1.5.1.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/lib/mootools-more-1.5.1.js Mon Jun 22 20:11:42 2015
@@ -0,0 +1,1253 @@
+/*
+---
+MooTools: the javascript framework
+
+web build:
+ - http://mootools.net/more/16f279284293383895ae88bb0e54545f
+
+packager build:
+ - packager build More/Class.Binds More/Hash More/Element.Shortcuts More/Fx.Elements More/Fx.Accordion More/Drag More/Drag.Move More/Hash.Cookie More/Swiff
+
+...
+*/
+
+/*
+---
+
+script: More.js
+
+name: More
+
+description: MooTools More
+
+license: MIT-style license
+
+authors:
+  - Guillermo Rauch
+  - Thomas Aylott
+  - Scott Kyle
+  - Arian Stolwijk
+  - Tim Wienk
+  - Christoph Pojer
+  - Aaron Newton
+  - Jacob Thornton
+
+requires:
+  - Core/MooTools
+
+provides: [MooTools.More]
+
+...
+*/
+
+MooTools.More = {
+	version: '1.5.1',
+	build: '2dd695ba957196ae4b0275a690765d6636a61ccd'
+};
+
+
+/*
+---
+
+script: Class.Binds.js
+
+name: Class.Binds
+
+description: Automagically binds specified methods in a class to the instance of the class.
+
+license: MIT-style license
+
+authors:
+  - Aaron Newton
+
+requires:
+  - Core/Class
+  - MooTools.More
+
+provides: [Class.Binds]
+
+...
+*/
+
+Class.Mutators.Binds = function(binds){
+	if (!this.prototype.initialize) this.implement('initialize', function(){});
+	return Array.from(binds).concat(this.prototype.Binds || []);
+};
+
+Class.Mutators.initialize = function(initialize){
+	return function(){
+		Array.from(this.Binds).each(function(name){
+			var original = this[name];
+			if (original) this[name] = original.bind(this);
+		}, this);
+		return initialize.apply(this, arguments);
+	};
+};
+
+
+/*
+---
+
+name: Hash
+
+description: Contains Hash Prototypes. Provides a means for overcoming the JavaScript practical impossibility of extending native Objects.
+
+license: MIT-style license.
+
+requires:
+  - Core/Object
+  - MooTools.More
+
+provides: [Hash]
+
+...
+*/
+
+(function(){
+
+if (this.Hash) return;
+
+var Hash = this.Hash = new Type('Hash', function(object){
+	if (typeOf(object) == 'hash') object = Object.clone(object.getClean());
+	for (var key in object) this[key] = object[key];
+	return this;
+});
+
+this.$H = function(object){
+	return new Hash(object);
+};
+
+Hash.implement({
+
+	forEach: function(fn, bind){
+		Object.forEach(this, fn, bind);
+	},
+
+	getClean: function(){
+		var clean = {};
+		for (var key in this){
+			if (this.hasOwnProperty(key)) clean[key] = this[key];
+		}
+		return clean;
+	},
+
+	getLength: function(){
+		var length = 0;
+		for (var key in this){
+			if (this.hasOwnProperty(key)) length++;
+		}
+		return length;
+	}
+
+});
+
+Hash.alias('each', 'forEach');
+
+Hash.implement({
+
+	has: Object.prototype.hasOwnProperty,
+
+	keyOf: function(value){
+		return Object.keyOf(this, value);
+	},
+
+	hasValue: function(value){
+		return Object.contains(this, value);
+	},
+
+	extend: function(properties){
+		Hash.each(properties || {}, function(value, key){
+			Hash.set(this, key, value);
+		}, this);
+		return this;
+	},
+
+	combine: function(properties){
+		Hash.each(properties || {}, function(value, key){
+			Hash.include(this, key, value);
+		}, this);
+		return this;
+	},
+
+	erase: function(key){
+		if (this.hasOwnProperty(key)) delete this[key];
+		return this;
+	},
+
+	get: function(key){
+		return (this.hasOwnProperty(key)) ? this[key] : null;
+	},
+
+	set: function(key, value){
+		if (!this[key] || this.hasOwnProperty(key)) this[key] = value;
+		return this;
+	},
+
+	empty: function(){
+		Hash.each(this, function(value, key){
+			delete this[key];
+		}, this);
+		return this;
+	},
+
+	include: function(key, value){
+		if (this[key] == undefined) this[key] = value;
+		return this;
+	},
+
+	map: function(fn, bind){
+		return new Hash(Object.map(this, fn, bind));
+	},
+
+	filter: function(fn, bind){
+		return new Hash(Object.filter(this, fn, bind));
+	},
+
+	every: function(fn, bind){
+		return Object.every(this, fn, bind);
+	},
+
+	some: function(fn, bind){
+		return Object.some(this, fn, bind);
+	},
+
+	getKeys: function(){
+		return Object.keys(this);
+	},
+
+	getValues: function(){
+		return Object.values(this);
+	},
+
+	toQueryString: function(base){
+		return Object.toQueryString(this, base);
+	}
+
+});
+
+Hash.alias({indexOf: 'keyOf', contains: 'hasValue'});
+
+
+})();
+
+
+
+/*
+---
+
+script: Element.Shortcuts.js
+
+name: Element.Shortcuts
+
+description: Extends the Element native object to include some shortcut methods.
+
+license: MIT-style license
+
+authors:
+  - Aaron Newton
+
+requires:
+  - Core/Element.Style
+  - MooTools.More
+
+provides: [Element.Shortcuts]
+
+...
+*/
+
+Element.implement({
+
+	isDisplayed: function(){
+		return this.getStyle('display') != 'none';
+	},
+
+	isVisible: function(){
+		var w = this.offsetWidth,
+			h = this.offsetHeight;
+		return (w == 0 && h == 0) ? false : (w > 0 && h > 0) ? true : this.style.display != 'none';
+	},
+
+	toggle: function(){
+		return this[this.isDisplayed() ? 'hide' : 'show']();
+	},
+
+	hide: function(){
+		var d;
+		try {
+			//IE fails here if the element is not in the dom
+			d = this.getStyle('display');
+		} catch(e){}
+		if (d == 'none') return this;
+		return this.store('element:_originalDisplay', d || '').setStyle('display', 'none');
+	},
+
+	show: function(display){
+		if (!display && this.isDisplayed()) return this;
+		display = display || this.retrieve('element:_originalDisplay') || 'block';
+		return this.setStyle('display', (display == 'none') ? 'block' : display);
+	},
+
+	swapClass: function(remove, add){
+		return this.removeClass(remove).addClass(add);
+	}
+
+});
+
+Document.implement({
+
+	clearSelection: function(){
+		if (window.getSelection){
+			var selection = window.getSelection();
+			if (selection && selection.removeAllRanges) selection.removeAllRanges();
+		} else if (document.selection && document.selection.empty){
+			try {
+				//IE fails here if selected element is not in dom
+				document.selection.empty();
+			} catch(e){}
+		}
+	}
+
+});
+
+
+/*
+---
+
+script: Fx.Elements.js
+
+name: Fx.Elements
+
+description: Effect to change any number of CSS properties of any number of Elements.
+
+license: MIT-style license
+
+authors:
+  - Valerio Proietti
+
+requires:
+  - Core/Fx.CSS
+  - MooTools.More
+
+provides: [Fx.Elements]
+
+...
+*/
+
+Fx.Elements = new Class({
+
+	Extends: Fx.CSS,
+
+	initialize: function(elements, options){
+		this.elements = this.subject = $$(elements);
+		this.parent(options);
+	},
+
+	compute: function(from, to, delta){
+		var now = {};
+
+		for (var i in from){
+			var iFrom = from[i], iTo = to[i], iNow = now[i] = {};
+			for (var p in iFrom) iNow[p] = this.parent(iFrom[p], iTo[p], delta);
+		}
+
+		return now;
+	},
+
+	set: function(now){
+		for (var i in now){
+			if (!this.elements[i]) continue;
+
+			var iNow = now[i];
+			for (var p in iNow) this.render(this.elements[i], p, iNow[p], this.options.unit);
+		}
+
+		return this;
+	},
+
+	start: function(obj){
+		if (!this.check(obj)) return this;
+		var from = {}, to = {};
+
+		for (var i in obj){
+			if (!this.elements[i]) continue;
+
+			var iProps = obj[i], iFrom = from[i] = {}, iTo = to[i] = {};
+
+			for (var p in iProps){
+				var parsed = this.prepare(this.elements[i], p, iProps[p]);
+				iFrom[p] = parsed.from;
+				iTo[p] = parsed.to;
+			}
+		}
+
+		return this.parent(from, to);
+	}
+
+});
+
+
+/*
+---
+
+script: Fx.Accordion.js
+
+name: Fx.Accordion
+
+description: An Fx.Elements extension which allows you to easily create accordion type controls.
+
+license: MIT-style license
+
+authors:
+  - Valerio Proietti
+
+requires:
+  - Core/Element.Event
+  - Fx.Elements
+
+provides: [Fx.Accordion]
+
+...
+*/
+
+Fx.Accordion = new Class({
+
+	Extends: Fx.Elements,
+
+	options: {/*
+		onActive: function(toggler, section){},
+		onBackground: function(toggler, section){},*/
+		fixedHeight: false,
+		fixedWidth: false,
+		display: 0,
+		show: false,
+		height: true,
+		width: false,
+		opacity: true,
+		alwaysHide: false,
+		trigger: 'click',
+		initialDisplayFx: true,
+		resetHeight: true
+	},
+
+	initialize: function(){
+		var defined = function(obj){
+			return obj != null;
+		};
+
+		var params = Array.link(arguments, {
+			'container': Type.isElement, //deprecated
+			'options': Type.isObject,
+			'togglers': defined,
+			'elements': defined
+		});
+		this.parent(params.elements, params.options);
+
+		var options = this.options,
+			togglers = this.togglers = $$(params.togglers);
+
+		this.previous = -1;
+		this.internalChain = new Chain();
+
+		if (options.alwaysHide) this.options.link = 'chain';
+
+		if (options.show || this.options.show === 0){
+			options.display = false;
+			this.previous = options.show;
+		}
+
+		if (options.start){
+			options.display = false;
+			options.show = false;
+		}
+
+		var effects = this.effects = {};
+
+		if (options.opacity) effects.opacity = 'fullOpacity';
+		if (options.width) effects.width = options.fixedWidth ? 'fullWidth' : 'offsetWidth';
+		if (options.height) effects.height = options.fixedHeight ? 'fullHeight' : 'scrollHeight';
+
+		for (var i = 0, l = togglers.length; i < l; i++) this.addSection(togglers[i], this.elements[i]);
+
+		this.elements.each(function(el, i){
+			if (options.show === i){
+				this.fireEvent('active', [togglers[i], el]);
+			} else {
+				for (var fx in effects) el.setStyle(fx, 0);
+			}
+		}, this);
+
+		if (options.display || options.display === 0 || options.initialDisplayFx === false){
+			this.display(options.display, options.initialDisplayFx);
+		}
+
+		if (options.fixedHeight !== false) options.resetHeight = false;
+		this.addEvent('complete', this.internalChain.callChain.bind(this.internalChain));
+	},
+
+	addSection: function(toggler, element){
+		toggler = document.id(toggler);
+		element = document.id(element);
+		this.togglers.include(toggler);
+		this.elements.include(element);
+
+		var togglers = this.togglers,
+			options = this.options,
+			test = togglers.contains(toggler),
+			idx = togglers.indexOf(toggler),
+			displayer = this.display.pass(idx, this);
+
+		toggler.store('accordion:display', displayer)
+			.addEvent(options.trigger, displayer);
+
+		if (options.height) element.setStyles({'padding-top': 0, 'border-top': 'none', 'padding-bottom': 0, 'border-bottom': 'none'});
+		if (options.width) element.setStyles({'padding-left': 0, 'border-left': 'none', 'padding-right': 0, 'border-right': 'none'});
+
+		element.fullOpacity = 1;
+		if (options.fixedWidth) element.fullWidth = options.fixedWidth;
+		if (options.fixedHeight) element.fullHeight = options.fixedHeight;
+		element.setStyle('overflow', 'hidden');
+
+		if (!test) for (var fx in this.effects){
+			element.setStyle(fx, 0);
+		}
+		return this;
+	},
+
+	removeSection: function(toggler, displayIndex){
+		var togglers = this.togglers,
+			idx = togglers.indexOf(toggler),
+			element = this.elements[idx];
+
+		var remover = function(){
+			togglers.erase(toggler);
+			this.elements.erase(element);
+			this.detach(toggler);
+		}.bind(this);
+
+		if (this.now == idx || displayIndex != null){
+			this.display(displayIndex != null ? displayIndex : (idx - 1 >= 0 ? idx - 1 : 0)).chain(remover);
+		} else {
+			remover();
+		}
+		return this;
+	},
+
+	detach: function(toggler){
+		var remove = function(toggler){
+			toggler.removeEvent(this.options.trigger, toggler.retrieve('accordion:display'));
+		}.bind(this);
+
+		if (!toggler) this.togglers.each(remove);
+		else remove(toggler);
+		return this;
+	},
+
+	display: function(index, useFx){
+		if (!this.check(index, useFx)) return this;
+
+		var obj = {},
+			elements = this.elements,
+			options = this.options,
+			effects = this.effects;
+
+		if (useFx == null) useFx = true;
+		if (typeOf(index) == 'element') index = elements.indexOf(index);
+		if (index == this.current && !options.alwaysHide) return this;
+
+		if (options.resetHeight){
+			var prev = elements[this.current];
+			if (prev && !this.selfHidden){
+				for (var fx in effects) prev.setStyle(fx, prev[effects[fx]]);
+			}
+		}
+
+		if ((this.timer && options.link == 'chain') || (index === this.current && !options.alwaysHide)) return this;
+
+		if (this.current != null) this.previous = this.current;
+		this.current = index;
+		this.selfHidden = false;
+
+		elements.each(function(el, i){
+			obj[i] = {};
+			var hide;
+			if (i != index){
+				hide = true;
+			} else if (options.alwaysHide && ((el.offsetHeight > 0 && options.height) || el.offsetWidth > 0 && options.width)){
+				hide = true;
+				this.selfHidden = true;
+			}
+			this.fireEvent(hide ? 'background' : 'active', [this.togglers[i], el]);
+			for (var fx in effects) obj[i][fx] = hide ? 0 : el[effects[fx]];
+			if (!useFx && !hide && options.resetHeight) obj[i].height = 'auto';
+		}, this);
+
+		this.internalChain.clearChain();
+		this.internalChain.chain(function(){
+			if (options.resetHeight && !this.selfHidden){
+				var el = elements[index];
+				if (el) el.setStyle('height', 'auto');
+			}
+		}.bind(this));
+
+		return useFx ? this.start(obj) : this.set(obj).internalChain.callChain();
+	}
+
+});
+
+
+
+
+/*
+---
+
+script: Drag.js
+
+name: Drag
+
+description: The base Drag Class. Can be used to drag and resize Elements using mouse events.
+
+license: MIT-style license
+
+authors:
+  - Valerio Proietti
+  - Tom Occhinno
+  - Jan Kassens
+
+requires:
+  - Core/Events
+  - Core/Options
+  - Core/Element.Event
+  - Core/Element.Style
+  - Core/Element.Dimensions
+  - MooTools.More
+
+provides: [Drag]
+...
+
+*/
+
+var Drag = new Class({
+
+	Implements: [Events, Options],
+
+	options: {/*
+		onBeforeStart: function(thisElement){},
+		onStart: function(thisElement, event){},
+		onSnap: function(thisElement){},
+		onDrag: function(thisElement, event){},
+		onCancel: function(thisElement){},
+		onComplete: function(thisElement, event){},*/
+		snap: 6,
+		unit: 'px',
+		grid: false,
+		style: true,
+		limit: false,
+		handle: false,
+		invert: false,
+		preventDefault: false,
+		stopPropagation: false,
+		compensateScroll: false,
+		modifiers: {x: 'left', y: 'top'}
+	},
+
+	initialize: function(){
+		var params = Array.link(arguments, {
+			'options': Type.isObject,
+			'element': function(obj){
+				return obj != null;
+			}
+		});
+
+		this.element = document.id(params.element);
+		this.document = this.element.getDocument();
+		this.setOptions(params.options || {});
+		var htype = typeOf(this.options.handle);
+		this.handles = ((htype == 'array' || htype == 'collection') ? $$(this.options.handle) : document.id(this.options.handle)) || this.element;
+		this.mouse = {'now': {}, 'pos': {}};
+		this.value = {'start': {}, 'now': {}};
+		this.offsetParent = (function(el){
+			var offsetParent = el.getOffsetParent();
+			var isBody = !offsetParent || (/^(?:body|html)$/i).test(offsetParent.tagName);
+			return isBody ? window : document.id(offsetParent);
+		})(this.element);
+		this.selection = 'selectstart' in document ? 'selectstart' : 'mousedown';
+
+		this.compensateScroll = {start: {}, diff: {}, last: {}};
+
+		if ('ondragstart' in document && !('FileReader' in window) && !Drag.ondragstartFixed){
+			document.ondragstart = Function.from(false);
+			Drag.ondragstartFixed = true;
+		}
+
+		this.bound = {
+			start: this.start.bind(this),
+			check: this.check.bind(this),
+			drag: this.drag.bind(this),
+			stop: this.stop.bind(this),
+			cancel: this.cancel.bind(this),
+			eventStop: Function.from(false),
+			scrollListener: this.scrollListener.bind(this)
+		};
+		this.attach();
+	},
+
+	attach: function(){
+		this.handles.addEvent('mousedown', this.bound.start);
+		if (this.options.compensateScroll) this.offsetParent.addEvent('scroll', this.bound.scrollListener);
+		return this;
+	},
+
+	detach: function(){
+		this.handles.removeEvent('mousedown', this.bound.start);
+		if (this.options.compensateScroll) this.offsetParent.removeEvent('scroll', this.bound.scrollListener);
+		return this;
+	},
+
+	scrollListener: function(){
+
+		if (!this.mouse.start) return;
+		var newScrollValue = this.offsetParent.getScroll();
+
+		if (this.element.getStyle('position') == 'absolute'){
+			var scrollDiff = this.sumValues(newScrollValue, this.compensateScroll.last, -1);
+			this.mouse.now = this.sumValues(this.mouse.now, scrollDiff, 1);
+		} else {
+			this.compensateScroll.diff = this.sumValues(newScrollValue, this.compensateScroll.start, -1);
+		}
+		if (this.offsetParent != window) this.compensateScroll.diff = this.sumValues(this.compensateScroll.start, newScrollValue, -1);
+		this.compensateScroll.last = newScrollValue;
+		this.render(this.options);
+	},
+
+	sumValues: function(alpha, beta, op){
+		var sum = {}, options = this.options;
+		for (z in options.modifiers){
+			if (!options.modifiers[z]) continue;
+			sum[z] = alpha[z] + beta[z] * op;
+		}
+		return sum;
+	},
+
+	start: function(event){
+		var options = this.options;
+
+		if (event.rightClick) return;
+
+		if (options.preventDefault) event.preventDefault();
+		if (options.stopPropagation) event.stopPropagation();
+		this.compensateScroll.start = this.compensateScroll.last = this.offsetParent.getScroll();
+		this.compensateScroll.diff = {x: 0, y: 0};
+		this.mouse.start = event.page;
+		this.fireEvent('beforeStart', this.element);
+
+		var limit = options.limit;
+		this.limit = {x: [], y: []};
+
+		var z, coordinates, offsetParent = this.offsetParent == window ? null : this.offsetParent;
+		for (z in options.modifiers){
+			if (!options.modifiers[z]) continue;
+
+			var style = this.element.getStyle(options.modifiers[z]);
+
+			// Some browsers (IE and Opera) don't always return pixels.
+			if (style && !style.match(/px$/)){
+				if (!coordinates) coordinates = this.element.getCoordinates(offsetParent);
+				style = coordinates[options.modifiers[z]];
+			}
+
+			if (options.style) this.value.now[z] = (style || 0).toInt();
+			else this.value.now[z] = this.element[options.modifiers[z]];
+
+			if (options.invert) this.value.now[z] *= -1;
+
+			this.mouse.pos[z] = event.page[z] - this.value.now[z];
+
+			if (limit && limit[z]){
+				var i = 2;
+				while (i--){
+					var limitZI = limit[z][i];
+					if (limitZI || limitZI === 0) this.limit[z][i] = (typeof limitZI == 'function') ? limitZI() : limitZI;
+				}
+			}
+		}
+
+		if (typeOf(this.options.grid) == 'number') this.options.grid = {
+			x: this.options.grid,
+			y: this.options.grid
+		};
+
+		var events = {
+			mousemove: this.bound.check,
+			mouseup: this.bound.cancel
+		};
+		events[this.selection] = this.bound.eventStop;
+		this.document.addEvents(events);
+	},
+
+	check: function(event){
+		if (this.options.preventDefault) event.preventDefault();
+		var distance = Math.round(Math.sqrt(Math.pow(event.page.x - this.mouse.start.x, 2) + Math.pow(event.page.y - this.mouse.start.y, 2)));
+		if (distance > this.options.snap){
+			this.cancel();
+			this.document.addEvents({
+				mousemove: this.bound.drag,
+				mouseup: this.bound.stop
+			});
+			this.fireEvent('start', [this.element, event]).fireEvent('snap', this.element);
+		}
+	},
+
+	drag: function(event){
+		var options = this.options;
+		if (options.preventDefault) event.preventDefault();
+		this.mouse.now = this.sumValues(event.page, this.compensateScroll.diff, -1);
+
+		this.render(options);
+		this.fireEvent('drag', [this.element, event]);
+	},  
+
+	render: function(options){
+		for (var z in options.modifiers){
+			if (!options.modifiers[z]) continue;
+			this.value.now[z] = this.mouse.now[z] - this.mouse.pos[z];
+
+			if (options.invert) this.value.now[z] *= -1;
+			if (options.limit && this.limit[z]){
+				if ((this.limit[z][1] || this.limit[z][1] === 0) && (this.value.now[z] > this.limit[z][1])){
+					this.value.now[z] = this.limit[z][1];
+				} else if ((this.limit[z][0] || this.limit[z][0] === 0) && (this.value.now[z] < this.limit[z][0])){
+					this.value.now[z] = this.limit[z][0];
+				}
+			}
+			if (options.grid[z]) this.value.now[z] -= ((this.value.now[z] - (this.limit[z][0]||0)) % options.grid[z]);
+			if (options.style) this.element.setStyle(options.modifiers[z], this.value.now[z] + options.unit);
+			else this.element[options.modifiers[z]] = this.value.now[z];
+		}
+	},
+
+	cancel: function(event){
+		this.document.removeEvents({
+			mousemove: this.bound.check,
+			mouseup: this.bound.cancel
+		});
+		if (event){
+			this.document.removeEvent(this.selection, this.bound.eventStop);
+			this.fireEvent('cancel', this.element);
+		}
+	},
+
+	stop: function(event){
+		var events = {
+			mousemove: this.bound.drag,
+			mouseup: this.bound.stop
+		};
+		events[this.selection] = this.bound.eventStop;
+		this.document.removeEvents(events);
+		this.mouse.start = null;
+		if (event) this.fireEvent('complete', [this.element, event]);
+	}
+
+});
+
+Element.implement({
+
+	makeResizable: function(options){
+		var drag = new Drag(this, Object.merge({
+			modifiers: {
+				x: 'width',
+				y: 'height'
+			}
+		}, options));
+
+		this.store('resizer', drag);
+		return drag.addEvent('drag', function(){
+			this.fireEvent('resize', drag);
+		}.bind(this));
+	}
+
+});
+
+
+/*
+---
+
+script: Drag.Move.js
+
+name: Drag.Move
+
+description: A Drag extension that provides support for the constraining of draggables to containers and droppables.
+
+license: MIT-style license
+
+authors:
+  - Valerio Proietti
+  - Tom Occhinno
+  - Jan Kassens
+  - Aaron Newton
+  - Scott Kyle
+
+requires:
+  - Core/Element.Dimensions
+  - Drag
+
+provides: [Drag.Move]
+
+...
+*/
+
+Drag.Move = new Class({
+
+	Extends: Drag,
+
+	options: {/*
+		onEnter: function(thisElement, overed){},
+		onLeave: function(thisElement, overed){},
+		onDrop: function(thisElement, overed, event){},*/
+		droppables: [],
+		container: false,
+		precalculate: false,
+		includeMargins: true,
+		checkDroppables: true
+	},
+
+	initialize: function(element, options){
+		this.parent(element, options);
+		element = this.element;
+
+		this.droppables = $$(this.options.droppables);
+		this.setContainer(this.options.container);
+
+		if (this.options.style){
+			if (this.options.modifiers.x == 'left' && this.options.modifiers.y == 'top'){
+				var parent = element.getOffsetParent(),
+					styles = element.getStyles('left', 'top');
+				if (parent && (styles.left == 'auto' || styles.top == 'auto')){
+					element.setPosition(element.getPosition(parent));
+				}
+			}
+
+			if (element.getStyle('position') == 'static') element.setStyle('position', 'absolute');
+		}
+
+		this.addEvent('start', this.checkDroppables, true);
+		this.overed = null;
+	},
+	
+	setContainer: function(container) {
+		this.container = document.id(container);
+		if (this.container && typeOf(this.container) != 'element'){
+			this.container = document.id(this.container.getDocument().body);
+		}
+	},
+
+	start: function(event){
+		if (this.container) this.options.limit = this.calculateLimit();
+
+		if (this.options.precalculate){
+			this.positions = this.droppables.map(function(el){
+				return el.getCoordinates();
+			});
+		}
+
+		this.parent(event);
+	},
+
+	calculateLimit: function(){
+		var element = this.element,
+			container = this.container,
+
+			offsetParent = document.id(element.getOffsetParent()) || document.body,
+			containerCoordinates = container.getCoordinates(offsetParent),
+			elementMargin = {},
+			elementBorder = {},
+			containerMargin = {},
+			containerBorder = {},
+			offsetParentPadding = {},
+			offsetScroll = offsetParent.getScroll();
+
+		['top', 'right', 'bottom', 'left'].each(function(pad){
+			elementMargin[pad] = element.getStyle('margin-' + pad).toInt();
+			elementBorder[pad] = element.getStyle('border-' + pad).toInt();
+			containerMargin[pad] = container.getStyle('margin-' + pad).toInt();
+			containerBorder[pad] = container.getStyle('border-' + pad).toInt();
+			offsetParentPadding[pad] = offsetParent.getStyle('padding-' + pad).toInt();
+		}, this);
+
+		var width = element.offsetWidth + elementMargin.left + elementMargin.right,
+			height = element.offsetHeight + elementMargin.top + elementMargin.bottom,
+			left = 0 + offsetScroll.x,
+			top = 0 + offsetScroll.y,
+			right = containerCoordinates.right - containerBorder.right - width + offsetScroll.x,
+			bottom = containerCoordinates.bottom - containerBorder.bottom - height + offsetScroll.y;
+
+		if (this.options.includeMargins){
+			left += elementMargin.left;
+			top += elementMargin.top;
+		} else {
+			right += elementMargin.right;
+			bottom += elementMargin.bottom;
+		}
+
+		if (element.getStyle('position') == 'relative'){
+			var coords = element.getCoordinates(offsetParent);
+			coords.left -= element.getStyle('left').toInt();
+			coords.top -= element.getStyle('top').toInt();
+
+			left -= coords.left;
+			top -= coords.top;
+			if (container.getStyle('position') != 'relative'){
+				left += containerBorder.left;
+				top += containerBorder.top;
+			}
+			right += elementMargin.left - coords.left;
+			bottom += elementMargin.top - coords.top;
+
+			if (container != offsetParent){
+				left += containerMargin.left + offsetParentPadding.left;
+				if (!offsetParentPadding.left && left < 0) left = 0;
+				top += offsetParent == document.body ? 0 : containerMargin.top + offsetParentPadding.top;
+				if (!offsetParentPadding.top && top < 0) top = 0;
+			}
+		} else {
+			left -= elementMargin.left;
+			top -= elementMargin.top;
+			if (container != offsetParent){
+				left += containerCoordinates.left + containerBorder.left;
+				top += containerCoordinates.top + containerBorder.top;
+			}
+		}
+
+		return {
+			x: [left, right],
+			y: [top, bottom]
+		};
+	},
+
+	getDroppableCoordinates: function(element){
+		var position = element.getCoordinates();
+		if (element.getStyle('position') == 'fixed'){
+			var scroll = window.getScroll();
+			position.left += scroll.x;
+			position.right += scroll.x;
+			position.top += scroll.y;
+			position.bottom += scroll.y;
+		}
+		return position;
+	},
+
+	checkDroppables: function(){
+		var overed = this.droppables.filter(function(el, i){
+			el = this.positions ? this.positions[i] : this.getDroppableCoordinates(el);
+			var now = this.mouse.now;
+			return (now.x > el.left && now.x < el.right && now.y < el.bottom && now.y > el.top);
+		}, this).getLast();
+
+		if (this.overed != overed){
+			if (this.overed) this.fireEvent('leave', [this.element, this.overed]);
+			if (overed) this.fireEvent('enter', [this.element, overed]);
+			this.overed = overed;
+		}
+	},
+
+	drag: function(event){
+		this.parent(event);
+		if (this.options.checkDroppables && this.droppables.length) this.checkDroppables();
+	},
+
+	stop: function(event){
+		this.checkDroppables();
+		this.fireEvent('drop', [this.element, this.overed, event]);
+		this.overed = null;
+		return this.parent(event);
+	}
+
+});
+
+Element.implement({
+
+	makeDraggable: function(options){
+		var drag = new Drag.Move(this, options);
+		this.store('dragger', drag);
+		return drag;
+	}
+
+});
+
+
+/*
+---
+
+script: Hash.Cookie.js
+
+name: Hash.Cookie
+
+description: Class for creating, reading, and deleting Cookies in JSON format.
+
+license: MIT-style license
+
+authors:
+  - Valerio Proietti
+  - Aaron Newton
+
+requires:
+  - Core/Cookie
+  - Core/JSON
+  - MooTools.More
+  - Hash
+
+provides: [Hash.Cookie]
+
+...
+*/
+
+Hash.Cookie = new Class({
+
+	Extends: Cookie,
+
+	options: {
+		autoSave: true
+	},
+
+	initialize: function(name, options){
+		this.parent(name, options);
+		this.load();
+	},
+
+	save: function(){
+		var value = JSON.encode(this.hash);
+		if (!value || value.length > 4096) return false; //cookie would be truncated!
+		if (value == '{}') this.dispose();
+		else this.write(value);
+		return true;
+	},
+
+	load: function(){
+		this.hash = new Hash(JSON.decode(this.read(), true));
+		return this;
+	}
+
+});
+
+Hash.each(Hash.prototype, function(method, name){
+	if (typeof method == 'function') Hash.Cookie.implement(name, function(){
+		var value = method.apply(this.hash, arguments);
+		if (this.options.autoSave) this.save();
+		return value;
+	});
+});
+
+
+/*
+---
+
+name: Swiff
+
+description: Wrapper for embedding SWF movies. Supports External Interface Communication.
+
+license: MIT-style license.
+
+credits:
+  - Flash detection & Internet Explorer + Flash Player 9 fix inspired by SWFObject.
+
+requires: [Core/Options, Core/Object, Core/Element]
+
+provides: Swiff
+
+...
+*/
+
+(function(){
+
+var Swiff = this.Swiff = new Class({
+
+	Implements: Options,
+
+	options: {
+		id: null,
+		height: 1,
+		width: 1,
+		container: null,
+		properties: {},
+		params: {
+			quality: 'high',
+			allowScriptAccess: 'always',
+			wMode: 'window',
+			swLiveConnect: true
+		},
+		callBacks: {},
+		vars: {}
+	},
+
+	toElement: function(){
+		return this.object;
+	},
+
+	initialize: function(path, options){
+		this.instance = 'Swiff_' + String.uniqueID();
+
+		this.setOptions(options);
+		options = this.options;
+		var id = this.id = options.id || this.instance;
+		var container = document.id(options.container);
+
+		Swiff.CallBacks[this.instance] = {};
+
+		var params = options.params, vars = options.vars, callBacks = options.callBacks;
+		var properties = Object.append({height: options.height, width: options.width}, options.properties);
+
+		var self = this;
+
+		for (var callBack in callBacks){
+			Swiff.CallBacks[this.instance][callBack] = (function(option){
+				return function(){
+					return option.apply(self.object, arguments);
+				};
+			})(callBacks[callBack]);
+			vars[callBack] = 'Swiff.CallBacks.' + this.instance + '.' + callBack;
+		}
+
+		params.flashVars = Object.toQueryString(vars);
+		if ('ActiveXObject' in window){
+			properties.classid = 'clsid:D27CDB6E-AE6D-11cf-96B8-444553540000';
+			params.movie = path;
+		} else {
+			properties.type = 'application/x-shockwave-flash';
+		}
+		properties.data = path;
+
+		var build = '<object id="' + id + '"';
+		for (var property in properties) build += ' ' + property + '="' + properties[property] + '"';
+		build += '>';
+		for (var param in params){
+			if (params[param]) build += '<param name="' + param + '" value="' + params[param] + '" />';
+		}
+		build += '</object>';
+		this.object = ((container) ? container.empty() : new Element('div')).set('html', build).firstChild;
+	},
+
+	replaces: function(element){
+		element = document.id(element, true);
+		element.parentNode.replaceChild(this.toElement(), element);
+		return this;
+	},
+
+	inject: function(element){
+		document.id(element, true).appendChild(this.toElement());
+		return this;
+	},
+
+	remote: function(){
+		return Swiff.remote.apply(Swiff, [this.toElement()].append(arguments));
+	}
+
+});
+
+Swiff.CallBacks = {};
+
+Swiff.remote = function(obj, fn){
+	var rs = obj.CallFunction('<invoke name="' + fn + '" returntype="javascript">' + __flash__argumentsToXML(arguments, 2) + '</invoke>');
+	return eval(rs);
+};
+
+})();
+

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Accesskey.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Accesskey.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Accesskey.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Accesskey.js Mon Jun 22 20:11:42 2015
@@ -21,33 +21,45 @@
 /*
 Function: Accesskey
     Highlight the available accesskeys to the user:
-    - underline the accesskey ( wrap inside span.accesskey )
+    - wrap the access key inside a span.accesskey to apply css style
+      (eg. underlining the access key)
     - add a suffix to the title attribute of the element with the accesskey
       in square brackets : "title [ key ]"
 
 Arguments:
     element - DOM element
-    template - (string) html template replacement string, default <span class='accesskey'>$1</span>
+
+Example:
+(start code)
+    new Accesskey( $('#menu) );
+
+    //before
+    <a id="menu" accesskey="m" title="main menu">Menu</a>
+
+    //after
+    <a id="menu" accesskey="m" title="main menu [m]"><span class="accesskey">M</span>enu</a>
+
+(end)
 */
 
-function Accesskey(element, template){
+function Accesskey(element){
 
-    if( !element.getElement('span.accesskey') ){
+    var accesskey = 'accesskey',
+        key = element.get(accesskey),
+        title = element.get('title');
 
-        var key = element.get('accesskey'),
-            title = element.get('title');
+    if( key && !element.getElement('span.'+accesskey) ){
 
-        if( key ){
+        element.set({
+            html: element.get('html').replace(
+                RegExp( '('+key+')', 'i'),
+                "<span class='"+accesskey+"'>$1</span>"
+            )
+        });
 
-            element.set({
-                html: element.get('html').replace(
-                    RegExp( '('+key+')', 'i'),
-                    template || "<span class='accesskey'>$1</span>" )
-            });
-            if( title ){ element.set('title', title + ' [ '+key+' ]'); }
+        if(title){ element.set('title', title + ' ['+key+']'); }
 
-           //console.log("ACCESSKEY ::",key, element.get('text'), element.get('title') );
+        //console.log("ACCESSKEY ::",key, element.get('text'), element.get('title') );
 
-        }
     }
-}
+}
\ No newline at end of file

Added: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.HSV.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.HSV.js?rev=1686927&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.HSV.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.HSV.js Mon Jun 22 20:11:42 2015
@@ -0,0 +1,95 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); fyou may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+/*
+Function: hsv2rgb
+    Convert HSV values into RGB values
+    Credits: www.easyrgb.com/math.php?MATH=M21#text21
+*/
+Array.implement({
+
+    hsv2rgb: function(){
+
+        var self = this,
+            r,A,B,C,F,
+            hue = self[0]/360, //hue - degrees from 0 to 360
+            sat = self[1]/100, //saturation - %
+            val = self[2]/100; //value - %
+
+        if( !sat/*sat==0*/ ){
+
+            r=[val,val,val];
+
+        } else {
+
+            hue = (hue>1) ? 0 : 6 * hue;
+            F = hue|0;  //Math.floor(hue);
+            A = val * (1 - sat);
+            B = val * (1 - sat * (hue-F) );
+            C = val + A - B; //val * (1 - sat * ( 1 - (hue-F)) );
+            //val = Math.round(val);
+
+            r = (F==0) ? [val, C, A] :
+                (F==1) ? [B, val, A] :
+                (F==2) ? [A, val ,C] :
+                (F==3) ? [A, B, val] :
+                (F==4) ? [C, A, val] : [val, A, B];
+
+        }
+
+        return r.map( function(x){ return(.5 + x*255)|0; }); ///Math.round()
+        //return [ (.5+r[0]*255)|0, (.5+r[1]*255)|0, (.5+r[2]*255)|0 ];
+
+    },
+
+    rgb2hsv: function(){
+
+        var self = this,
+            hue = 0, //hue - degrees from 0 to 360
+            sat = 0, //saturation - %
+            tmp = 255,
+            r = self[0]/tmp, dR,
+            g = self[1]/tmp, dG,
+            b = self[2]/tmp, dB,
+            maxRGB = [r,g,b].max(),         //Math.max(r, g, b),
+            deltaRGB = maxRGB - [r,g,b].min(); //Math.min(r, g, b);
+
+        if( deltaRGB ){    //if deltaRGB==0 : this is a gray, no chroma; otherwise chromatic data
+
+            sat = deltaRGB / maxRGB;
+
+            tmp = deltaRGB / 2;
+            dR = (((maxRGB - r) / 6) + tmp) / deltaRGB;
+            dG = (((maxRGB - g) / 6) + tmp) / deltaRGB;
+            dB = (((maxRGB - b) / 6) + tmp) / deltaRGB;
+
+            hue = (r == maxRGB) ? dB - dG
+                : (g == maxRGB) ? (1/3) + dR - dB
+                : /*b == maxRGB*/ (2/3) + dG - dR;
+
+            if (hue < 0) { hue += 1; }
+            if (hue > 1) { hue -= 1; }
+
+        }
+
+        return [ hue*360, sat*100, maxRGB*100 ];
+
+    }
+});

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.Extend.js Mon Jun 22 20:11:42 2015
@@ -39,21 +39,21 @@ Requires:
     - core/Elements
     - core/Array
 
-Example 
->   new Element('div',{ attach:this });      //this.element now refers to div
->   new Element('div',{ attach:[this] });    //this.element now refers to div
->   new Element('div',{ attach:[this,'myproperty'] }); //this.myproperty now refers to div
+Example
+>   new Element("div",{ attach:this });      //this.element now refers to div
+>   new Element("div",{ attach:[this] });    //this.element now refers to div
+>   new Element("div",{ attach:[this,"myproperty"] }); //this.myproperty now refers to div
 
 Example rendAr()
->   ['div',{attach:[this,'myproperty'] }].slick();
->   ['ul', ['li[text=One]','li[text=Two]','li[text=Three]']].slick();
+>   ["div",{attach:[this,"myproperty"] }].slick();
+>   ["ul", ["li[text=One]","li[text=Two]","li[text=Three]"]].slick();
 
 */
 Element.Properties.attach = {
 
     set: function( object ){
-        if(!object[0]) object = [object];
-        object[0][ object[1] || 'element' ] = this;
+        if(!object[0]){ object = [object]; }
+        object[0][ object[1] || "element" ] = this;
     }
 
 };
@@ -62,16 +62,16 @@ Array.implement({
 
     slick: function() {
 
-        var elements = [],type;
+        var elements = [], type;
 
         this.each( function(item){
-            if(item != null){ 
-            type = typeOf(item);
-            if ( type == 'elements' ) elements.append(item);
-            else if ( item.grab /*isElement*/ ) elements.push(item);
-            else if ( item.big  /*isString*/ ) elements.push(item.slick());
-            else if ( type == 'object' ) elements.getLast().set(item);
-            else if ( item.pop /*isArray*/ ) elements.getLast().adopt(item.slick());
+            if(item != null){
+                type = typeOf(item);
+                if ( type == "elements" ){ elements.append(item); }
+                else if ( item.grab /*isElement*/ ){ elements.push(item); }
+                else if ( item.big  /*isString*/ ){ elements.push(item.slick()); }
+                else if ( type == "object" ){ elements.getLast().set(item); }
+                else if ( item.pop /*isArray*/ ){ elements.getLast().adopt(item.slick()); }
             }
         });
 
@@ -80,22 +80,25 @@ Array.implement({
 
     /*
     Function: scale
-    
+
     Example
         [0,50,100].scale() == [0,0.5,1]
         [0,50,100].scale(2) == [0,1,2]
-        
+        [0.5].scale() == [0.5]
+        [0.5].scale(0, 2) == [0.25]
+
     */
-    scale: function( scale ) {
+    scale: function( minv, maxv ) {
+
 
-        var result = [],
-            i, len = this.length,
-            min = this.min(),
-            rmax = this.max() - min;
+        var i, result = [],
+            len = this.length,
+            min = isNaN( minv ) ? ( len > 1 ? this.min() : 0 ) : minv ;
+            distance = ( isNaN( maxv ) ?  this.max() : maxv ) - min ;
 
-        if( rmax == 0 ){ rmax = min; min = 0; }
+        if( distance == 0 ){ distance = min; min = 0; }
 
-        for( i=0; i<len; i++) result[i] = (scale||1) * (this[i] - min) / rmax;
+        for( i = 0; i < len; i++){ result[i] = ( this[i] - min ) / distance; }
 
         return result;
     },

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Array.NaturalSort.js Mon Jun 22 20:11:42 2015
@@ -18,28 +18,72 @@
     specific language governing permissions and limitations
     under the License.
 */
+/*jshint forin:false, noarg:true, noempty:true, undef:true, unused:true, plusplus:false, immed:false, browser:true, mootools:true */
+
+!function(){
+
+/* helper stuff for <array>.toNatural() */
+
+var reNAT = /([-+]?\d+)|(\D+)/g,  //split string in sequences of digits
+
+    //stuff to support matching KMGT patterns, like 2MB, 4GB, 1.2kb, 8Tb
+    KMGTre = /(?:[\d.,]+)\s*([kmgt])b/,
+    KMGTmul = { k: 1, m: 1e3, g: 1e6, t: 1e9 };
+
+function parseKMGT( v ){
+
+    return KMGTre.test( v.toLowerCase() ) ? v.toFloat() * KMGTmul[RegExp.$1] : NaN;
+
+}
+
 /*
- Function: naturalSort
-        Sorts the elements of an array, using a more 'natural' algoritm.
-        Maintains a cache of the prepared sortable array.
+Function: naturalCompare
+    Helper comparison function for <array>.naturalSort().
+    Each entry of the sorted array consists of a 2 item array:
+    [0] - the actual data to be sorted (can be of any data type, dom nodes, etc.)
+    [1] - the toNatural value, which is either a scalar or an array of scalars
+*/
+function naturalCompare(a, b){
 
- Example:
-        [0, 1, "017", 6, , 21 ].naturalSort();  //[0, 1, 6, "017", 21]
+    var aa, bb, i = 0, t;
 
-        [[6,"chap 1-14"],["05","chap 1-4"]].naturalSort(1); //[["05","chap 1-4"],[6,"chap 1-14"]]
-        rows.naturalSort( 3 );
+    // retrieve the toNatural values: scalars or tokenized arrays
+    a = a[1];
+    b = b[1];
+
+    // scalars, always same types - integer, float, date, string
+    // if( !a.pop ){ return a.localeCompare(b); }
+    if( !a.pop ){
+        return ( a < b ) ? -1 : ( a > b ) ? 1 : 0;
+    }
 
- */
-/*jshint forin:false, noarg:true, noempty:true, undef:true, unused:true, plusplus:false, immed:false, browser:true, mootools:true */
+    //compare arrays
+    //for(i = 0; i < len; i++){
+    while( ( aa = a[i] ) ){
 
-!function(){
+        if( !( bb = b[i++] ) ){ return 1; } //fixme
+
+        t = aa - bb;       //auto-conversion to numbers, if possible
+        if( t ){ return t; } //otherwise fall-through to string comparison
+
+        if( aa !== bb ){ return ( aa > bb ) ? 1 : -1; }
+        //if( aa !== bb ) return aa.localeCompare( bb );
+
+    }
+    return b[i] ? -1 : 0;
+}
+
+
+Array.implement({
 
     /*
-    Function: makeSortable
-        Parse the column and guess its data-type.
-        Then convert all values according to that data-type.
-        Cache the sortable values in rows[0-n].cache.
-        Empty rows will sort based on the title attribute of the cells.
+    Function: toNatural(column)
+        Convert this array into an array with natural sortable data.
+
+        1. Parse the column and auto-guess the data-type.
+        2. Convert all data to scalars according to the data-type.
+
+        DOM-nodes are sorted on its content or its title attributes. (CHECKME)
 
     Supported data-types:
         numeric - numeric value, with . as decimal separator
@@ -57,135 +101,120 @@
     Returns:
         comparison function which can be used to sort the table
     */
-    function makeSortable(thisArray, column){
+    toNatural: function( column ){
 
-        var num=[], dmy=[], kmgt=[], nat=[], val, i, len = thisArray.length, isNode,
+        var len = this.length,
+            num = [], dmy = [], kmgt = [], nat = [],
+            val, i, isNode;
 
-            //split string in sequences of digits
-            reNAT = /([-+]?\d+)|(\D+)/g,
-
-            KMGTre = /(:?[\d.,]+)\s*([kmgt])b/,    //eg 2 MB, 4GB, 1.2kb, 8Tb
-            KMGTmul = { k:1, m:1e3, g:1e6, t:1e9 },
-            KMGTparse = function( val ){
-                return KMGTre.test( val.toLowerCase() ) ?
-                    val.toFloat() * KMGTmul[ RegExp.$2 ] : NaN;
-            };
-
-        for( i=0; i<len; i++ ){
+        for(i = 0; i < len; i++){
 
             //1. Retrieve the value to be sorted: native js value, or dom elements
 
-            val = thisArray[i];
+            val = this[i];
             isNode = val && val.nodeType;
 
-            //if 'column' => retrieve the nth DOM-element or the nth Array-item
-            if( !isNaN(column) ) val = ( isNode ? val.getChildren() : val )[column];
+            //if "column" => retrieve the nth DOM-element or the nth Array-item
+            if( !isNaN(column) ){ val = ( isNode ? val.getChildren() : val )[column]; }
 
             //retrieve the value and convert to string
-            val = (''+(isNode ? val.get('text') || val.get('title') : val)).trim();
+            val = ("" + (isNode ? val.get("text") || val.get("title") : val)).trim();
+
 
-            //2. Convert and store in type specific arrays (num,dmy,kmgt,nat)
+            //2. Convert and store in type specific arrays (num, dmy, kmgt, nat)
 
             //CHECKME: some corner cases: numbers with leading zero's, confusing date string
-            if( /(?:^0\d+)|(?:^[^\+\-\d]+\d+$)/.test(val) ){ num=dmy=0; }
+            if( /(?:^0\d+)|(?:^[^\+\-\d]+\d+$)/.test(val) ){ num = dmy = 0; }
 
-            if( num && isNaN( num[i] = +val ) ) num=0;
+//remove non numeric tail : replace( /[\w].*$/,'');
+            if( num && isNaN( num[i] = +val ) ){ num = 0; }
+            //if( num && isNaN( num[i] = + val.replace(/[\W].*$/,"") ) ){ num = 0; }
 
-            if( nat && !( nat[i] = val.match(reNAT) ) ) nat=0;
+            if( nat && !( nat[i] = val.match(reNAT) ) ){ nat = 0; }
 
             //Only strings with non-numeric values
-            if( dmy && ( num || isNaN( dmy[i] = Date.parse(val) ) ) ) dmy=0;
+            if( dmy && ( num || isNaN( dmy[i] = Date.parse(val) ) ) ){ dmy = 0; }
 
-            if( kmgt && isNaN( kmgt[i] = KMGTparse(val) ) ) kmgt=0;
+            if( kmgt && isNaN( kmgt[i] = parseKMGT(val) ) ){ kmgt = 0; }
 
         }
 
-        console.log("[",kmgt?"kmgt":dmy?"dmy":num?"num":nat?"nat":'no conversion',"] ");
-        //console.log(nat);
-        //console.log(kmgt||dmy||num||nat||thisArray);
+        //console.log("[", kmgt ? "kmgt" : dmy ? "dmy" : num ? "num" : nat ? "nat" : "no conversion", "] ");
 
-        return kmgt || dmy || num || nat || thisArray;
+        return kmgt || dmy || num || nat || this.slice();
 
-    }
+    },
 
     /*
-    Function: naturalCmp
-        Comparison function for sorting "natural sortable" arrays.
-        The entries of sortable arrays consists of tupples:
-        ( .[1] is the sortable value, .[0] is the original value )
-
-        The sortable value is either a scalar or an array.
-    */
-    function naturalCmp(a,b){
-
-        var aa, bb, i=0, t;
-
-        // retrieve the sortable values: scalars or tokenized arrays
-        a = a[1]; b = b[1];
-
-        // scalars, always same types - integer, float, date, string
-        if( typeof a !='object' ) return (a<b) ? -1 : (a>b) ? 1 : 0;
-        //if( !a.length ) return a.localeCompare(b);
-
-        while( (aa = a[i]) ){
-
-            if( !( bb = b[i++] ) ) return 1; //fixme
+    Function: naturalSort
+        Sort the elements of an array, using a "natural" algoritm.
+        First it converts to sort key into a toNatural array: <array>.toNatural()
+        Then it sorts the array with the naturalCompare() routine.
+        To increase speed, the toNatural arrays are cached.
 
-            t = aa - bb;       //auto-conversion to numbers, if possible
-            if( t ) return t;  //otherwise fall-through to string comparison
+    Example:
+        [0, 1, "017", 6, , 21 ].naturalSort();  //=> [0, 1, 6, "017", 21]
 
-            if( aa !== bb ) return (aa > bb) ? 1 : -1;
-            //if( aa !== bb ) return aa.localeCompare(bb);
-
-        }
-        return b[i] ? -1 : 0;
-    }
+        [[6,"chap 1-14"],["05","chap 1-4"]].naturalSort(1); //=> [["05","chap 1-4"],[6,"chap 1-14"]]
 
+        rows.naturalSort( 3 ); //eg HTML table rows, sorting key is the 3rd table column
+    */
+    naturalSort: function(column, force){
 
-    Array.implement('naturalSort',function(column, force){
+        var self = this,
+            naturalArr = [],
+            cache = "cache",
+            len = self.length,
+            i;
 
-        var thisArray = this, sortable, i, len = thisArray.length,
-            cache = 'cache';
 
-console.log('naturalSort',column,force)
-        //1. read sortable cache or make a new sortable array
-        if( isNaN(column) ){    // 1D array : [ .. ]
+        //1. Retrieve toNatural: either from cache or via <array>.toNatural
 
-            sortable = thisArray[cache] || [];
+        if( isNaN( column ) ){    // 1D array : [ .. ]
 
-            if( column/*==force*/ || !sortable.length/*==0*/ ){
+            naturalArr = self[cache];
+            if( column/*==force*/ || !naturalArr ){
 
-                sortable = thisArray[cache] = makeSortable(thisArray);
+                naturalArr = self[cache] = self.toNatural();
 
             }
 
         } else {    // 2D array : [[..],[..],..]
 
-            sortable = thisArray[0][cache] || [];
+            //init 2D cache if not present
+            if( !self[0][cache] ){
+
+                 for(i = 0; i < len; i++){ self[i][cache] = []; }
 
-            if( !sortable.length ) for(i=0; i<len; i++) thisArray[i][cache] = []; //init row caches
+            }
 
-            if( force || (sortable[column]==undefined) ){
+            if( force || isNaN( self[0][cache][column] ) ){
 
-                sortable = makeSortable(thisArray, column);
-                for(i=0; i<len; i++) thisArray[i][cache][column] = sortable[i]; //cache sortable values
+                naturalArr = self.toNatural(column);
+                for(i = 0; i < len; i++){ self[i][cache][column] = naturalArr[i]; }
 
             } else {
 
-                for(i=0; i<len; i++) sortable[i]=thisArray[i][cache][column];  //retrieve cached column
+                //retrieved cached toNatural array
+                naturalArr = [];
+                for(i = 0; i < len; i++){ naturalArr[i] = self[i][cache][column]; }
 
              }
 
         }
 
-console.log(this.cache);
         //2. Do the actual sorting
-        for( i=0; i<len; i++) sortable[i] = [ thisArray[i], sortable[i] ];
-        sortable.sort( naturalCmp );
-        for( i=0; i<len; i++) thisArray[i] = sortable[i][0];
 
-        return thisArray;
+        for(i = 0; i < len; i++){ naturalArr[i] = [ self[i], naturalArr[i] ]; }
+
+        naturalArr.sort( naturalCompare );
+
+        for(i = 0; i < len; i++){ self[i] = naturalArr[i][0]; }
+
+        return self;
+
+    }
 
-    });
+  });
 
 }();

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Behavior.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Behavior.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Behavior.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Behavior.js Mon Jun 22 20:11:42 2015
@@ -51,7 +51,7 @@ var Behavior = new Class({
 
     add: function(selector, behavior, options, once){
 
-        this.behaviors.push({s: selector, b: behavior, o: options, once:once});
+        this.behaviors.push({s: selector, b: behavior, o: options, once: once});
         return this;
 
     },
@@ -64,38 +64,44 @@ var Behavior = new Class({
 
     update: function(){
 
-        //console.log(this.behaviors);
-        var cache = "_bhvr", updated, type, nodes;
+        var cache = "_bhvr", updated, type, isClass, isFunction,
+            nodes, node, i = 0, j, item, behavior, options;
 
-        this.behaviors.each( function( behavior ){
+        while( item = this.behaviors[ i++ ] ){
 
-            nodes = $$(behavior.s);
-            type = typeOf(behavior.b);
-            //console.log("BEHAVIOR ", behavior.once?"ONCE ":"", nodes.length, behavior.s, typeOf(behavior.b) );
+            //console.log("BEHAVIOR ", item.once?"ONCE ":"", nodes.length, item.s, typeOf(item.b) );
+            options = item.o;
+            behavior = item.b;
+            type = typeOf(behavior);
+            isClass = ( type == "class" );
+            isFunction = ( type == "function" );
 
-            if( behavior.once && nodes[0] ){
+            nodes = $$(item.s); //selector
+            if( nodes[0] ){
 
-                if( type == 'class'){ new behavior.b(nodes, behavior.o); }
-                else if( type == 'function'){ behavior.b(nodes, behavior.o); }
+                if( item.once ){
 
-            } else {
+                    if( isClass ){ new behavior(nodes, options); }
+                    else if( isFunction ){ behavior(nodes, options); }
 
-                nodes.each( function(node){
+                } else {
 
-                    updated = node[cache] || (node[cache] = []);
+                    for( j=0; node = nodes[ j++ ]; ){
 
-                    if ( updated.indexOf(behavior) == -1 ){
+                        updated = node[cache] || (node[cache] = []);
 
-                        //if( type == 'string' ) node[behavior.b](behavior.o);
-                        if( type == 'class'){ new behavior.b(node, behavior.o); }
-                        else if( type == 'function'){ behavior.b.call(node, node, behavior.o); }
+                        if ( updated.indexOf(item) < 0 ){
 
-                        updated.push( behavior );
+                            //if( isString ) node[behavior](options);
+                            if( isClass ){ new behavior(node, options); }
+                            else if( isFunction ){ behavior.call(node, node, options); }
+
+                            updated.push( item );
+                        }
                     }
-                });
+                }
             }
-
-        })
+        }
 
         return this;
     }

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Color.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Color.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Color.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Color.js Mon Jun 22 20:11:42 2015
@@ -47,8 +47,7 @@ Examples:
 
 !function(){
 
-var RGB = 'rgb',
-    VGA = "black#000 green#008000 silver#c0c0c0 lime#0f0 gray#808080 olive#808000 white#fff yellow#ff0 maroon#800000 navy#000080 red#f00 blue#00f purple#800080 teal#008080 fuchsia#f0f aqua#0ff",
+var VGA = "black#000 green#008000 silver#c0c0c0 lime#0f0 gray#808080 olive#808000 white#fff yellow#ff0 maroon#800000 navy#000080 red#f00 blue#00f purple#800080 teal#008080 fuchsia#f0f aqua#0ff",
     c0l0r = 'i'.slick(),
 
     Color = this.Color = new Type('Color', function(color){
@@ -59,14 +58,14 @@ var RGB = 'rgb',
 
     } else if (typeof color == 'string'){
 
-        if(color.test(/^[\da-f]{3,6}$/i)) color = "#"+color;
+        if(color.test(/^[\da-f]{3,6}$/i)){ color = "#"+color; }
         c0l0r.setStyle('color',''); //reset the template
         color = ( VGA.test( RegExp(color+"(#\\S+)","i" ) ) ? RegExp.$1 :
             color.match(/rgb/i) ? color.rgbToHex() :
                 c0l0r.setStyle('color',color).getStyle('color') ).hexToRgb(true);
 
     }
-    if(!color) return null;
+    if(!color){ return null; }
     color.rgb = color.slice(0, 3);
     color.hex = color.rgbToHex();
     return Object.append(color, this);
@@ -84,7 +83,7 @@ Color.implement({
         while( colors[0] ){
             color = new Color( colors.shift() );
             for (i=0; i < 3; i++){ rgb[i] = ((rgb[i] * alphaI) + (color[i] * alpha)).round(); }
-        };
+        }
         return new Color(rgb);
 
     },
@@ -100,4 +99,4 @@ Color.implement({
 
 });
 
-}();
+}();
\ No newline at end of file

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Date.Extend.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Date.Extend.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Date.Extend.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Date.Extend.js Mon Jun 22 20:11:42 2015
@@ -29,6 +29,8 @@ Example:
 > alert( new Date().toISOString() ); // alerts 2009-05-21
 > alert( new Date().toISOString() ); // alerts 2009-05-21T16:06:05.000TZ
 */
+
+/* Obsolete -- now covered by ECMAScript5, ok in most browsers
 Date.extend({
     toISOString: function(){
         var d = this,
@@ -38,3 +40,4 @@ Date.extend({
         return d.getFullYear() + '-' + (mm<10 ?'0':'') + mm + '-' + (dd<10 ?'0':'') + dd;
     }
 });
+*/

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Element.Extend.js Mon Jun 22 20:11:42 2015
@@ -39,55 +39,61 @@ Element.implement({
         (element) - This Element
 
     Examples:
-    >    $('page').ifClass( i>5, 'hideMe' );
+    >    $("page").ifClass( i > 5, "hideMe" );
     */
-    ifClass : function(flag, T_Class, F_Class){
+    ifClass: function(flag, trueClass, falseClass){
 
-        return this.addClass(flag?T_Class:F_Class).removeClass(flag?F_Class:T_Class);
+        trueClass = trueClass || "";
+        falseClass = falseClass || "";
+
+        return this.addClass(flag ? trueClass : falseClass).removeClass(flag ? falseClass : trueClass);
 
     },
 
-	/*
-	Function: wrapChildren
-		This method moves this Element around its children elements.
-		The Element is moved to the position of the passed element and becomes the parent.
-		All child-nodes are moved to the new element.
+    /*
+    Function: wrapChildren
+        This method moves this Element around its children elements.
+        The Element is moved to the position of the passed element and becomes the parent.
+        All child-nodes are moved to the new element.
 
-	Arguments:
-		el - DOM element.
+    Arguments:
+        el - DOM element.
 
-	Returns:
-		(element) This Element.
+    Returns:
+        (element) This Element.
 
-	DOM Structure:
-	(start code)
+    DOM Structure:
+    (start code)
         //before
-		div#firstElement
-		    <children>
+        div#firstElement
+            <children>
 
-    	//javaScript
-	    var secondElement = 'div#secondElement'.slick();
-	    secondElement.wrapChildren($('myFirstElement'));
-
-	    //after
-		div#firstElement
-    		div#secondElement
-            <children>	
+        //javaScript
+        var secondElement = "div#secondElement".slick();
+        secondElement.wrapChildren($("myFirstElement"));
+
+        //after
+        div#firstElement
+            div#secondElement
+            <children>
     (end)
-	*/
-	wrapChildren : function(el){
-	
-		while( el.firstChild ){ this.appendChild( el.firstChild ); }
-		el.appendChild( this ) ;
-		return this;
+    */
+    /*CHECKME: obsolete ??
+    wrapChildren : function(el){
 
-	},
+        while( el.firstChild ){ this.appendChild( el.firstChild ); }
+        el.appendChild( this ) ;
+        return this;
 
+    },
+    */
 
     /*
     Function: addHover
-        Shortcut function to add 'hover' css class to an element.
+        Shortcut function to add a css class to an element on mouseenter,
+        and remove it again on mouseleave.
         This allows to support :hover effects on all elements, also in IE.
+        Obsolete
 
     Arguments
         clazz - (optional) hover class-name, default is {{hover}}
@@ -96,11 +102,11 @@ Element.implement({
         (element) - This Element
 
     Examples:
-    >    $('thisElement').addHover();
+    >    $("thisElement").addHover();
     */
     addHover: function( clazz ){
 
-        clazz = clazz || 'hover';
+        clazz = clazz || "hover";
 
         return this.addEvents({
             mouseenter: function(){ this.addClass(clazz); },
@@ -111,13 +117,14 @@ Element.implement({
 
     /*
     Function: onHover
-        Convert element into a hover menu.
+        Turns a DOM element into a hoverable menu.
 
     Arguments:
         toggle - (string,optional) A CSS selector to match the hoverable toggle element
+        onOpen - (function, optional) Function which is call when opening the menu
 
     Example
-    > $('li.dropdown-menu').onHover('ul');
+    > $("li.dropdown-menu").onHover("ul");
     */
     onHover: function( toggle, onOpen ){
 
@@ -125,11 +132,18 @@ Element.implement({
 
         if( toggle = element.getParent(toggle) ){
 
-             element.fade('hide');
+             element.fade("hide");  //CHECKME : is this sill needed, menu should be hidden/visible depending on .open
 
              toggle.addEvents({
-                mouseenter: function(){ element.fade(0.9); toggle.addClass('open'); if(onOpen) onOpen(); },
-                mouseleave: function(){ element.fade(0);   toggle.removeClass('open'); }
+                mouseenter: function(){
+                    element.fade(0.9);
+                    toggle.addClass("open");
+                    if(onOpen){ onOpen(); }
+                },
+                mouseleave: function(){
+                    element.fade(0);
+                    toggle.removeClass("open");
+                }
             });
 
         }
@@ -138,58 +152,61 @@ Element.implement({
 
     /*
     Function: onToggle
-        Set/reset '.active' class, based on 'data-toggle' attribute.
+        Set/reset ".active" class of an element, based on click events received on
+        the element referred to by the "data-toggle" attribute.
 
     Arguments:
-        toggle - A CSS selector of one or more clickable toggle button
-            A special selector "buttons" is available for style toggling
-            of a group of checkboxes or radio-buttons.  (ref. Bootstrap)
-        
-        active - CSS classname to toggle this element (default .active )
+        toggle - A CSS selector of clickable toggle buttons
+            The selector "buttons" is used to style a group of checkboxes or radio-buttons.  (ref. Bootstrap)
+
+        active - CSS classname to toggle this element (default is ".active" )
 
     Example
     (start code)
-       wiki.add('div[data-toggle]', function(element){
-           element.onToggle( element.get('data-toggle') );
+       wiki.add("[data-toggle]", function(element){
+           element.onToggle( element.get("data-toggle") );
        })
     (end)
-    
+
     DOM Structure
     (start code)
         //normal toggle case
-        div[data-toggle="button#somebutton"](.active) That
+        div[data-toggle="button#somebutton"](.active)
         ..
         button#somebutton Click here to toggle that
-        
+
         //special toggle case with "buttons" selector
         div.btn-group[data-toggle="buttons"]
             label.btn.btn-default(.active)
-                input[type="radio"][name="aRadio"] checked='checked' value="One" />
+                input[type="radio"][name="aRadio"] checked="checked" value="One" />
             label.btn.btn-default(.active)
                 input[type="radio"][name="aRadio"] value="Two" />
-        
+
     (end)
 
     */
     onToggle: function( toggle, active ){
 
         var element = this;
+        active = active || "active";
 
         if( toggle == "buttons" ){
-        
-            (toggle = function(e){
-                //FIXME: differentiate between radioboxes and checkboxes !!
-                element.getElements(".active").removeClass("active");
-                element.getElements(":checked !").addClass("active");
-            })();
-            element.addEvent('click', toggle);
-        
+
+            toggle = function(event){
+                //FIXME: differentiate between radioboxes and checkboxes
+                element.getElements("." + active).removeClass(active);
+                //console.log(element.getElements(":checked !>").length, element);
+                element.getElements(":checked !>").addClass(active);
+            };
+            toggle();
+            element.addEvent("click", toggle);
+
         } else {
 
             //if(!document.getElements(toggle)[0]){ console.log("toggle error:",toggle); }
-            document.getElements(toggle).addEvent('click', function(event){
+            document.getElements(toggle).addEvent("click", function(event){
                 event.stop();
-                element.toggleClass( active || 'active');
+                element.toggleClass( active );
             });
 
         }
@@ -198,51 +215,135 @@ Element.implement({
     },
 
     /*
+    Function onModal
+        Open a modal dialog with ""message"".
+
+        Used on forms (submit) or form-elements (click) to get a
+        confirmation prior to executing the default behaviour of the event.
+        TODO: use DOM based modal dialog rather then JS confirm(..)
+
+    Example:
+    (start code)
+        <form data-modal="Are your really sure?" ... > .. </form>
+
+        behavior.add("[data-modal]", function(element){
+            element.onModal( element.get("data-modal") );
+        });
+
+    (end)
+
+    */
+    onModal: function( message ){
+
+        this.addEvent( this.match("form") ? "submit" : "click", function( /*event*/ ){
+
+console.log(message);
+
+            return window.confirm(message);
+            /*
+            TODO
+            build modal dialog
+            modalbody.set("html",message);
+            return modaldialog.show();
+            */
+
+        });
+    },
+
+    /*
+    Function sticky
+        Simulate "position:sticky".
+        Keep the element fixed on the screen, during scrolling.
+        Only supports top-bottom scrolling.
+
+    Example:
+    (start code)
+        //css
+        .sticky {
+            display:block;
+            + .sticky-spacer { .hide; }
+        }
+        .stickyOn {
+            position: fixed;
+            top: 0;
+            z-index: @sticky-index;
+
+            // avoid page-bump when sticky become "fixed", by adding a spacer with its height
+            + .sticky-spacer { .show; }
+        }
+
+        wiki.add(".sticky", function(element){ element.onSticky() );  });
+    (end)
+    */
+    onSticky: function(){
+
+        //FFS: check for native position:sticky support
+        var element = this,
+            origWidth = element.offsetWidth,
+            origOffset = element.getPosition(document.body).y, //get offset relative to the doc.body
+            on;
+
+        "div.sticky-spacer".slick({styles: {height: element.offsetHeight} }).inject(element, "after");
+
+        //FFS: consider adding throttle to limit event invocation rate eg "scroll:throttle"
+        document.addEvent("scroll", function(){
+
+            on = ( window.scrollY >= origOffset );
+
+            element.ifClass(on, "stickyOn").setStyle("width", on ? origWidth : "" );
+            //take care of the "inherited" width
+            //set the width of the fixed element, because "position:fixed" is relative to the document,
+            //therefore the element may loose inherited box widths (FFS: quid other inherited styles ??)
+
+        });
+    },
+
+    /*
     Function: getDefaultValue
         Returns the default value of a form element.
-        Inspired by get('value') of mootools, v1.1
+        Inspired by get("value") of mootools, v1.1
 
     Note:
         Checkboxes will return true/false depending on the default checked status.
         ( input.checked to read actual value )
-        The value returned in a POST will be input.get('value')
-        and is depending on the value set by the 'value' attribute (optional)
+        The value returned in a POST will be input.get("value")
+        and is depending on the value set by the "value" attribute (optional)
 
     Returns:
         (value) - the default value of the element; or false if not applicable.
 
     Examples:
-    > $('thisElement').getDefaultValue();
+    > $("thisElement").getDefaultValue();
     */
     getDefaultValue: function(){
 
         var self = this,
-            type = self.get('type'),
+            type = self.get("type"),
             values = [];
 
-        switch( self.get('tag') ){
+        switch( self.get("tag") ){
 
-            case 'select':
+            case "select":
 
                 Array.from(this.options).each( function(option){
 
-                    if (option.defaultSelected){ values.push(option.value||option.text); }
+                    if (option.defaultSelected){ values.push(option.value || option.text); }
 
                 });
 
                 return (self.multiple) ? values : values[0];
 
-            case 'input':
+            case "input":
 
-                if( type == 'checkbox' ){   //checkbox.get-value = returns 'on' on some browsers, T/F on others
+                if( type == "checkbox" ){   //checkbox.get-value = returns "on" on some browsers, T/F on others
 
-                    return ('input[type=checkbox]'+(self.defaultChecked?":checked":"")).slick().get('value');
+                    return ("input[type=checkbox]" + (self.defaultChecked?":checked":"")).slick().get("value");
 
                 }
 
-                if( !'radio|hidden|text|password'.test(type) ){ break; }
+                if( !"radio|hidden|text|password".test(type) ){ break; }
 
-            case 'textarea':
+            case "textarea":
 
                 return self.defaultValue;
 
@@ -279,31 +380,31 @@ Element.implement({
             b
 
     Example:
-    >   el.groupChildren(/hr/i,'div.col');  
-    >   el.groupChildren(/h[1-6]/i,'div.col');
-    >   el.groupChildren( container.getTag(), 'div');
+    >   el.groupChildren(/hr/i,"div.col");
+    >   el.groupChildren(/h[1-6]/i,"div.col");
+    >   el.groupChildren( container.getTag(), "div");
     */
-    groupChildren:function(start, grab, replacesFn){
+    groupChildren: function(start, grab, replacesFn){
 
-        var next, 
-            group = grab.slick().inject(this,'top'),
+        var next,
+            group = grab.slick().inject(this, "top"),
             firstGroupDone = false;
 
         //need at least one start element to get going
         if( this.getElement(start) ){
 
             while( next = group.nextSibling ){
-            
-                if( ( next.nodeType!=3 ) && next.match(start) ){  //start a new group
-                    
-                    if( firstGroupDone ){  group = grab.slick(); } //make a new group
-                    if( replacesFn ) replacesFn(group, next); 
+
+                if( ( next.nodeType != 3 ) && next.match(start) ){  //start a new group
+
+                    if( firstGroupDone ){ group = grab.slick(); } //make a new group
+                    if( replacesFn ){ replacesFn(group, next); }
                     group.replaces( next );  //destroys the matched start element
                     firstGroupDone = true;
 
                 } else {
 
-                    group.appendChild( next );  //grap all other elements in the group 
+                    group.appendChild( next );  //grab all other elements in the group
 
                 }
             }
@@ -318,30 +419,30 @@ Element.implement({
     Arguments:
         fn - callback function
         options - (object)
-        options.event - (string) event-type to observe, default = 'keyup'
+        options.event - (string) event-type to observe, default = "keyup"
         options.delay - (number) timeout in ms, default = 300ms
 
     Example:
     >    $(formInput).observe(function(){
-    >        alert('my value changed to '+this.get('value') );
+    >        alert("my value changed to "+this.get("value") );
     >    });
 
     */
     observe: function(callback, options){
 
         var element = this,
-            value = element.get('value'),
-            event = (options && options.event) || 'keyup',
+            value = element.get("value"),
+            event = (options && options.event) || "keyup",
             delay = (options && options.delay) || 300,
             timer = null;
 
-        return element.set({autocomplete:'off'}).addEvent(event, function(){
+        return element.set({autocomplete: "off"}).addEvent(event, function(){
 
-            var v = element.get('value');
+            var v = element.get("value");
 
             if( v != value ){
                 value = v;
-                //console.log('observer ',v);
+                //console.log("observer ",v);
                 clearTimeout( timer );
                 timer = callback.delay(delay, element);
             }

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.File.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.File.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.File.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.File.js Mon Jun 22 20:11:42 2015
@@ -28,10 +28,9 @@ Credit:
     Arian Stolwijk, [https://github.com/arian/mootools-form-upload]
 
 */
-
 !function(){
-//"use strict";
 
+//"use strict";
 if (!this.Form) this.Form = {};
 var Form = this.Form;
 
@@ -40,126 +39,123 @@ Form.File = new Class({
     Implements: [Options, Events],
 
     options: {
+
         max: 5, //maximum number of files to upload in one go...  0=unlimited.
-        list: '.list-group',
-        item: '.list-group-item',
-        drop: '.droppable',
-        progress: '.progress-bar',
+        list: ".list-group",
+        item: ".list-group-item",
+        drop: ".droppable",
+        progress: ".progress-bar",
         fireAtOnce: false,
         onComplete: function(){
             // reload
             window.location.href = window.location.href;
         }
-        
     },
 
     initialize: function(input, options){
-    
-        input = document.id(input);
 
-        var form = input.getParent('form');
+        var form,
+            isXHR20 = false; //force old browser -- FIXME:  "FormData" in window;
+
+        input = document.id(input);
+        form = input.getParent("form");
         if(!form) return false;
-        
-        this.setOptions(options);
-        this.nbr = 0; //counter
-        var list = this.list = input.getParent(this.options.list);
-        this.submit = form.getElement('input[type=submit]');
-        this.progress = form.getElement(this.options.progress);
-        
-        //console.log('FormData' in window ? "XHR2.0":"legacy");
-        this['disabled-for-now-FormData' in window ? 'uploadXHR2' : 'upload'](form, input,list);
-        
+
+        options = this.setOptions(options).options;
+        this.nbr = 0; //upload file counter
+        this.list = input.getParent(options.list);
+        this.submit = form.getElement("input[type=submit]");
+        this.progress = form.getElement(options.progress);
+
+        //console.log("XHR20 ? ", isXHR20);
+        form.ifClass( isXHR20, "XHR20" , "legacy" );
+        this[ isXHR20 ? "uploadXHR2" : "upload"](form, input, this.list, options);
+
     },
 
     update: function( step ){
 
         var self = this,
-            disabled = 'disabled';
-           
-           console.log('update ',self.nbr,step); 
+            disabled = "disabled";
+
+        console.log("update ",self.nbr,step);
+
         self.nbr += step;
-        self.submit.set(disabled, self.nbr ? '':disabled );  
-        self.list.getFirst().ifClass(self.nbr >= self.options.max, disabled);                  
+        self.submit.set(disabled, self.nbr ? "":disabled );
+        self.list.getFirst().ifClass(self.nbr >= self.options.max, disabled);
 
     },
 
-    uploadXHR2: function(form,input,list){
-
-        //console.log("xhr2.0", form.action, form.get('action'), input.name);
+    uploadXHR2: function(form,input,list, options){
 
-        var self = this, 
-            options = self.options,
-            name = input.get('name'),
+        var self = this,
+            name = input.get("name"),
             drop = form.getElement(options.drop),
             progress = self.progress,
+
             fireAtOnce = function(){ if(options.fireAtOnce) submit(); },
 
             uploadReq = new Request.File({
-
-                url: form.get('action'),
+                url: form.get("action"),
                 onRequest: function(){
-                    progress.setStyle('width', 0).getParent().removeClass('hidden');
+                    progress.setStyle("width", 0).getParent().removeClass("hidden");
                 },
                 onProgress: function(event){
                     var percent = event.loaded.toInt(10) / event.total.toInt(10);
-                    progress.setStyle('width', (percent * 100).toInt().limit(0,100) + '%');
+                    progress.setStyle("width", (percent * 100).toInt().limit(0,100) + "%");
                 },
                 onComplete: function(){
-                    progress.setStyle('width', '100%');
-                    self.fireEvent('complete', Array.slice(arguments));
+                    progress.setStyle("width", "100%");
+                    self.fireEvent("complete", Array.slice(arguments));
                     this.reset();
                 }
             }),
 
             //select one or more files via input[type=file] or drag/drop
-            inputFiles = new Form.MultipleFileInput(input, list, drop, {
-
+            inputFiles = new Form.MultipleFile(input, list, drop, {
                 onDrop: fireAtOnce,
                 onChange: fireAtOnce,
                 onAdd: self.update.pass(+1,self),
                 onRemove: self.update.pass(-1,self)
-
             }),
 
             submit = function(event){
-
                 if (event) event.preventDefault();
-                 inputFiles.getFiles().each(function(file){ 
+                 inputFiles.getFiles().each(function(file){
                     uploadReq.append(name, file);
                 });
                 uploadReq.send();
+            };
 
-            }
-        
-        form.addEvent('submit', submit);
+        form.addEvent("submit", submit);
 
         self.reset = function(){
+
             console.log(" reset ");
             var files = inputFiles.getFiles();
-            while( files[0] ) inputFiles.remove( files.shift() );
+
+            while( files[0] ){ inputFiles.remove( files.shift() ); }
             /*
             for (var i = 0; i < files.length; i++){
                 inputFiles.remove(files[i]);
             }
             */
-        }
-        
-        
-    },
 
+        };
+
+    },
     /*
     Function: upload
-        Legacy upload handler, compatible with legacy input[type=file] capabilities
-    
-    The script works by hiding the file input element when a file is selected,
-    then immediately replacing it with a new, empty one.
-    Although ideally the extra elements would be hidden using the CSS setting
-    'display:none', this causes Safari to ignore the element completely when
-    the form is submitted. So instead, elements are moved to a position
-    off-screen.
-    On submit, any remaining empty file input element is removed.
+        Legacy upload handler, compatible with legacy input[type=file] capabilities.
+
+        The script works by hiding the file input element when a file is selected,
+        then immediately replacing it with a new, empty one.
+        Although ideally the extra elements would be hidden using the CSS setting
+        "display:none", this causes Safari to ignore the element completely when
+        the form is submitted. So instead, elements are moved to a position
+        off-screen.
+        On submit, any remaining empty file input element is removed.
 
-    
     DOM structure:
     (start code)
      ul.list-group
@@ -167,92 +163,85 @@ Form.File = new Class({
             a
                 label.add
                     input[type=file][id=attachefilename][name=content[?]]
-            a.delete            
+            a.delete
         li.list-group-item
             a
                 label.add
                     input[type=file][id=unique]
-            a.delete            
+            a.delete
     (end)
     */
-    upload: function(form,input,list){
-    
-        console.log("legacy");
+    upload: function(form,input,list,options){
 
-        var self = this,
-            options = self.options;
-        
-        list.addEvents({
+        var self = this;
 
-            'change:relay(input)': function( event ){
+        list.addEvents({
+            "change:relay(input)": function(){
 
                 //this event can only be received on the first input[type=file]
                 var input = this,
-                    item = input.getParent(options.item);
+                    item = input.getParent(options.item),
                     newItem = item.clone(true, true);
 
-                input.set('id',String.uniqueID());
-                item.getElement('label').set('text', input.value.replace(/.*[\\\/]/, '') );
-                item.getElement('.delete').removeClass('hidden');
-                item.removeClass('droppable');        
-            
-                list.grab(newItem,'top');
+                input.set("id",String.uniqueID());
+                item.getElement("label").set("text", input.value.replace(/.*[\\\/]/, "") );
+                item.getElement(".delete").removeClass("hidden");
+                item.removeClass("droppable");
+                list.grab(newItem,"top");
                 self.update(+1);
             },
-
-            'click:relay(a.delete)': function(event){
-
+            "click:relay(a.delete)": function(){
                 this.getParent(options.item).destroy();
                 self.update(-1);
-
             }
         });
-        
-        form.addEvent('submit', function(event){
 
-            list.getElement('input').destroy(); //remove first input[type=file] which is empty
+        form.addEvent("submit", function(){
+            list.getElement("input").destroy(); //remove first input[type=file] which is empty
             self.progressRpc();   //legacy rpc-based progress handler...
-
         });
 
         /* not used
         this.reset = function(){
-            list.getElements(':not(:first-child)').destroy(); 
+            list.getElements(":not(:first-child)").destroy();
         };
         */
 
     },
-    
+
     /*
     Function: progressRpc
         JSPWiki progress-bar implementation based on JSON-RPC
-
     JSON-RPC protocol:
     {{{
     --> {"id":10000,"method":"progressTracker.getProgress","params":["2a0d2563-1ec7-4d1e-9d10-5f4ae62e8251"]}:
-    <-- {"id":10000,"result":30}                                
+    <-- {"id":10000,"result":30}
     }}}}
     */
     progressRpc: function(){
-        
+
         var progress = this.progress;
-            
+
         if( progress ){
-            
-            progress.getParent().removeClass('hidden');
-                
-            this.options.rpc( progress.get('data-progressid'), function(result){
 
-                //console.log("rpc progress result ",result);                
-                if( result && result.code ){
+            progress.getParent().removeClass("hidden");
+
+            this.options.rpc( progress.get("data-progressid"), function(result){
+
+                //CHECKME:  alert("rpc progress result ",result);
+
+                if( result ){
                     result = result.toInt().limit(0,100);
-                    progress.setStyle('width',result+"%");
+                    progress.setStyle("width",result + "%");
                     if( result < 100 ){ progressRpc.delay(500); }
-                }               
+                }
+
             });
-        }                
+
+        }
+
     }
 
 });
 
-}();
+}();
\ No newline at end of file

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.MultipleFile.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.MultipleFile.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.MultipleFile.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/moo-extend/Form.MultipleFile.js Mon Jun 22 20:11:42 2015
@@ -55,7 +55,7 @@ Form.MultipleFile = new Class({
     _files: [],
 
     initialize: function(input, list, drop, options){
-    
+
         input = this.element = document.id(input);
         list = this.list = document.id(list);
         drop = document.id(drop);
@@ -77,17 +77,17 @@ Form.MultipleFile = new Class({
         });
 
         function activateDrop(event, isOn){
-            drop.ifClass(isOn, 'active', '');
+            drop.ifClass(isOn, 'active');
             self.fireEvent( event.type, event );
         };
 
         if(drop && (typeof document.body.draggable != 'undefined')){
-        
+
             input.addEvents({
             dragenter: function(event){ activateDrop(event,true); }, //self.fireEvent.bind(self, 'dragenter'),
             dragleave: function(event){ activateDrop(event,false); }, //self.fireEvent.bind(self, 'dragleave'),
             dragend: self.fireEvent.bind(self, 'dragend'),
-            dragover: function(event){ 
+            dragover: function(event){
                 event.preventDefault();
                 self.fireEvent(event.type, event);
             },
@@ -98,7 +98,7 @@ Form.MultipleFile = new Class({
                 activateDrop(event, false);
             }
             });
-/*        
+/*
             input.addEvents({
             dragenter: function(e){ activateDrop(true); console.log(e.type); self.fireEvent('dragenter'); },
             dragleave: self.fireEvent.bind(self, 'dragleave'),
@@ -121,10 +121,10 @@ Form.MultipleFile = new Class({
     },
 
     add: function(file){
-    
+
         this._files.push(file);
-        
-        var newItem = this.list.getFirst().clone(true,true);          
+
+        var newItem = this.list.getFirst().clone(true,true);
         newItem.getElement('input').destroy();
         newItem.getElement('label').set('html', file.name + "<b>"+file.size/1024+" Kb</b>" );
         newItem.getElement('.delete').removeClass('hidden').store('file',file);
@@ -148,7 +148,7 @@ Form.MultipleFile = new Class({
     },
 
     getFiles: function(){
-        return this._files;        
+        return this._files;
     }
 
 });