jspwiki-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From brus...@apache.org
Subject svn commit: r809270 [1/2] - in /incubator/jspwiki/trunk: ChangeLog src/WebContent/scripts/jspwiki-common.js src/WebContent/templates/default/jspwiki.css src/java/org/apache/wiki/Release.java
Date Sun, 30 Aug 2009 08:34:15 GMT
Author: brushed
Date: Sun Aug 30 08:34:14 2009
New Revision: 809270

URL: http://svn.apache.org/viewvc?rev=809270&view=rev
Log:
v3.0.0-svn-149:
       * JSPWIKI-577: Fixed the 'jumping' behavior of clicking this wide tabs.
       * Open/Close of collapsible boxes is now only possible by clicking the +/- icon.
       * Implemented the standard css overflow treatment of the 'diff' body.

Modified:
    incubator/jspwiki/trunk/ChangeLog
    incubator/jspwiki/trunk/src/WebContent/scripts/jspwiki-common.js
    incubator/jspwiki/trunk/src/WebContent/templates/default/jspwiki.css
    incubator/jspwiki/trunk/src/java/org/apache/wiki/Release.java

Modified: incubator/jspwiki/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/ChangeLog?rev=809270&r1=809269&r2=809270&view=diff
==============================================================================
--- incubator/jspwiki/trunk/ChangeLog (original)
+++ incubator/jspwiki/trunk/ChangeLog Sun Aug 30 08:34:14 2009
@@ -1,3 +1,21 @@
+2009-08-30 Dirk Frederickx <brushed@apache.org>
+
+        * 3.0.0-svn-149 - align with 2.8.3-svn-16
+                
+        * JSPWIKI-577: tabbed sections with many tabs with long names will float the 
+        tabs to a next line. Fixed the 'jumping' behavior of clicking this wide tabs,
+        which was caused by a superfluous bottom-border css style.
+
+        * Open/Close of collapsible boxes is now only possible by clicking the +/- icon.
+        Any clicks on the header-bar will not change the status of the 
+        collapsible box anymore. E.G. in the Info tab, when looking at page 
+        differences between 2 versions, you can now click the version drop-downs
+        without changing the status of the collapsible box.
+
+        * Implemented the standard css overflow treatment of the 'diff' body. Horizontal 
+        scroll-bars will only be shown when looking at wide content.
+        This is the same overflow treatment as the page content.
+
 2009-08-25 Dirk Frederickx <brushed@apache.org>
 
         * 3.0.0-svn-148

Modified: incubator/jspwiki/trunk/src/WebContent/scripts/jspwiki-common.js
URL: http://svn.apache.org/viewvc/incubator/jspwiki/trunk/src/WebContent/scripts/jspwiki-common.js?rev=809270&r1=809269&r2=809270&view=diff
==============================================================================
--- incubator/jspwiki/trunk/src/WebContent/scripts/jspwiki-common.js (original)
+++ incubator/jspwiki/trunk/src/WebContent/scripts/jspwiki-common.js Sun Aug 30 08:34:14 2009
@@ -1,4 +1,4 @@
-/*! 
+/*!
     JSPWiki - a JSP-based WikiWiki clone.
 
     Licensed to the Apache Software Foundation (ASF) under one
@@ -16,7 +16,7 @@
     "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.  
+    under the License.
 */
 
 /*
@@ -35,10 +35,10 @@
 	*	Effects(ex. Scroll), Drag(Base), Remote, Plugins(Hash.Cookie, Tips, Accordion)
 
 Core JS Routines:
-	*	[Wiki] object (page parms, UserPrefs and setting focus) 
+	*	[Wiki] object (page parms, UserPrefs and setting focus)
 	*	[WikiSlimbox]
 	*	[SearchBox]: remember 10 most recent search topics
-	*	[HighlightWords] 
+	*	[HighlightWords]
 
 Core Wiki plugins, implementing JSPWiki Dynamic Styles:
 	*	Wiki.registerPlugin( <js-plugin: function(dom-element, page-name){...} >)
@@ -47,7 +47,7 @@
 	*	[WikiSlimbox] (attachment viewer)
 	*	[TabbedSection] including all accordion variants
 	*	[Colors], [GraphBar]
-	*	[Collapsible] list and box 
+	*	[Collapsible] list and box
 	*	[TableAdds] with %%sortable, %%tablefilter (excel like column filters) and %%zebra-table
 	* 	[Popup] DOM based popup, replacing alert(), prompt(), confirm()
 
@@ -69,7 +69,7 @@
 	/*
 	Function: deCamelize
 		Convert camelCase string to space-separated set of words.
-	
+
 	Example:
 	> "CamelCase".deCamelize(); /returns "Camel Case"
 	*/
@@ -78,9 +78,9 @@
 	},
 
 	/*
-	Function: trunc 
+	Function: trunc
 		Truncate a string to a maximum length
-	
+
 	Arguments:
 		size - maximum length of the string
 		elips - (optional) the elips indicates when the string was truncacted (defaults to '...')
@@ -90,7 +90,7 @@
 	*/
 	trunc: function(size, elips){
 
-		return (this.length<size) ? this : this.slice(0, size) + (elips||'...');
+		return this.slice(0,size) + ((this.length<size) ? '' : (elips||'...'));
 
 	},
 
@@ -100,7 +100,7 @@
 
 	Examples:
 	> var myString = "<script>alert('Hello')</script>Hello, World.";
-	> myString.stripScripts(); //Returns "Hello, World."	
+	> myString.stripScripts(); //Returns "Hello, World."
 	*/
 	stripScripts: function(){
 		return this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, '');
@@ -144,7 +144,7 @@
 	Resulting HTML
 	>	<div id="mySecondElement">
     >		<div id="myFirstElement"></div>
-	>	</div>	
+	>	</div>
 	*/
 	wraps: function(el){
 		while( el.firstChild ) this.appendChild( el.firstChild );
@@ -179,7 +179,7 @@
 		(element) - This Element
 
 	Examples:
-	>	$('thisElement').hide(); 
+	>	$('thisElement').hide();
 	*/
  	hide: function() {
 		return this.setStyle('display','none');
@@ -193,7 +193,7 @@
 		(element) - This Element
 
 	Examples:
-	>	$('thisElement').show(); 
+	>	$('thisElement').show();
 	*/
 	show: function() {
 		return this.setStyle('display','');
@@ -207,12 +207,12 @@
 		(element) - This Element
 
 	Examples:
-	>	$('thisElement').toggle(); 
+	>	$('thisElement').toggle();
 	*/
 	toggle: function() {
-		return this.visible() ? this.hide() : this.show();  
+		return this.visible() ? this.hide() : this.show();
 	},
-	
+
 	/*
 	Function: addHover
 		Shortcut function to add 'hover' css class to an element.
@@ -225,7 +225,7 @@
 		(element) - This Element
 
 	Examples:
-	>	$('thisElement').addHover(); 
+	>	$('thisElement').addHover();
 	*/
 	addHover: function(clazz){
 		if(!clazz) clazz = 'hover';
@@ -234,7 +234,7 @@
 			'mouseleave': function(){ this.removeClass(clazz) }
 		});
 	},
-	
+
 	/*
 	Function: getDefaultValue
 		Returns the default value of a form element.
@@ -244,7 +244,7 @@
 		(element) - This Element
 
 	Examples:
-	> $('thisElement').getDefaultValue(); 
+	> $('thisElement').getDefaultValue();
 	*/
 	getDefaultValue: function(){
 		switch(this.getTag()){
@@ -265,8 +265,8 @@
 		Returns the real offsets of the element.
 
 	Arguments:
-		overflown - optional, an array of nested scrolling containers for 
-		  scroll offset calculation, use this if your element is inside 
+		overflown - optional, an array of nested scrolling containers for
+		  scroll offset calculation, use this if your element is inside
 		  any element containing scrollbars
 
 	Example:
@@ -300,7 +300,7 @@
 /*
 Class: Observer
 	Class to observe a dom element for changes.
-	
+
 Example:
 >	$(formInput).observe(function(){
 >		alert('my value changed to '+this.getValue() );
@@ -349,16 +349,16 @@
 });
 
 
-/* 
-Global: LocalizedString 
+/*
+Global: LocalizedString
 	The __LocalizedStrings__ object is the store of all {{name:value}} pairs
-	with the localisation values. 
+	with the localisation values.
 	The name of each entry starts with the prefix {{javascript}}.
 	The value of each entry may contain parameters like this: {{ {0},{1},... }}
-	
+
 Examples:
 	(start code)
-	LocalizedStrings = { 
+	LocalizedStrings = {
 		"javascript.some.resource.key":"localised resource key {0}" ,
 		"javascript.moreInfo":"More",
 		"javascript.imageInfo":"Image {0} of {1}"
@@ -380,12 +380,12 @@
 */
 String.extend({
 	localize: function(){
-		var s = LocalizedStrings["javascript."+this], 
+		var s = LocalizedStrings["javascript."+this],
 			args = arguments;
 
 		if(!s) return("???" + this + "???");
 
-		return s.replace(/\{(\d)\}/g, function(m){ 
+		return s.replace(/\{(\d)\}/g, function(m){
 			return args[m.charAt(1)] || "???"+m.charAt(1)+"???";
 		});
 	}
@@ -401,27 +401,27 @@
 	/*
 	Function: initialize
 		Initialize main Wiki properties.
-	
+
 	It reads all the "meta" dom elements, prefixed with "wiki",
-	such as 
+	such as
 	* wikiContext : jspwiki requestcontext variable (view, edit, info, ...)
-	* wikiBaseUrl 
+	* wikiBaseUrl
 	* wikiPageUrl: page url template with dummy pagename "%23%24%25"
 	* wikiEditUrl : edit page url
 	* wikiJsonUrl : JSON-RPC url
 	* wikiPageName : pagename without blanks
-	* wikiUserName 
+	* wikiUserName
 	* wikiTemplateUrl : path of the jsp template
 	* wikiApplicationName
 
 	It parses the {{JSPWikiUserPrefs}} cookie.
-	
+
 	All registered js plugins are invoked for both the main page and
 	the favorites block.
-	
-	When the 'referrer' url (previous page) contains a "section=" parameter, 
+
+	When the 'referrer' url (previous page) contains a "section=" parameter,
 	the wiki page will be scrolled to the right section.
-	
+
 	*/
 	initialize: function(){
 
@@ -436,19 +436,19 @@
 			if( n.indexOf('wiki') == 0 ) this[n.substr(4)] = el.getProperty('content');
 		}, self);
 
-		self.BasePath = (self.BaseUrl) ? 
+		self.BasePath = (self.BaseUrl) ?
 			self.BaseUrl.slice(self.BaseUrl.indexOf(host)+host.length,-1) : '';
 
 		// if JSPWiki is installed in the root, then we have to make sure that
-		// the cookie-cutter works properly here.		
+		// the cookie-cutter works properly here.
 		if(self.BasePath == '') self.BasePath = '/';
-		
+
 		self.prefs = new Hash.Cookie('JSPWikiUserPrefs', {path:Wiki.BasePath, duration:20});
-		
+
 		self.allowEdit = !!$E('a.edit'); //deduct permission level
 		self.url = null;
 		self.parseHash.periodical(500);
-		
+
 		/* reusable dialog object for alert, prompt, confirm */
 		//FIXME: lazy creation ???
 		self.dialog = new Dialog({
@@ -463,7 +463,7 @@
 
 		self.renderPage( $('page'), Wiki.PageName);
 		self.renderPage( $('favorites'), "Favorites");
-		
+
 		//self.addCollapsableFavs();
 		self.splitbar();
 
@@ -484,22 +484,22 @@
 
 	/*
 	Function: getSections
-		Returns the list of all section headers, excluding the header of the 
+		Returns the list of all section headers, excluding the header of the
 		Table Of Contents.
 	*/
 	getSections: function(){
-		return $$('#pagecontent *[id^=section]').filter( 
+		return $$('#pagecontent *[id^=section]').filter(
 			function(item){ return(item.id != 'section-TOC') }
 		);
 	},
 
-	/* 
+	/*
 	Function: alert
 		Show the alert popup. Any html fragment can be displayed.
 
 	Arguments:
 		msg - html text fragment
-		
+
 	Example:
 	> Wiki.alert( "alert message");
 	*/
@@ -515,7 +515,7 @@
 	/*
 	Function: confirm
 		Replaces the standard confirm dialog, supporting any html fragment.
-		If the user clicks "OK", the box returns true. 
+		If the user clicks "OK", the box returns true.
 		If the user clicks "Cancel", the box returns false.
 		The return value (true/false) is handled via the callback function.
 
@@ -527,16 +527,16 @@
 
 		this.dialog
 			.setBody( new Element('p').setHTML(msg) )
-			.setButtons({ 
+			.setButtons({
 				Ok:function(){ callback(true); },
 				Cancel:function(){ callback(false); }
 			})
 			.show();
 	},
 
-	/* 
+	/*
 	Function: prompt
-		Show the prompt prompt, with standard 'Ok' and 'Cancel' buttons. 
+		Show the prompt prompt, with standard 'Ok' and 'Cancel' buttons.
 		Replaces the standard prompt handling, supporting any html fragment.
 		The return value is handled via the callback function.
 
@@ -546,22 +546,22 @@
 		callback - (function) invoke when pressing the Ok button
 
 	Example:
-		> Wiki.prompt("sometext","defaultvalue", callback-function(result) );		
+		> Wiki.prompt("sometext","defaultvalue", callback-function(result) );
 	*/
 	prompt: function(msg, defaultreply, callback){
 		//return callback( prompt( msg, defaultreply ) ); //standard js
 
 		var input;
-			
+
 		this.dialog.setBody([
 				new Element('p').setHTML(msg),
-				new Element('form').adopt( 
-					input = new Element('input',{ 
-						name:'prompt', 
-						type:'text', 
-						value: defaultreply, 
-						size: 24 
-					}) 
+				new Element('form').adopt(
+					input = new Element('input',{
+						name:'prompt',
+						type:'text',
+						value: defaultreply,
+						size: 24
+					})
 				)
 			])
 			.setButtons({
@@ -574,7 +574,7 @@
 
 	/*
 	Function: registerPlugin
-		Register a jspwiki javascript plugin.	
+		Register a jspwiki javascript plugin.
 	*/
 	registerPlugin: function(fn){
 		if(!this.plugins) this.plugins = [];
@@ -584,9 +584,9 @@
 	/*
 	Function: renderPage
 		Invoke all registered wiki js plugins.
-	
+
 	Arguments:
-		page - dom element 
+		page - dom element
 		name - wiki page of the page (pagename, or 'Favorites)
 	*/
 	renderPage: function(page, name){
@@ -613,17 +613,17 @@
 
 	/*
 	Property: toUrl
-		Turn a wiki pagename into a full wiki-url 
+		Turn a wiki pagename into a full wiki-url
 	*/
 	toUrl: function(pagename){
 
 		return this.PageUrl.replace(/%23%24%25/, pagename);
 
-	},	
+	},
 
 	/*
 	Property: toPageName
-		Parse a wiki-url and return the corresponding wiki pagename 
+		Parse a wiki-url and return the corresponding wiki pagename
 	*/
 	toPageName: function(url){
 
@@ -636,8 +636,8 @@
 	/*
 	Property: cleanPageName
 		Remove all not-allowed chars from a *candidate* pagename.
-		Trim repeated whitespace, allow letters, digits and 
-		following punctuation chars: ()&+,-=._$ 
+		Trim repeated whitespace, allow letters, digits and
+		following punctuation chars: ()&+,-=._$
 		Ref com.ecyrd.jspwiki.parser.MarkupParser.cleanPageName()
 	*/
 	cleanPageName: function(p){
@@ -649,10 +649,10 @@
 
 	/*
 	Function: makeMenuFx
-		Make hover menu with fade effect. 
+		Make hover menu with fade effect.
 	*/
 	makeMenuFx: function(btn, menu){
-		btn = $(btn); 
+		btn = $(btn);
 		menu = $(menu);
 		if(!btn || !menu) return;
 
@@ -665,7 +665,7 @@
 			}
 		});
 	},
-	
+
 	/*
 	Function: locatemenu
 		TODO
@@ -689,8 +689,8 @@
 
 	/*
 	Function: parseHash
-		TODO: periodic screening of the #hash to ensure all screen sections are displayed properly 
-	
+		TODO: periodic screening of the #hash to ensure all screen sections are displayed properly
+
 	FIXME:
 		add handling of BACK button for tabs ??
 	*/
@@ -698,12 +698,12 @@
 
 		if(this.url && this.url == location.href ) return;
 		this.url = location.href;
-		var h = location.hash; 
+		var h = location.hash;
 		if( !h || h=='' ) return;
 		h = $( h.slice(1) );
 
 		while( $type( h ) == 'element' ){
-		
+
 			if( h.hasClass('hidetab') ){
 
 				TabbedSection.click.apply($('menu-' + h.id));
@@ -712,7 +712,7 @@
 
 				/* accordion -- need to find accordion toggle object */
 				h.fireEvent('onShow');
-				
+
 			} else if( h.hasClass('collapsebody') ){
 
 				/* collapsible box -- need to find the toggle button */
@@ -721,7 +721,7 @@
 
 				var bullet = h.getFirst();
 				if(bullet) bullet.fireEvent('click');
-				
+
 			} else if( !h.visible() ){
 				//alert('not visible'+el.id);
 				//fixme need to find the correct toggler
@@ -732,7 +732,7 @@
 
 		location = location.href; /* now jump to the #hash */
 	},
-	
+
 	/*
 	Function: SubmitOnce
 		Disable all form buttons to avoid double submits.
@@ -745,7 +745,7 @@
 	submitOnce: function(form){
 
 		window.onbeforeunload = null; /* regular exit of this page -- see jspwiki-edit.js */
-		(function(){ 
+		(function(){
 			$A(form.elements).each(function(e){
 				if( (/submit|button/i).test(e.type)) e.disabled = true;
 			});
@@ -758,7 +758,7 @@
 	Function: submitUpload
 		Support for the upload progressbar.
 		Attached to the attachment upload submit form.
-		
+
 	Returns:
 		Returns via the submitOnce() function.
 	*/
@@ -766,10 +766,10 @@
 
 		var self = this,
 			bar = $('progressbar').setStyle('visibility','visible');
-			
+
 		self.progressbar = self.jsonrpc.periodical(
-			1000, 
-			self, 
+			1000,
+			self,
 			["progressTracker.getProgress",[progress],function(result){
 				result = result.stripScripts(); //xss vulnerability
 				if(!result.code) bar.getFirst().setStyle('width',result+'%').setHTML(result+'%');
@@ -780,19 +780,19 @@
 
 	/*
 	Property: splitbar
-		Add a toggle bar next to the main page content block, to 
+		Add a toggle bar next to the main page content block, to
 		show/hide the favorites block with a click of the mouse.
 		The open/close status is saved in the Wiki.prefs cookie.
 		When the user hovers the mouse over the toggle bar, an arrow
 		image is shown to indicate the collapsable effect.
 
-	Note: 
+	Note:
 		The toggle bar has css-id 'collapseFavs'.
 		The toggle bar gets a .hover class when the mouse hovers over it.
 		The mouse-pointer image has css-id 'collapseFavsPointer'.
 		The DOM body gets a .fav-slide class when the favorites are collapsed (hidden)
-		
-		
+
+
 	DOM structure:
 	(start code)
 	<div id='content'>
@@ -825,7 +825,7 @@
 		// so the body class will not be set yet.
 		// Should better move server side, for faster rendering. wf-stripes
 		body.addClass( Wiki.prefs.get( pref )||'' );
-					
+
 		new Element('div',{
 			'class':splitbar,
 			'events':{
@@ -839,21 +839,21 @@
 			}
 		}).injectTop( $('page') );
 
-	},	
+	},
 
 	addCollapsableFavs: function(){
 
 		var body = $('wikibody'),
 			$pref = 'fav-slide',
 			pref = Wiki.prefs.get('ToggleFav'),
-			tabs = $E('#page .tabs'); 
-			
+			tabs = $E('#page .tabs');
+
 		if( !tabs ) return;
-		
-		// The cookie is not saved to the server's Preferences automatically, 
+
+		// The cookie is not saved to the server's Preferences automatically,
 		// so the body class will not be set yet.
 		// Should better move server side, for faster rendering. wf-stripes
-		(pref==$pref) ? body.addClass($pref) : body.removeClass($pref);		
+		(pref==$pref) ? body.addClass($pref) : body.removeClass($pref);
 
 		/* Be careful.
 		   The .tabs block can not be made relative, cause then the .tabmenu doesn't
@@ -862,20 +862,20 @@
 		   TODO: needs probably another IE hack ;-)
 		 */
 
-		tabs = new Element('div', { 
-			'styles': { 
-				'position':'relative', 
-				'padding': tabs.getStyle('padding') // take over padding from original .tabs 
-			} 
-		}).wraps(tabs.setStyle('padding','0'));			
+		tabs = new Element('div', {
+			'styles': {
+				'position':'relative',
+				'padding': tabs.getStyle('padding') // take over padding from original .tabs
+			}
+		}).wraps(tabs.setStyle('padding','0'));
 
 		var pointer = new Element('div', {'id':'collapseFavsPointer'}).hide().inject(body),
 			movePointer = function(e){
 				this.addClass('hover');
 				pointer.setStyles({ left:this.getPosition().x, top: (e.pageY || e.clientY) }).show();
 			};
-					
-		new Element('div', { 
+
+		new Element('div', {
 			'id':'collapseFavs',
 			'events': {
 				'click': function(){
@@ -884,7 +884,7 @@
 				},
 				'mouseenter': movePointer,
 				'mousemove': movePointer,
-				'mouseleave': function(){ 
+				'mouseleave': function(){
 					this.removeClass('hover');
 					pointer.hide();
 				}
@@ -905,13 +905,13 @@
 		var url = this.EditUrl;
 		url = url + (url.contains('?') ? '&' : '?') + 'section=';
 
-		var aa = new Element('a',{'class':'editsection'}).setHTML('quick.edit'.localize()), 
+		var aa = new Element('a',{'class':'editsection'}).setHTML('quick.edit'.localize()),
 			i = 0;
 
 		this.getSections().each( function(el){
 			el.adopt(aa.set({'href':url + i++ }).clone());
 		});
-		
+
 	},
 
 	/*
@@ -920,7 +920,7 @@
 		FIXME: to be refactored based on Stripes approach to AJAX.
 
 	Arguments:
-	
+
 	Options:
 		action - stripes event name
 		params - DOM-element or js-object. Will be converted to a query-string
@@ -935,22 +935,22 @@
 				alert('ajax - done');
 			}
 		});
-		(end)	
+		(end)
 	*/
 	ajax: function(url, options){
 
-		//FIXME: under contstruction	
-		var params = options.action+'=&'+options.params.toQueryString();		
+		//FIXME: under contstruction
+		var params = options.action+'=&'+options.params.toQueryString();
 
   		new Ajax( url, {
 			postBody: params,
 			method: 'post',
 			update: options.update,
-			onComplete: function( result ){ 
+			onComplete: function( result ){
 				options.onComplete( result );
 			}
 		}).request();
-	
+
 	},
 
 	/*
@@ -964,7 +964,7 @@
 
 	Supported rpc calls:
 		- {{search.findPages}} gets the list of pagenames with partial match
-		- {{progressTracker.getProgress}}  
+		- {{progressTracker.getProgress}}
 		- {{search.getSuggestions}} gets the list of pagenames with partial match
 
 	Example:
@@ -976,7 +976,7 @@
 		//stripes approach
 		Wiki.jsonrpc('Search.jsp', {
 			action: 'findPages',
-			params: js-object, 
+			params: js-object,
 			onComplete: function(result){
 			...json result object...
 		});
@@ -990,12 +990,12 @@
 
 			new Ajax(this.JsonUrl, {
 				postBody: Json.toString({
-					'id':this.$jsonid++, 
-					'method':method, 
+					'id':this.$jsonid++,
+					'method':method,
 					'params':params
-				}), 
-				method: 'post', 
-				onComplete: function(result){ 
+				}),
+				method: 'post',
+				onComplete: function(result){
 					var r = Json.evaluate(result,true);
 					fn(r.result || r.error || null);
 					/*if( r ){
@@ -1006,7 +1006,7 @@
 			}).request();
 
 		}
-	}	
+	}
 
 }
 
@@ -1016,7 +1016,7 @@
 Plugin: WikiSlimbox
 
 Credits:
-	Inspired by Slimbox by Christophe Bleys. (see http://www.digitalia.be/software/slimbox) 
+	Inspired by Slimbox by Christophe Bleys. (see http://www.digitalia.be/software/slimbox)
 
 Example:
 	> %%slimbox [...] %%
@@ -1026,13 +1026,13 @@
 Wiki.registerPlugin( function(page,name){
 	var i = 0,
 		lnk = new Element('a',{'class':'slimbox'}).setHTML('&raquo;');
-			
+
 	$ES('*[class^=slimbox]',page).each(function(slim){
 		var group = 'lightbox'+ i++,
 			parm = slim.className.split('-')[1] || 'img ajax',
 			filter = [];
-		if(parm.test('img')) filter.extend(['img.inline', 'a.attachment']); 
-		if(parm.test('ajax')) filter.extend(['a.wikipage', 'a.external']); 
+		if(parm.test('img')) filter.extend(['img.inline', 'a.attachment']);
+		if(parm.test('ajax')) filter.extend(['a.wikipage', 'a.external']);
 
 		$ES(filter.join(','),slim).each(function(el){
 			var href = el.src||el.href,
@@ -1041,7 +1041,7 @@
 			if((rel=='img') && !href.test('(.bmp|.gif|.png|.jpg|.jpeg)(\\?.*)?$','i')) return;
 
 			lnk.clone().setProperties({
-				'href':href, 
+				'href':href,
 				'rel':group+' '+rel,
 				'title':el.alt||el.getText()
 			}).injectAfter(el);//.injectBefore(el);
@@ -1072,7 +1072,7 @@
 	- spacebar, down arrow, enter : next image
 	- up arrow : prev image
 	- allow the same picture occuring several times
-	- add support for external page links  => slimbox_ex 
+	- add support for external page links  => slimbox_ex
 */
 var Lightbox = {
 
@@ -1123,7 +1123,7 @@
 		//new Element('a', {'id': 'lbCloseLink', 'href': '#', 'title':'slimbox.close.title'.localize()}).setHTML('slimbox.close'.localize()).inject(this.bottom).onclick = this.overlay.onclick = this.close.bind(this);
 		this.caption = new Element('div', {'id': 'lbCaption'}).inject(this.bottom);
 
-		var info = new Element('div').inject(this.bottom);  
+		var info = new Element('div').inject(this.bottom);
 		this.prevLink = new Element('a', {'id': 'lbPrevLink', 'href': '#', 'styles': {'display': 'none'}}).setHTML("slimbox.previous".localize()).inject(info);
 		this.number = new Element('span', {'id': 'lbNumber'}).inject(info);
 		this.nextLink = this.prevLink.clone().setProperties({'id': 'lbNextLink' }).setHTML("slimbox.next".localize()).inject(info);
@@ -1132,7 +1132,7 @@
 
  		this.error = new Element('div').setProperty('id', 'lbError').setHTML(this.options.errorMessage);
 		new Element('div', {'styles': {'clear': 'both'}}).inject(this.bottom);
-		
+
 		var nextEffect = this.nextEffect.bind(this);
 		this.fx = {
 			overlay: this.overlay.effect('opacity', {duration: 500}).hide(),
@@ -1142,7 +1142,7 @@
 		};
 
 		this.fxs = new Fx.Elements([this.center, this.image], $extend({duration: this.options.resizeDuration, onComplete: nextEffect}, this.options.resizeTransition ? {transition: this.options.resizeTransition} : {}));
-		
+
 		this.preloadPrev = new Image();
 		this.preloadNext = new Image();
 	},
@@ -1191,7 +1191,7 @@
 	keyboardListener: function(event){
 		switch (event.keyCode){
 			case 27: case 88: case 67: this.close(); break;
-			case 37: case 38: case 80: this.previous(); break;	
+			case 37: case 38: case 80: this.previous(); break;
 			case 13: case 32: case 39: case 40: case 78: this.next(); break;
 			default: return;
 		}
@@ -1225,19 +1225,19 @@
 			/**/
 			this.so = this.images[imageNum][0];
 			this.so.setProperties({
-				width: '120px', 
-				height: '120px' 
+				width: '120px',
+				height: '120px'
 			});
 			this.so.inject(this.image);
 			this.nextEffect();
-		} else {			
+		} else {
 			this.iframeId = "lbFrame_"+new Date().getTime();	// Safari would not update iframe content that has static id.
 			this.so = new Element('iframe').setProperties({
-				id: this.iframeId, 
-//				width: this.contentsWidth, 
-//				height: this.contentsHeight, 
-				frameBorder:0, 
-				scrolling:'auto', 
+				id: this.iframeId,
+//				width: this.contentsWidth,
+//				height: this.contentsHeight,
+				frameBorder:0,
+				scrolling:'auto',
 				src:this.images[imageNum][0]
 			}).inject(this.image);
 			this.nextEffect();	//asynchronous loading?
@@ -1250,7 +1250,7 @@
 		this.image.setHTML('').adopt(this.error.clone());
 		this.nextEffect();
 	},
-	
+
 	nextEffect: function(){
 		switch (this.step++){
 		case 1:
@@ -1259,7 +1259,7 @@
 					'href':this.images[this.activeImage][0],
 					'title':"slimbox.directLink".localize()
 				}).setHTML(this.images[this.activeImage][1] || ''));
-				
+
 			var type = (this.images[this.activeImage][2]=='img') ? "slimbox.info" : "slimbox.remoteRequest";
 			this.number.setHTML((this.images.length == 1) ? '' : type.localize(this.activeImage+1, this.images.length));
 			this.image.style.backgroundImage = 'none';
@@ -1274,13 +1274,13 @@
 
 			this.image.style.width = this.bottom.style.width = w+'px';
 			this.image.style.height = /*this.prevLink.style.height = this.nextLink.style.height = */ h+'px';
-			
+
 			if( this.images[this.activeImage][2]=='img') {
 				this.image.style.backgroundImage = 'url('+this.images[this.activeImage][0]+')';
 
 				if (this.activeImage) this.preloadPrev.src = this.images[this.activeImage-1][0];
 				if (this.activeImage != (this.images.length - 1)) this.preloadNext.src = this.images[this.activeImage+1][0];
-			
+
 				this.number.setHTML(this.number.innerHTML+'&nbsp;&nbsp;['+this.preload.width+'&#215;'+this.preload.height+']');
 			} else {
 				this.so.style.width=w+'px';
@@ -1292,7 +1292,7 @@
 			this.fxs.start({
 				'0': { height: [this.image.offsetHeight], width: [this.image.offsetWidth], marginLeft: [-this.image.offsetWidth/2] },
 				'1': { opacity: [1] }
-			});	
+			});
 
 			break;
 		case 2:
@@ -1332,15 +1332,15 @@
 /*
 Class: TabbedSection
 	Creates tabs, based on some css-class information
-	Use in jspwiki: 
-	> %%tabbedSection  
-	> 	%%tab-FirstTab .. %% 
+	Use in jspwiki:
+	> %%tabbedSection
+	> 	%%tab-FirstTab .. %%
 	> /%
 
 	Alternative syntax based on header markup
-	> %%tabbedSection  
-	> 	!# First tab title .. 
-	> 	!# Second tab title .. 
+	> %%tabbedSection
+	> 	!# First tab title ..
+	> 	!# Second tab title ..
 	> /%
 
 
@@ -1367,31 +1367,31 @@
 		// add click handlers to existing tabmenu's, generated by <wiki:tabbedSection>
 		$ES('.tabmenu a',page).each(function(el){
 			if(!el.href) el.addEvent('click', this.click);
-		},this);	
-	
+		},this);
+
 		// convert tabbedSections into tabmenu's with click handlers
 		$ES('.tabbedSection',page).each( function(tt){
 			if(tt.hasClass('tabs')) return;
 			tt.addClass('tabs'); //css styling on tabs
-			
+
 			var menu = new Element('div',{'class':'tabmenu'}).injectBefore(tt);
 
 			/*
 			var menuItems = this.getTabs(tt);
 			for( var m in menuItems ){
 				new Element('a', {
-					//'id':'menu-'+tab.id, 
+					//'id':'menu-'+tab.id,
 					'class':(i==0) ? 'activetab' : '',  //fixme
-					'events':{ 
-						'click': this.click(this,m) 
+					'events':{
+						'click': this.click(this,m)
 					}
-				}).appendText( menuItems[m] ).inject(menu);				
+				}).appendText( menuItems[m] ).inject(menu);
 			}
 			*/
 			tt.getChildren().each(function(tab,i) {
 				//find nested %%tab-XXX
 				var clazz = tab.className;
-				if( !clazz.test('^tab-') ) return; 
+				if( !clazz.test('^tab-') ) return;
 
 				if( !tab.id || (tab.id=="") ) tab.id = clazz; //unique id
 
@@ -1401,7 +1401,7 @@
 
 				var title = clazz.substr(4).deCamelize(); //drop 'tab-' prefix
 				new Element('a', {
-					'id':'menu-'+tab.id, 
+					'id':'menu-'+tab.id,
 					'class':(i==0) ? 'activetab' : '',
 					'events':{ 'click': this.click }
 				}).appendText(title).inject(menu);
@@ -1409,35 +1409,35 @@
 			},this);
 		}, this);
 	},
-	
-	/* 
+
+	/*
 	Function: getTabs
 		Helper function for TabbedSection. Also used by Accordion.
-		It will scan the 
+		It will scan the
 		modifies DOM to ensure each TAB section is conform <div class="tab">...</div>
 		return a set of menu-items : {id:'menu1-title', id:'menu2-title'}
 
 		(1) %%tab-tabName : <div class="tab">...</div>
 		(2) !# tab name: <div class="tab"><h2>tab name</h2> ... </div>
-		
+
 	Arguments:
 		el - DOM content container
-		
+
 	Returns:
 		{id:'menu1 title', id:'menu2 title', ...} or null
 	*/
 	$id: 1000,
 	getTabs : function( tt ){
 		var tabs = [], titles=[];
-		
-		var isTabClass = true, isTabHeads = true;		
-		
-		
+
+		var isTabClass = true, isTabHeads = true;
+
+
 		el.getChildren().each(function(tab) {
-			
+
 			if( !tab.className.test('^tab-') ) return;
 			var clazz = tab.className;
-			if( !clazz.test('^tab-') ) return; 
+			if( !clazz.test('^tab-') ) return;
 
 			if( !tab.id || (tab.id=="") ) tab.id = clazz; //unique id
 
@@ -1447,7 +1447,7 @@
 
 			var title = clazz.substr(4).deCamelize(); //drop 'tab-' prefix
 
-			//FIXME use class to make tabs visible during printing 
+			//FIXME use class to make tabs visible during printing
 			//(i==0) ? tab.removeClass('hidetab'): tab.addClass('hidetab');
 
 			var title = tab.className.substr(4).deCamelize(),
@@ -1456,11 +1456,11 @@
 				toggles.push(t.inject(togglemenu));
 			} else {
 				toggles.push(t.adopt(bullet.clone()).injectBefore(tab));
-			}        
+			}
 			titles.push(title);
 			tabs.push(tab.addClass('tab'));
 		});
-			
+
 		return {'titles':titles,'tabs':tabs};
 
 
@@ -1468,7 +1468,7 @@
 			if(tt.hasClass('tabs')) return;
 
 			el.addClass('tabs'); //css styling on tabs contents
-			
+
 			var tt = this.getTabs(el);
 			var menu = new Element('div',{'class':'tabmenu'}).injectBefore(tt);
 			var toggle = new Element('a',{'events':{ 'click': this.click }});
@@ -1480,7 +1480,7 @@
 			},this);
 
 
-/**accordion*******/		
+/**accordion*******/
 
 			var toggles=[], menu=false;
 
@@ -1489,8 +1489,8 @@
 			else if(tt.hasClass('leftAccordion')){ menu = 'sidemenu left'; }
 			else if(tt.hasClass('rightAccordion')){	menu = 'sidemenu right'; }
 
-			if(menu) menu = new (Element('div'),{'class':menu }).injectBefore(tt);			
-			
+			if(menu) menu = new (Element('div'),{'class':menu }).injectBefore(tt);
+
 			var tt = this.getTabs(el);
 			/*build togglemenu*/
 			tt.titles.each( function(title,i){
@@ -1498,27 +1498,27 @@
 				menu ? t.inject(menu) : t.adopt(bullet.clone()).injectBefore(tt.tabs[i]);
 				toggles.push(t);
 			});
-			new Accordion(toggles, tt.tabs, { /* ... */});		
-		
-	}, 
+			new Accordion(toggles, tt.tabs, { /* ... */});
+
+	},
 
 	click: function(){
 		var menu = $(this).getParent(),
 			tabs = menu.getNext();
-			
+
 		menu.getChildren().removeClass('activetab');
 		this.addClass('activetab');
 
-		//skip possible relative wrapper element 
+		//skip possible relative wrapper element
 		var rel = tabs.getFirst();
 		if(rel.getStyle('position')=='relative') tabs = rel;
 
 		tabs.getChildren().addClass('hidetab');
 
 		//fixme: id needs to be unique , should not be the TAB name
-		tabs.getElementById( this.id.slice(5) ).removeClass('hidetab');		
+		tabs.getElementById( this.id.slice(5) ).removeClass('hidetab');
 	}
-	
+
 }
 Wiki.registerPlugin( TabbedSection );
 //FIXME: convert to class
@@ -1540,18 +1540,18 @@
 
 	onPageLoadQuickSearch : function(){
 		var q = $('query'); if( !q ) return;
-		this.query = q; 
-		q.observe(this.ajaxQuickSearch.bind(this) ); 
+		this.query = q;
+		q.observe(this.ajaxQuickSearch.bind(this) );
 
 		this.hover = $('searchboxMenu').setProperty('visibility','visible')
 			.effect('opacity', {wait:false}).set(0);
-	
+
 		$(q.form).addEvent('submit',this.submit.bind(this))
 			//FIXME .addEvent('blur',function(){ this.hasfocus=false; this.hover.start(0) }.bind(this))
 			//FIXME .addEvent('focus',function(){ this.hasfocus=true; this.hover.start(0.9) }.bind(this))
 			  .addEvent('mouseout',function(){ this.hover.start(0) }.bind(this))
 			  .addEvent('mouseover',function(){ Wiki.locatemenu(this.query, $('searchboxMenu') ); this.hover.start(0.9) }.bind(this));
-		
+
 		/* use advanced search-input on safari - experimental */
 		//if(window.webkit){
 		//	q.setProperties({type:"search",autosave:q.form.action,results:"9",placeholder:q.defaultValue});
@@ -1563,9 +1563,9 @@
 			var ul = new Element('ul',{'id':'recentItems'}).inject($('recentSearches').show());
 			this.recent.each(function(el){
 				// xss vulnerability JSPWIKI-384
-				el = el.stripScripts();				
+				el = el.stripScripts();
 				new Element('a',{
-					'href':'#', 
+					'href':'#',
 					'events': {'click':function(){ q.value = el; q.form.submit(); }}
 					}).setHTML(el).inject( new Element('li').inject(ul) );
 			});
@@ -1575,18 +1575,18 @@
 	onPageLoadFullSearch : function(){
 		var q2 = $("query2"); if( !q2 ) return;
 		this.query2 = q2;
-		
+
 		var changescope = function(){
 			var qq = this.query2.value.replace(/^(?:author:|name:|contents:|attachment:)/,'');
 			this.query2.value = $('scope').getValue() + qq;
 			this.runfullsearch();
 		}.bind(this);
-		
+
 		q2.observe( this.runfullsearch0.bind(this) );
-		
+
 		$('scope').addEvent('change', changescope);
 		$('details').addEvent('click', this.runfullsearch.bind(this));
-		
+
 		if(location.hash){
 			/* hash contains query:pagination(-1=all,0,1,2...) */
 			var s = decodeURIComponent(location.hash.substr(1)).match(/(.*):(-?\d+)$/);
@@ -1606,13 +1606,13 @@
 
 	runfullsearch: function(e){
 		var q2 = this.query2.value;
-		if( !q2 || (q2.trim()=='')) { 
+		if( !q2 || (q2.trim()=='')) {
 			$('searchResult2').empty();
-			return; 
+			return;
 		}
 		$('spin').show();
 
-		var scope = $('scope'), 
+		var scope = $('scope'),
 			match= q2.match(/^(?:author:|name:|contents:|attachment:)/) ||"";
 
 		$each(scope.options, function(option){
@@ -1622,21 +1622,21 @@
 		Wiki.ajax('Search.jsp',{
 			action:'ajaxSearch',
 			params:$('searchform2'),
-			update: 'searchResult2', 
-			onComplete: function() { 
-				$('spin').hide(); 
+			update: 'searchResult2',
+			onComplete: function() {
+				$('spin').hide();
 				//FIXME: stripes generates a whole web-page iso of page fragment with searchresults.
 				var x = $E('#searchResult2',$('searchResult2'));
 				$('searchResult2').replaceWith( x );
-				GraphBar.render($('searchResult2')); 
-				Wiki.prefs.set('PrevQuery', q2); 
-			} 
+				GraphBar.render($('searchResult2'));
+				Wiki.prefs.set('PrevQuery', q2);
+			}
 		});
 		location.hash = '#'+q2+":"+$('start').value;  /* push the query into the url history */
 
 	},
 
-	submit: function(){ 
+	submit: function(){
 		var v = this.query.value.stripScripts(); //xss vulnerability
 		if( v == this.query.defaultValue) this.query.value = '';
 		if( !this.recent ) this.recent=[];
@@ -1647,7 +1647,7 @@
 		}
 	},
 
-	clear: function(){		
+	clear: function(){
 		this.recent = [];
 		Wiki.prefs.remove('RecentSearch');
 		$('recentSearches','recentClear').hide();
@@ -1663,13 +1663,13 @@
 		$('searchSpin').show();
 
 		Wiki.jsonrpc('search.findPages', [qv,20], function(result){
-				$('searchSpin').hide(); 
+				$('searchSpin').hide();
 				if(!result.list) return;
 				var frag = new Element('ul');
-				
+
 				result.list.each(function(el){
-					new Element('li').adopt( 
-						new Element('a',{'href':Wiki.toUrl(el.map.page) }).setHTML(el.map.page), 
+					new Element('li').adopt(
+						new Element('a',{'href':Wiki.toUrl(el.map.page) }).setHTML(el.map.page),
 						new Element('span',{'class':'small'}).setHTML(" ("+el.map.score+")")
 					).inject(frag);
 				});
@@ -1682,33 +1682,33 @@
 	navigate: function(url, promptText, clone, search){
 		var p = Wiki.PageName,
 			defaultResult = (clone) ? p+'sbox.clone.suffix'.localize() : p,
-			s = this.query.value;			
+			s = this.query.value;
 		if(s == this.query.defaultValue) s = '';
 
 		var handleResult = function(s){
 			if(s == '') return;
 			if(!search)	s = Wiki.cleanPageName(s);//remove invalid chars from the pagename
-		
+
 			p=encodeURIComponent(p);
 			s=encodeURIComponent(s);
 			if(clone && (s != p)) s += '&clone=' + p;
 
 			location.href = url.replace('__PAGEHERE__', s );
 		};
-		
+
 		if(s!='') {
-			handleResult(s); 
+			handleResult(s);
 		} else {
 			Wiki.prompt(promptText, defaultResult, handleResult.bind(this));
-		} 
+		}
 	}
 }
 
 
-/* 
+/*
 Class: Color
-	Class for creating and manipulating colors in JavaScript. 
-	Minimal variant of the Color class, inspired by mootools 
+	Class for creating and manipulating colors in JavaScript.
+	Minimal variant of the Color class, inspired by mootools
  
 Syntax:
 	>var myColor = new Color(color[, type]);
@@ -1718,7 +1718,7 @@
 	# type - (string, optional) A string representing the type of the color to create.
 
 Color:
-	There are 2 representations of color: String, RGB. 
+	There are 2 representations of color: String, RGB.
 	For String representation see Element:setStyle for more information.
 
 Examples:
@@ -1787,7 +1787,7 @@
 		white:[255,255,255],
 		yellow:[255,255,0]
 	},
-	
+
 	initialize: function(color, type){
 
 		if(!color) return false;
@@ -1827,18 +1827,18 @@
 			rgb = this.copy(),
 			alpha = (($type(colors.getLast()) == 'number') ? colors.pop() : 50)/100,
 			alphaI = 1-alpha;
-		
+
 		colors.each(function(color){
 			color = new Color(color);
 			for (var i = 0; i < 3; i++) rgb[i] = Math.round((rgb[i] * alphaI) + (color[i] * alpha));
 		});
 		return new Color(rgb, 'rgb');
 	},
-	
+
 	/*
 	Method: invert
 		Inverts the Color.
-	
+
 	Syntax:
 		> var myInvert = myColor.invert();
 
@@ -1890,7 +1890,7 @@
 				isHorizontal = true,// horizontal or vertical orientation
 				parms = g.className.substr(9).split('-'),
 				barName = parms.shift(); //first param is optional barName
-			
+
 			parms.each(function(p){
 				p = p.toLowerCase();
 				if(p == "vertical") { isHorizontal = false; }
@@ -1900,7 +1900,7 @@
 				else if(p.indexOf("max") == 0) { ubound = p.substr(3).toInt(); }
 				else if(p != "") {
 					p = new Color(p,'hex'); if(!p.hex) return;
-					if(!color1) color1 = p; 
+					if(!color1) color1 = p;
 					else if(!color2) color2 = p;
 				}
 			});
@@ -1919,17 +1919,17 @@
 				border = (isHorizontal ? 'borderLeft' : 'borderBottom');
 
 			bars.each(function(b,j){
-				var bar1 = $H().set(border+'Width',barData[j]), 
-					bar2 = $H(), // 2nd bar only valid ico 'progress' 
+				var bar1 = $H().set(border+'Width',barData[j]),
+					bar2 = $H(), // 2nd bar only valid ico 'progress'
 					barEL = new Element('span',{'class':'graphBar'}),
 					pb = b.getParent(); // parent of gBar element
 
 				if(isHorizontal){
 					barEL.setHTML('x');
-					if(isProgress){	
+					if(isProgress){
 						bar2.extend(bar1.obj);
-						bar1.set(border+'Width',ubound-barData[j]).set('marginLeft','-1ex'); 
-					}					
+						bar1.set(border+'Width',ubound-barData[j]).set('marginLeft','-1ex');
+					}
 				} else { // isVertical
 					if(pb.getTag()=='td') { pb = new Element('div').wraps(pb); }
 
@@ -1938,22 +1938,22 @@
 					if( !isProgress ) { b.setStyle('top', (ubound-barData[j])); }
 
 					bar1.extend({'position':'absolute', 'width':vwidth, 'bottom':'0'});
-					if(isProgress){ 
-						bar2.extend(bar1.obj).set(border+'Width', ubound); 
+					if(isProgress){
+						bar2.extend(bar1.obj).set(border+'Width', ubound);
 					}
 				}
 				if(isProgress){
 					if(color1){ bar1.set('borderColor', color1.hex); }
-					if(color2){ 
-						bar2.set('borderColor', color2.hex); 
-					} else { 
+					if(color2){
+						bar2.set('borderColor', color2.hex);
+					} else {
 						bar1.set('borderColor', 'transparent');
 					}
 				} else if(color1){
 					var percent = isGauge ? (barData[j]-lbound)/size : j/(bars.length-1);
 					bar1.set('borderColor', color1.mix(color2, 100 * percent).hex);
 				}
-				
+
 				if(bar2.length > 0){ barEL.clone().setStyles(bar2.obj).injectBefore(b); };
 				if(bar1.length > 0){ barEL.setStyles(bar1.obj).injectBefore(b); };
 
@@ -1967,12 +1967,12 @@
 		Parse bar data types and scale according to lbound and size
 	*/
 	parseBarData: function(nodes, lbound, size){
-		var barData=[], 
-			maxValue=Number.MIN_VALUE, 
+		var barData=[],
+			maxValue=Number.MIN_VALUE,
 			minValue=Number.MAX_VALUE,
 			num=true,
 			ddd=num;
-	
+
 		nodes.each(function(n,i){
 			var v = n.getText();
 			barData.push(v);
@@ -1982,11 +1982,11 @@
 		barData = barData.map(function(b){
 			if( ddd ){ b = new Date(Date.parse(b) ).valueOf(); }
 			else if( num ){ b = b.match(/([+-]?\d+(:?\.\d+)?(:?e[-+]?\d+)?)/)[0].toFloat(); }
-			
+
 			maxValue = Math.max(maxValue, b);
 			minValue = Math.min(minValue, b);
 			return b;
-		});		
+		});
 
 		if(maxValue==minValue) maxValue=minValue+1; /* avoid div by 0 */
 		size = size/(maxValue-minValue);
@@ -1995,7 +1995,7 @@
 		});
 	},
 
-	/* 
+	/*
 	Function: getTableValues
 		Fetch set of gBar values from a table
 		* check first-row to match field-name: return array with col values
@@ -2049,27 +2049,27 @@
 		//var cookie = "";  //activate this line if you want to deactivatie cookie handling
 
 		if(!this.bullet) {
-			this.bullet = new Element('div',{'class':'collapseBullet'}).setHTML('&bull;');		
+			this.bullet = new Element('div',{'class':'collapseBullet'}).setHTML('&bull;');
 		}
 
 		this.pims.push({
 			'name':cookie,
 			'value':'',
-			'initial': (cookie ? Cookie.get(cookie) : "") 
+			'initial': (cookie ? Cookie.get(cookie) : "")
 		});
-		$ES('.collapse', page).each(function(el){ 
+		$ES('.collapse', page).each(function(el){
 			if(!$E('.collapseBullet',el)) this.collapseNode(el); // no nesting
 		}, this);
-		$ES('.collapsebox,.collapsebox-closed', page).each(function(el){ 
-			this.collapseBox(el); 
+		$ES('.collapsebox,.collapsebox-closed', page).each(function(el){
+			this.collapseBox(el);
 		}, this);
 	},
 
 	collapseBox: function(el){
 		if($E('.collapsetitle',el)) return; //been here before
 		var title = el.getFirst(); if( !title ) return;
-		
-		var body = new Element('div', {'class':'collapsebody'}), 
+
+		var body = new Element('div', {'class':'collapsebody'}),
 			bullet  = this.bullet.clone(),
 			isclosed = el.hasClass('collapsebox-closed');
 
@@ -2083,15 +2083,15 @@
 
 	/*
 	Function: collapseNode
-		Modifies the list such that sublists can be hidden/shown by clicking 
-		the listitem bullet. The listitem bullet is a node inserted into the 
+		Modifies the list such that sublists can be hidden/shown by clicking
+		the listitem bullet. The listitem bullet is a node inserted into the
 		DOM tree as the first child of the listitem contained by the sublist.
 	*/
 	collapseNode: function(node){
 		$ES('li',node).each(function(li){
 			var ulol = $E('ul',li) || $E('ol',li);
-			
-			//dont insert bullet when LI is 'empty': no text or no non-ul/ol tags			
+
+			//dont insert bullet when LI is 'empty': no text or no non-ul/ol tags
 			var emptyLI = true;
 			for( var n = li.firstChild; n ; n = n.nextSibling ) {
 				if((n.nodeType == 3 ) && ( n.nodeValue.trim() == "" ) ) continue; //keep searching
@@ -2100,7 +2100,7 @@
 				break;
 			}
 			if( emptyLI ) return;
-			
+
 			new Element('div',{'class':'collapsebody'}).wraps(li);
 			var bullet = this.bullet.clone().injectTop(li);
 			if(ulol) this.newBullet(bullet, ulol, (ulol.getTag()=='ul'));
@@ -2113,18 +2113,18 @@
 		if(!clicktarget) clicktarget = bullet;
 
 		var bodyfx = body.setStyle('overflow','hidden')
-			.effect('height', { 
+			.effect('height', {
 				wait:false,
 				onStart:this.renderBullet.bind(bullet),
-				onComplete:function(){ if(bullet.hasClass('collapseOpen')) body.setStyle('height','auto'); } 
+				onComplete:function(){ if(bullet.hasClass('collapseOpen')) body.setStyle('height','auto'); }
 			});
 
 		bullet.className = (isopen ? 'collapseClose' : 'collapseOpen'); //ready for rendering
-		clicktarget.addEvent('click', this.clickBullet.bind(bullet, [ck, ck.value.length-1, bodyfx]))
+		clicktarget.addEvent('click', this.clickBullet.bindWithEvent(bullet, [ck, ck.value.length-1, bodyfx]))
 			.addHover();
-			  
+
 		bodyfx.fireEvent('onStart');
-		if(!isopen) bodyfx.set(0);	
+		if(!isopen) bodyfx.set(0);
 	},
 
 	renderBullet: function(){
@@ -2135,19 +2135,23 @@
 		}
 	},
 
-	clickBullet: function( ck, bulletidx, bodyfx){
+	clickBullet: function(event, ck, bulletidx, bodyfx){
 		var collapse = this.hasClass('collapseOpen'),
-			bodyHeight = bodyfx.element.scrollHeight; 
+			bodyHeight = bodyfx.element.scrollHeight;
+
+		if(event.target==this){ /* don't handle clicks on nested elements */
 
-		if(collapse) bodyfx.start(bodyHeight, 0); else bodyfx.start(bodyHeight);
-		
-		ck.value = ck.value.substring(0,bulletidx) + (collapse ? 'c' : 'o') + ck.value.substring(bulletidx+1) ;
-		if(ck.name) Cookie.set(ck.name, ck.value, {path:Wiki.BasePath, duration:20});
+			if(collapse) bodyfx.start(bodyHeight, 0); else bodyfx.start(bodyHeight);
+
+			ck.value = ck.value.slice(0,bulletidx) + (collapse ? 'c' : 'o') + ck.value.slice(bulletidx+1);
+			if(ck.name) Cookie.set(ck.name, ck.value, {path:Wiki.BasePath, duration:20});
+
+		}
 	},
 
 	/*
 	Function: parseCookie
-		Parse the initial cookie versus actual document 
+		Parse the initial cookie versus actual document
 	Returns:
 		true if collapse status is open
 	*/
@@ -2177,11 +2181,11 @@
 Plugin: commentbox
 	This wiki-plugin supports the commentbox dynamic style.
 
-Example:  
+Example:
 >  %%commentbox ... /% : floating box to the right
 >  %%commentbox-LegendTitle .... /% : make it a legend box
 
-DOM structure  
+DOM structure
 >	<div class="commentbox"> ... </div>
 >	<fieldset class="commentbox">
 >		<legend>LegendTitle</legend>
@@ -2194,7 +2198,7 @@
 	$ES('*[class^=commentbox]',page).each(function(el){
 		var legend = el.className.split('-')[1];
   		if( legend ){
-  			new Element('fieldset',{'class':'commentbox'}).adopt( 
+  			new Element('fieldset',{'class':'commentbox'}).adopt(
   				new Element('legend').setHTML( legend.deCamelize() )
   			).wraps(el).injectBefore(el);
   			el.remove();
@@ -2235,21 +2239,21 @@
 		if( !self) {
 			this.table = table;
 			this.head = $A(table.rows[0].cells).filter(function(el){
-							return el.getTag()=='th'; 
-						}); 
+							return el.getTag()=='th';
+						});
 			table.TableAdds = self = this;
 		}
 		self.setOptions(options);
 		options = self.options;
 		var head = self.head;
-		
+
 		if(!self.sorted && options.sort){
 			head.each( function(th,i){
 				th.set({
 					'class': 'sort',
 					title: options.title.sort,
-					events: { 
-						'click': self.sort.bind(self,[i]) 
+					events: {
+						'click': self.sort.bind(self,[i])
 					}
 				});
 			});
@@ -2258,12 +2262,12 @@
 
 		if( !self.filters && options.filter){
 			head.each( function(th,i){
-				th.adopt( new Element('select',{ 
+				th.adopt( new Element('select',{
 					'class':'filter',
-					events: { 
+					events: {
 						'click': function(e){ new Event(e).stopPropagation() },
 						'change': self.filter.bind(self,[i])
-					} 
+					}
 				}) );
 			});
 			self.filters = [];
@@ -2275,33 +2279,33 @@
 		}
 		return self;
 	},
-	
+
 	/*
 	Function: sort
 		This is a ''click'' event handler to sort tables by a certain column.
-		Css styling is applied 
+		Css styling is applied
 		to change the appearance of the sortAscending/sortDescending clickable
-		controls inside the table header. 
+		controls inside the table header.
 		The data-type of the column is auto-recognized to avoid extensive
 		parameterisation.
 
-		# Copy the table body rows into a javascript array and guess 
+		# Copy the table body rows into a javascript array and guess
 		  the data-type of the column to be sorted.
 		# Do the actual sort or reverse sort
 		# Apply css format to the header cells.
 		# Put the sorted array back into the DOM tree of the document
 
-		The [guessDataType] and [doSort] are helper functions for data-type 
+		The [guessDataType] and [doSort] are helper functions for data-type
 		conversion and caching.
 
 		Following CSS selectors can be changed if needed ..
 		* clickable column headers, not yet sorted: css class = ''.sort''
-		* column headers, sorted ascending: css class = ''.sortAscending'' 
+		* column headers, sorted ascending: css class = ''.sortAscending''
 		* column headers, sorted descending: css clas = ''.sortDescending''
 
 
 	Credits:
-		The implementation was inspired by the excellent javascript created by 
+		The implementation was inspired by the excellent javascript created by
 		Erik Arvidsson. See http://webfx.eae.net/dhtml/sortabletable/sortabletable.html.
 
 	Arguments:
@@ -2315,10 +2319,10 @@
 
 		this.guessDataType(rows, column);
 
-		th.hasClass('sort') ? this.doSort(rows, column) : rows.reverse(); 
+		th.hasClass('sort') ? this.doSort(rows, column) : rows.reverse();
 
 		// format the header cell
-		var isdesc = th.hasClass('sortDescending'), 
+		var isdesc = th.hasClass('sortDescending'),
 			title = this.options.title;
 
 		new Elements(this.head).addClass('sort').removeClass('sortAscending').removeClass('sortDescending');
@@ -2327,26 +2331,26 @@
 			.addClass( isdesc ? 'sortAscending' : 'sortDescending')
 			.title = isdesc ? title.descending : title.ascending;
 
-		//put sorted rows back into the table		
+		//put sorted rows back into the table
 		var frag = document.createDocumentFragment();
 		rows.each( function(r){ frag.appendChild(r); });
 		this.table.appendChild(frag);
 
-		var zebra = this.zebra; 
+		var zebra = this.zebra;
 		if( zebra ) zebra();
 	},
 
 	/*
 	Function: filter
-		Filter the table based on the filter column and (selected) filter value. 
+		Filter the table based on the filter column and (selected) filter value.
 		This function is also an onChange event handler linked with a 'select' element.
-	
+
 	Arguments
 		column - index of the column to be used as sort key
-		filtervalue - (optional) the value to be filtered, if not present, 
-			take the selected value of the dropdown filter 
+		filtervalue - (optional) the value to be filtered, if not present,
+			take the selected value of the dropdown filter
 	*/
-	filter: function( column, filtervalue ){ 
+	filter: function( column, filtervalue ){
 
 		var rows = this.getRows(),
 			select = this.head[column].getLast(), //get select element
@@ -2360,7 +2364,7 @@
 		if( filters.every( function( filter ,i ){
 
 			if( filter.column != column ) return true;
-			isAll ? filters.splice(i, 1) : filter.value = value;  
+			isAll ? filters.splice(i, 1) : filter.value = value;
 			return false;
 
 		}) ) filters.push( {value:value, column:column} );
@@ -2370,12 +2374,12 @@
 
 		filters.each( function(filter){
 
-			var value = filter.value, 
+			var value = filter.value,
 				column = filter.column;
 
 			this.buildFilter(column, value);
 
-			rows.each( function(r){ 
+			rows.each( function(r){
 				if( value != r.data[column] ) r.style.display = 'none';
 			});
 
@@ -2386,7 +2390,7 @@
 
 	/*
 	Function: zebrafy
-		Add odd/even coloring to the table.		
+		Add odd/even coloring to the table.
 
 	Arguments:
 		color1 - color specified in hex(without #) or as html color name.
@@ -2446,9 +2450,9 @@
 
 	/*
 	Function: buildFilter
-		Build a single column dropdown filter. Only the column values of the 
+		Build a single column dropdown filter. Only the column values of the
 		visible rows will be part of the filter dropdown.
-	
+
 	Arguments:
 		table - table
 		col - column index
@@ -2471,7 +2475,7 @@
 		rows.each( function(r){
 			if( r.style.display !='none' ) rr.push(r);
 		});
-		
+
 		this.doSort(rr, column);
 
 		//build dropdown with all unique column values
@@ -2487,7 +2491,7 @@
 		});
 		select.value = filterValue || dropdown[0].value;
 
-		// disable the dropdown if only one value 
+		// disable the dropdown if only one value
 		select.disabled = (dropdown.length <= 2);
 	},
 
@@ -2536,8 +2540,8 @@
 		});
 
 		//now convert all cells to sortable values according to the datatype
-		rows.each( function( r ){ 
-		
+		rows.each( function( r ){
+
 			var val = r.data[column], z;
 
 			if( kmgt ){
@@ -2545,9 +2549,9 @@
 				val = val.match(/([0-9.,]+)\s*([kmgt])b/) || [0,0,''];
 				z = {m:3, g:6, t:9}[ val[2] ] || 0;
 				val = val[1].replace(/,/g,'').toFloat() * Math.pow(10, z);
-				
+
 			} else if( euro ){
-			
+
 				val = val.replace(/[^0-9.]/g,'').toFloat();
 
 			} else if( ip4 ){
@@ -2558,15 +2562,15 @@
 			} else if( ddd ){
 
 				val = Date.parse( val );
-				
+
 			} else if( num ){
 
 				val = val.match(/([+-]?\d+(:?\.\d+)?(:?e[-+]?\d+)?)/)[0].toFloat();
-				
-			}		
+
+			}
 
 			r.data[column] = val;
-		
+
 		});
 
 	},
@@ -2575,20 +2579,20 @@
 	Function: doSort
 		Helper function to sort an array, previoulsy prepared by
 		[guessDataType]
-	
+
 	Arguments:
 		array - target array to be sorted
 		column - column index to use a sorting key
 	*/
-	doSort: function( array, column){	
+	doSort: function( array, column){
 
-		array.sort( function(a, b){ 
+		array.sort( function(a, b){
 			a = a.data[column];
 			b = b.data[column];
-			return (a<b) ? -1 : (a>b) ? 1 : 0; 
-		}); 
+			return (a<b) ? -1 : (a>b) ? 1 : 0;
+		});
 	}
-	
+
 });
 TableAdds.implement(new Options);
 
@@ -2599,19 +2603,19 @@
 
 Table sorting:
 	All tables inside a JSPWiki {{%%sortable}} style are retrieved and processed.
-	An onclick() handler is added to each column header which points to the 
+	An onclick() handler is added to each column header which points to the
 	heart of the javascript: the [TableAdds.sort] function.
 
 Table filtering:
 	Add excel like filter dropdowns to all tables inside a JSPWiki {{%%filtertable}} style.
 
 
-Odd/Even coloring of tables (zebra style): 
+Odd/Even coloring of tables (zebra style):
 	- odd rows get css class odd (ref. jspwiki.css )
 	> %%zebra-table ... /%
 	- odd rows get css style='background=<color>'
 	> %%zebra-<odd-color> ... /%
-	- odd rows get odd-color, even rows get even-color	
+	- odd rows get odd-color, even rows get even-color
 	> %%zebra-<odd-color>-<even-color> ... /%
 
 */
@@ -2652,7 +2656,7 @@
 
 		$ES('.category a.wikipage',page).each(function(link){
 
-			var page = Wiki.toPageName(link.href); 
+			var page = Wiki.toPageName(link.href);
 			if(!page) return;
 			var wrap = new Element('span').injectBefore(link).adopt(link),
 				popup = new Element('div',{'class':'categoryPopup'}).inject(wrap),
@@ -2663,7 +2667,7 @@
 				.addEvent('click', function(e){
 				new Event(e).stop();  //dont jump to top of page ;-)
 
-				new Ajax( Wiki.TemplateUrl + 'AJAXCategories.jsp', { 
+				new Ajax( Wiki.TemplateUrl + 'AJAXCategories.jsp', {
 					postBody: '&page=' + page,
 					update: popup,
 					onComplete: function(){
@@ -2676,14 +2680,14 @@
 							'left': link.getPosition().x,
 							'top': link.getPosition().y+16
 						});
-						popfx.start(0.9); 
+						popfx.start(0.9);
 
-						$ES('li,div.categoryTitle',popup).addHover();						
+						$ES('li,div.categoryTitle',popup).addHover();
 					}
 				}).request();
 			});
 		});
-	} 
+	}
 }
 Wiki.registerPlugin( Categories );
 
@@ -2706,14 +2710,14 @@
 		var q = Wiki.prefs.get('PrevQuery');
 		Wiki.prefs.set('PrevQuery', '');
 		if( !q && document.referrer.test("(?:\\?|&)(?:q|query)=([^&]*)","g") ) q = RegExp.$1;
-		
+
 		if( q ){
 			var words = decodeURIComponent(q).stripScripts(); //xss vulnerability
 			words = words.replace( /\+/g, " " );
 			words = words.replace( /\s+-\S+/g, "" );
 			words = words.replace( /([\(\[\{\\\^\$\|\)\?\*\.\+])/g, "\\$1" ); //escape metachars
 			words = words.trim().split(/\s+/).join("|");
-			
+
 			this.reMatch = new RegExp( "(" + words + ")" , "gi");
 
 			this.walkDomTree( $("pagecontent") );
@@ -2729,7 +2733,7 @@
 		if( !node ) return;
 
 		for( var nn=null, n = node.firstChild; n ; n = nn ){
-			// prefetch nextSibling cause the tree will be modified 
+			// prefetch nextSibling cause the tree will be modified
 			nn = n. nextSibling;
 			this.walkDomTree(n);
 		}
@@ -2739,7 +2743,7 @@
 		if( node.parentNode.className == "searchword" ) return;
 		var s = node.innerText || node.textContent || '';
 
-		s = s.replace(/</g,'&lt;'); // pre text elements may contain <xml> element 
+		s = s.replace(/</g,'&lt;'); // pre text elements may contain <xml> element
 
 		if( this.reMatch.test( s ) ){
 			var tmp = new Element('span').setHTML(s.replace(this.reMatch,"<span class='searchword'>$1</span>")),
@@ -2782,14 +2786,14 @@
 Example:
 	(start code)
 	<script>
-	var button = $('colorButton');			
+	var button = $('colorButton');
 	var cd = new ColorDialog({
 		relativeTo:button,
 		onChange:function(color){ $('target').setStyle('background',color);}
-	});	
+	});
 	button.addEvent('click', cd.toggle.bind(cd));
 	//button.addEvent('click', function(){cd.toggle()});
-	
+
 	</script>
 	(end code)
 */
@@ -2810,9 +2814,9 @@
 	},
 
 	initialize:function(options){
-	
+
 		this.setOptions(options);
-	
+
 		var caption, body, self = this;
 		options = self.options;
 
@@ -2829,58 +2833,58 @@
 			body = new Element('div',{'class':'body'}),
 			buttons = new Element('div',{'class':'buttons'})
 		);
-		
+
 		self.caption = caption;
 		self.body = body;
 		self.buttons = buttons;
-		
-		if( options.caption ) caption.appendText(options.caption); 
+
+		if( options.caption ) caption.appendText(options.caption);
 		self.setBody( options.body );
 		self.setButtons( options.buttons );
-		
+
 		if( options.draggable ){
-			new Drag.Base(el); 
+			new Drag.Base(el);
 			el.setStyle('cursor','move');
 		}
-		
+
 		if( options.resize ){
 			var resize = new Element('div',{'class':'resize'}).inject(el);
 			body.makeResizable({
-				handle:resize, 
+				handle:resize,
 				limit:options.resize,
 				onDrag: function(){	self.resize(this.value.now.x) }
 			})
-		}		
+		}
 
 		el.injectInside(document.body);
 		self.resetPosition();
 		if( options.showNow ) self.show();
 	},
-	
+
 	/*
 	Function: toElement
 	*/
-	toElement: function(){ 
-		return this.element; 
+	toElement: function(){
+		return this.element;
 	},
 
 	/*
 	Function: show
 		Show the dialog box and fire the 'onShow' event.
 	*/
-	show: function(){ 
-		this.element.setStyle('display',''); 
+	show: function(){
+		this.element.setStyle('display','');
 		this.fireEvent('onShow', [this]);
-		return this; 
+		return this;
 	},
 	/*
 	Function: hide
 		Hide the dialog box and fire the 'onHide' event.
 	*/
 	hide: function(){
-		this.element.setStyle('display','none'); 
+		this.element.setStyle('display','none');
 		this.fireEvent('onHide');
-		return this; 
+		return this;
 	},
 	/*
 	Function: toggle
@@ -2912,27 +2916,27 @@
 			type = $type(content);
 
 		if( type=='string'){
-			body.setHTML(content)		
+			body.setHTML(content)
 		} else if( type=='element'){
 			body.adopt(content.show());
 		};
-		
+
 		return this;
 	},
 	/*
 	Function: setButtons
 		this.buttons.empty();
 		if( buttons ){
-		
+
 		}
 	*/
 	setButtons: function(buttons){
 
 		var self = this,
 			buttonDiv = this.buttons.empty();
-			
+
 		if( buttons ){
-		
+
 			for(var btn in buttons){
 				new Element('a',{
 					'class':'btn',
@@ -2952,7 +2956,7 @@
 	/*
 	Function: setPosition
 		Position the dialog box. (absolute positioning)
-		
+
 	Arguments:
 		relativeTo: (optional) DOM element. Default is the center of the window.
 	*/
@@ -2961,44 +2965,44 @@
 		if( relativeTo ){
 
 			//new Element('span',{'styles':{'position':'relative'}}).injectAfter(relativeTo).adopt(relativeTo,el);
-			
+
 			if( $type(relativeTo) == 'element' ) relativeTo = relativeTo.getCoordinates();
 			var pos = {left:relativeTo.left, top:relativeTo.top + relativeTo.height}
 
 		} else {
 
 			//center dialog box
-			var w = window.getSize(), 
+			var w = window.getSize(),
 				pos = this.element.getCoordinates();
 			pos = {
 				left: w.scroll.x + w.size.x/2 - pos.width/2,
 				top: w.scroll.y + w.size.y/2 - pos.height/2
 			}
 
-		}	
+		}
 
 		this.element.setStyles(pos);
-		//fixme: centering the dialog box does not yet work 
+		//fixme: centering the dialog box does not yet work
 		//alert(Json.toString(pos));
 		//alert(Json.toString(this.element.getCoordinates()) );
 	},
 	/*
 	Function: resize
 		Resize the dialog body and fire the 'resize' event.
-	
+
 	Arguments:
 		bodywidth - width in px of the body
 	*/
 	resize: function( bodywidth ){
 
-		//fixme: this resize only works for square color-boxes 
+		//fixme: this resize only works for square color-boxes
 		this.element.setStyles({ 'height': bodywidth+28, 'width': bodywidth+20 });
 		this.body.setStyles({ 'height': bodywidth, 'width':bodywidth });
 		this.fireEvent('onResize');
 		return this;
 
 	}
-	
+
 });
 Dialog.implement(new Options, new Events); //mootools v1.1
 



Mime
View raw message