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 2013/08/02 20:37:55 UTC
svn commit: r1509803 [1/4] - in /jspwiki/trunk: ./ jspwiki-war/
jspwiki-war/src/main/config/wro/ jspwiki-war/src/main/java/org/apache/wiki/
jspwiki-war/src/main/scripts/ jspwiki-war/src/main/styles/
jspwiki-war/src/main/webapp/scripts/ jspwiki-war/src/...
Author: brushed
Date: Fri Aug 2 18:37:54 2013
New Revision: 1509803
URL: http://svn.apache.org/r1509803
Log:
2.10.0-svn-27
* JSPWIKI-761 : Implementing the WRO4J ( Web Resource Optimizer for Java ) Build-time solution through the wro4j maven plugin.
Added:
jspwiki/trunk/jspwiki-war/src/main/config/wro/
jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.properties
jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.xml
jspwiki/trunk/jspwiki-war/src/main/scripts/
jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-common.js
jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-commonstyles.js
jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-edit.js
jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-prefs.js
jspwiki/trunk/jspwiki-war/src/main/scripts/posteditor.js
jspwiki/trunk/jspwiki-war/src/main/scripts/prettify.js (with props)
jspwiki/trunk/jspwiki-war/src/main/styles/
jspwiki/trunk/jspwiki-war/src/main/styles/jspwiki.css
jspwiki/trunk/jspwiki-war/src/main/styles/jspwiki_print.css
Removed:
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/jspwiki-common.js
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/jspwiki-commonstyles.js
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/jspwiki-edit.js
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/jspwiki-prefs.js
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/posteditor.js
jspwiki/trunk/jspwiki-war/src/main/webapp/scripts/prettify.js
jspwiki/trunk/jspwiki-war/src/main/webapp/templates/default/jspwiki.css
jspwiki/trunk/jspwiki-war/src/main/webapp/templates/default/jspwiki_print.css
Modified:
jspwiki/trunk/ChangeLog
jspwiki/trunk/jspwiki-war/pom.xml
jspwiki/trunk/jspwiki-war/src/main/java/org/apache/wiki/Release.java
jspwiki/trunk/jspwiki-war/src/main/webapp/templates/default/commonheader.jsp
jspwiki/trunk/jspwiki-war/src/main/webapp/templates/default/editors/plain.jsp
jspwiki/trunk/mvn_cheat-sheet.txt
jspwiki/trunk/pom.xml
Modified: jspwiki/trunk/ChangeLog
URL: http://svn.apache.org/viewvc/jspwiki/trunk/ChangeLog?rev=1509803&r1=1509802&r2=1509803&view=diff
==============================================================================
--- jspwiki/trunk/ChangeLog (original)
+++ jspwiki/trunk/ChangeLog Fri Aug 2 18:37:54 2013
@@ -1,3 +1,16 @@
+2013-08-01 Dirk Frederickx (brushed AT apache DOT org)
+
+ * 2.10.0-svn-27
+
+ * JSPWIKI-761 : Implementing the WRO4J ( Web Resource Optimizer for Java ) Build-time solution
+ through the wro4j maven plugin.
+ - replacing YUI-Compressor for JS by UglifyJS (better compression)
+ - introducing the LESS CSS preprocessor supporting advanced css authoring capabilities (variables, mixins, ...)
+ - merging JS and CSS files to reduce the number of resources needed at page-load.
+
+ You can now build with or without minification of the JS and CSS files to ease development
+ by using -Dminimize = true | false. (ref. mvn_cheat-sheet.txt)
+
2013-08-01 Juan Pablo Santos (juanpablo AT apache DOT org)
* 2.10.0-svn-26
Modified: jspwiki/trunk/jspwiki-war/pom.xml
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/pom.xml?rev=1509803&r1=1509802&r2=1509803&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/pom.xml (original)
+++ jspwiki/trunk/jspwiki-war/pom.xml Fri Aug 2 18:37:54 2013
@@ -15,12 +15,12 @@
"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.
-->
<project xmlns = "http://maven.apache.org/POM/4.0.0"
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation = "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
-
+
<parent>
<groupId>org.apache.jspwiki</groupId>
<artifactId>jspwiki-builder</artifactId>
@@ -47,7 +47,7 @@
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-highlighter</artifactId>
</dependency>
-
+
<dependency>
<groupId>org.apache.lucene</groupId>
<artifactId>lucene-analyzers-common</artifactId>
@@ -70,22 +70,22 @@
<groupId>net.sourceforge</groupId>
<artifactId>sandler</artifactId>
</dependency>
-
+
<dependency>
<groupId>opensymphony</groupId>
<artifactId>oscache</artifactId>
</dependency>
-
+
<dependency>
<groupId>oro</groupId>
<artifactId>oro</artifactId>
</dependency>
-
+
<dependency>
<groupId>javax.mail</groupId>
<artifactId>mail</artifactId>
</dependency>
-
+
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
@@ -95,12 +95,12 @@
<groupId>com.metaparadigm</groupId>
<artifactId>json-rpc</artifactId>
</dependency>
-
+
<dependency>
<groupId>org.jvnet.hudson</groupId>
<artifactId>org.suigeneris.jrcs.diff</artifactId>
</dependency>
-
+
<dependency>
<groupId>org.jdom</groupId>
<artifactId>jdom2</artifactId>
@@ -115,60 +115,60 @@
<groupId>javax.servlet</groupId>
<artifactId>jstl</artifactId>
</dependency>
-
+
<dependency>
<groupId>org.freshcookies</groupId>
<artifactId>freshcookies-security</artifactId>
</dependency>
-
+
<dependency>
<groupId>ecs</groupId>
<artifactId>ecs</artifactId>
</dependency>
-
+
<dependency>
<groupId>commons-lang</groupId>
<artifactId>commons-lang</artifactId>
</dependency>
-
+
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
</dependency>
-
+
<dependency>
<groupId>net.sourceforge</groupId>
<artifactId>akismet-java</artifactId>
</dependency>
-
+
<dependency>
<groupId>commons-httpclient</groupId>
<artifactId>commons-httpclient</artifactId>
</dependency>
-
+
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
</dependency>
-
+
<dependency>
<groupId>nekohtml</groupId>
<artifactId>nekohtml</artifactId>
<scope>runtime</scope>
</dependency>
-
+
<dependency>
<groupId>net.sourceforge.stripes</groupId>
<artifactId>stripes</artifactId>
<scope>test</scope>
</dependency>
-
+
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>hsqldb</artifactId>
<scope>test</scope>
</dependency>
-
+
<dependency>
<groupId>org.hsqldb</groupId>
<artifactId>sqltool</artifactId>
@@ -180,7 +180,7 @@
<artifactId>jetty-all</artifactId>
<scope>test</scope>
</dependency>
-
+
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
@@ -194,20 +194,20 @@
<filters>
<filter>src/main/filters/filters.properties</filter>
</filters>
-
+
<testResources>
<testResource>
<directory>src/test/resources</directory>
<filtering>true</filtering>
</testResource>
</testResources>
-
+
<plugins>
<!-- With below plugin can deploy to an embedded Tomcat instance via:
mvn clean install tomcat7:run-war [-Dmaven.test.skip]
...or standalone by adding a <server/> entry "myTomcat":
http://www.jroller.com/gmazza/entry/web_service_tutorial#maventomcat
- and running tomcat7:redeploy instead of run-war in
+ and running tomcat7:redeploy instead of run-war in
string above.
Either way, JSPWiki URL will be
@@ -222,13 +222,13 @@
<path>/${project.build.finalName}</path>
</configuration>
</plugin>
-
+
<!-- Surefire plugin (running unit tests):
http://maven.apache.org/surefire/maven-surefire-plugin/
-
+
Individual tests can be run command line via:
mvn clean test -Dtest=WikiEngineTest,AclImplTest,...
-
+
All tests can be skipped via -Dmaven.test.skip
-->
<plugin>
@@ -244,11 +244,44 @@
</includes>
</configuration>
</plugin>
-
- <!-- Compress certain CSS and JS files using the YUICompressor
- (http://alchim.sourceforge.net/yuicompressor-maven-plugin/)
+
+ <!-- wro4j Web Resource Optimizer for Java (http://http://code.google.com/p/wro4j/)
+ Merge and compress CSS and JS files using the WRO4J.
+ - use UglifyJS for JS compression
+ - use Less as advanced CSS preprocessor
-->
<plugin>
+ <groupId>ro.isdc.wro4j</groupId>
+ <artifactId>wro4j-maven-plugin</artifactId>
+ <executions>
+ <execution>
+ <phase>compile</phase>
+ <goals>
+ <goal>run</goal>
+ <!--<goal>jshint</goal>-->
+ </goals>
+ </execution>
+ </executions>
+ <configuration>
+ <!--
+ <targetGroups>all</targetGroups>
+ <minimize>true</minimize>
+ <cssDestinationFolder>d:/static/css/</cssDestinationFolder>
+ <jsDestinationFolder>d:/static/js/</jsDestinationFolder>
+ <ignoreMissingResources>false</ignoreMissingResources>
+ -->
+ <wroManagerFactory>ro.isdc.wro.maven.plugin.manager.factory.ConfigurableWroManagerFactory</wroManagerFactory>
+ <jsDestinationFolder>${project.build.directory}/generated-sources/wro/scripts</jsDestinationFolder>
+ <cssDestinationFolder>${project.build.directory}/generated-sources/wro/templates/default/</cssDestinationFolder>
+ <contextFolder>${basedir}/src/main/</contextFolder>
+ <wroFile>src/main/config/wro/wro.xml</wroFile>
+ <extraConfigFile>src/main/config/wro/wro.properties</extraConfigFile>
+ </configuration>
+ </plugin>
+
+ <!-- Compress certain CSS and JS files using the YUICompressor
+ (http://alchim.sourceforge.net/yuicompressor-maven-plugin/)
+ <plugin>
<groupId>net.alchim31.maven</groupId>
<artifactId>yuicompressor-maven-plugin</artifactId>
<executions>
@@ -258,16 +291,17 @@
<goal>compress</goal>
</goals>
</execution>
- </executions>
+ </executions>
<configuration>
<excludeResources>true</excludeResources>
<nosuffix>true</nosuffix>
<webappDirectory>${project.build.directory}/generated-sources/yuicompress</webappDirectory>
- <!-- relying on jslint-maven-plugin instead, which allows
- better customization -->
+ *** relying on jslint-maven-plugin instead, which allows
+ better customization ***
<jswarn>false</jswarn>
</configuration>
</plugin>
+ -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
@@ -302,9 +336,9 @@
<allowOneVarStatementPerFunction>false</allowOneVarStatementPerFunction>
</configuration>
</execution>
- </executions>
+ </executions>
</plugin>
-
+
<plugin>
<artifactId>maven-war-plugin</artifactId>
<configuration>
@@ -321,10 +355,14 @@
</includes>
<filtering>true</filtering>
</resource>
- <!-- Output directory configured above with the YUICompressor Maven plugin -->
+ <!-- Output directory configured above with the YUICompressor Maven plugin
<resource>
<directory>${project.build.directory}/generated-sources/yuicompress</directory>
</resource>
+ -->
+ <resource>
+ <directory>${project.build.directory}/generated-sources/wro</directory>
+ </resource>
</webResources>
</configuration>
</plugin>
Added: jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.properties
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.properties?rev=1509803&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.properties (added)
+++ jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.properties Fri Aug 2 18:37:54 2013
@@ -0,0 +1,2 @@
+preProcessors=lessCss,semicolonAppender
+postProcessors=cssMinJawr,uglifyJs
\ No newline at end of file
Added: jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.xml
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.xml?rev=1509803&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.xml (added)
+++ jspwiki/trunk/jspwiki-war/src/main/config/wro/wro.xml Fri Aug 2 18:37:54 2013
@@ -0,0 +1,47 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<groups xmlns="http://www.isdc.ro/wro"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://www.isdc.ro/wro wro.xsd">
+
+ <group name="base" abstract="true">
+ <!--<js>/scripts/mootools.js</js>-->
+ <js>/scripts/jspwiki-common.js</js>
+ <!-- <css>/templates/default/jspwiki.css</css> -->
+ </group>
+
+ <group name="jspwiki-common">
+ <js>/scripts/prettify.js</js>
+ <group-ref>base</group-ref>
+ <js>/scripts/jspwiki-commonstyles.js</js>
+ </group>
+
+ <group name="jspwiki-edit">
+ <!-- <group-ref>base</group-ref> -->
+ <js>/scripts/jspwiki-edit.js</js>
+ <js>/scripts/posteditor.js</js>
+ </group>
+
+ <group name="jspwiki-prefs">
+ <!-- <group-ref>base</group-ref> -->
+ <js>/scripts/jspwiki-prefs.js</js>
+ </group>
+
+ <!-- css styling; FIXME should become part of the regular groups -->
+ <group name="jspwiki">
+ <css>/styles/jspwiki.css</css>
+ </group>
+ <!-- FIXME: should be included in the main jspwiki.css, with a "@media print" -->
+ <group name="jspwiki_print">
+ <css>/styles/jspwiki_print.css</css>
+ </group>
+
+ <!-- FIXME : revise the way skins are handles with wro4j
+ For now, keep the skin css & js uncompressed/unmerged. (small files anyway)
+ <group name="skins">
+ <css>/templates/defaults/skins/**/skin.css</css>
+ <js>/templates/defaults/skins/**/skin.js</js>
+ </group>
+ -->
+
+</groups>
\ No newline at end of file
Modified: jspwiki/trunk/jspwiki-war/src/main/java/org/apache/wiki/Release.java
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/java/org/apache/wiki/Release.java?rev=1509803&r1=1509802&r2=1509803&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/java/org/apache/wiki/Release.java (original)
+++ jspwiki/trunk/jspwiki-war/src/main/java/org/apache/wiki/Release.java Fri Aug 2 18:37:54 2013
@@ -75,7 +75,7 @@ public final class Release
* <p>
* If the build identifier is empty, it is not added.
*/
- public static final String BUILD = "26";
+ public static final String BUILD = "27";
/**
* This is the generic version string you should use
Added: jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-common.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-common.js?rev=1509803&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-common.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-common.js Fri Aug 2 18:37:54 2013
@@ -0,0 +1,1719 @@
+/*
+ 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"); you 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.
+ */
+
+/*
+Javascript routines to support JSPWiki
+Since v.2.6.0
+
+Uses mootools v1.1, with following components:
+* Core, Class, Native, Element(ex. Dimensions), Window,
+* Effects(ex. Scroll), Drag(Base), Remote, Plugins(Hash.Cookie, Tips, Accordion)
+
+Core JS Routine
+* 100 Wiki object (page parms, UserPrefs and setting focus)
+* 140 SearchBox object: remember 10 most recent search topics
+* 290 HighlightWords in the page-content
+
+Core Dynamic Styles
+ Wiki.addPageRender( XYZ )
+ Wiki.renderPage(page-element, page-name)
+
+* 110 WikiSlimbox (attachment viewer): dynamic style
+* 130 TabbedSection object: dynamic style
+* 150 Colors, GraphBar object: dynamic style
+* 200 Collapsible list items: dynamic style
+* 230 Sortable: dynamic style
+* 240 Table-filter (excel like column filters): dynamic style
+* 280 ZebraTable (color odd/even rows): dynmaic style
+
+Complementary Dynamic Styles (see jspwiki-commonstyles.js)
+* 114 Reflection (adds reflection to images): dynamic style
+* 116 WikiCoverflow (based on MooFlow) : dynamic style
+* 118 Google Chart: dynamic style
+* 132 Accordion object: dynamic style
+* 220 RoundedCorners: dynamic style
+* 260 WikiTips: dynamic style
+* 270 WikiColumns: dynamic style
+* 300 Prettify: dynamic style
+
+*/
+
+/* extend mootools */
+String.extend({
+ deCamelize: function(){
+ return this.replace(/([a-z])([A-Z])/g,"$1 $2");
+ },
+ trunc: function(size,elips){
+ if( !elips ) elips="...";
+ return (this.length<size) ? this : this.substring(0,size)+elips;
+ },
+ stripScripts: function(){
+ var text = this.replace(/<script[^>]*>([\s\S]*?)<\/script>/gi, function(){
+ return '';
+ });
+ return text;
+ }
+})
+
+// get text of a dhtml node
+function $getText(el) {
+ return el.innerText || el.textContent || '';
+}
+Element.extend({
+
+ /* wrapper = new Element('div').injectWrapper(node); */
+ wrapChildren: function(el){
+ while( el.firstChild ) this.appendChild( el.firstChild );
+ el.appendChild( this ) ;
+ return this;
+ },
+
+ visible: function() {
+ var el = this;
+ while($type(el)=='element'){
+ if(el.getStyle('visibility') == 'hidden') return false;
+ if(el.getStyle('display') == 'none' ) return false;
+ el = el.getParent();
+ }
+ return true;
+ },
+
+ hide: function() {
+ return this.setStyle('display','none');
+ },
+
+ show: function() {
+ return this.setStyle('display','');
+ },
+
+ toggle: function() {
+ return this.visible() ? this.hide() : this.show();
+ },
+
+ scrollTo: function(x, y){
+ this.scrollLeft = x;
+ this.scrollTop = y;
+ },
+
+ /* dimensions.js */
+ getPosition: function(overflown){
+ overflown = overflown || [];
+ var el = this, left = 0, top = 0;
+ do {
+ left += el.offsetLeft || 0;
+ top += el.offsetTop || 0;
+ el = el.offsetParent;
+ } while (el);
+ overflown.each(function(element){
+ left -= element.scrollLeft || 0;
+ top -= element.scrollTop || 0;
+ });
+ return {'x': left, 'y': top};
+ },
+
+ getDefaultValue: function(){
+ switch(this.getTag()){
+ case 'select':
+ var values = [];
+ $each(this.options, function(option){
+ if (option.defaultSelected) values.push($pick(option.value, option.text));
+ });
+ return (this.multiple) ? values : values[0];
+ case 'input': if (!(this.defaultChecked && ['checkbox', 'radio'].contains(this.type)) && !['hidden', 'text', 'password'].contains(this.type)) break;
+ case 'textarea': return this.defaultValue;
+ }
+ return false;
+ }
+
+});
+
+var Observer = new Class({
+ initialize: function(el, fn, options){
+ this.options = Object.extend({
+ event: 'keyup',
+ delay: 300
+ }, options || {});
+ this.element = $(el);
+ this.callback = fn;
+ this.timeout = null;
+ this.listener = this.fired.bind(this);
+ this.value = this.element.getValue();
+ this.element.setProperty('autocomplete','off').addEvent(this.options.event, this.listener);
+ },
+ fired: function() {
+ if (this.value == this.element.value) return;
+ this.clear();
+ this.value = this.element.value;
+ this.timeout = this.callback.delay(this.options.delay, null, [this.element]);
+ },
+ clear: function() {
+ this.timeout = $clear(this.timeout);
+ },
+ stop: function() {
+ this.element.removeEvent(this.options.event, this.listener);
+ this.clear();
+ }
+});
+
+/* Observable class: observe any form element for changes */
+Element.extend({
+ observe: function(fn, options){
+ return new Observer(this, fn, options);
+ }
+});
+
+
+/* I18N Support
+ * LocalizedStrings takes form { "javascript.some.resource.key":"localised resource key {0}" }
+ * Examples:
+ * "moreInfo".localize();
+ * "imageInfo".localize(2,4); => "Image {0} of {1}" becomes "Image 2 of 4
+ */
+var LocalizedStrings = LocalizedStrings || []; //defensive
+String.extend({
+ localize: function(){
+ var s = LocalizedStrings["javascript."+this],
+ args = arguments;
+
+ if(!s) return("???" + this + "???");
+
+ return s.replace(/\{(\d)\}/g, function(m){
+ return args[m.charAt(1)] || "???"+m.charAt(1)+"???";
+ });
+ }
+});
+
+/* FIXME parse number anywhere inside a string */
+Number.REparsefloat = new RegExp( "([+-]?\\d+(:?\\.\\d+)?(:?e[-+]?\\d+)?)", "i");
+
+/** TABLE stuff **/
+function $T(el) {
+ var t = $(el);
+ return (t && t.tBodies[0]) ? $(t.tBodies[0]) : t;
+};
+
+/* FIXME */
+// find first ancestor element with tagName
+function getAncestorByTagName( node, tagName ) {
+ if( !node) return null;
+ if( node.nodeType == 1 && (node.tagName.toLowerCase() == tagName.toLowerCase())){
+ return node;
+ } else {
+ return getAncestorByTagName( node.parentNode, tagName );
+ }
+}
+
+
+/** 100 Wiki functions **/
+var Wiki = {
+
+ onPageLoad: function(){
+ if(this.prefs) return; //already initialised
+ //read all meta elements starting with wiki
+ $$('meta').each(function(el){
+ var n = el.getProperty('name') || '';
+ if( n.indexOf('wiki') == 0 ) this[n.substr(4)] = el.getProperty('content');
+ },this);
+
+ var h = location.host;
+ this.BasePath = this.BaseUrl.slice(this.BaseUrl.indexOf(h)+h.length,-1);
+
+ // If JSPWiki is installed in the root, then we have to make sure that
+ // the cookie-cutter works properly here.
+
+ if( this.BasePath == '' ) this.BasePath = '/';
+
+ this.prefs = new Hash.Cookie('JSPWikiUserPrefs', {path:Wiki.BasePath, duration:20});
+
+ this.PermissionEdit = !!$$('a.edit')[0]; //deduct permission level
+ this.url = null;
+ this.parseLocationHash.periodical(500);
+
+ this.makeMenuFx('morebutton', 'morepopup');
+ this.addEditLinks();
+
+ var p = $('page'); if(p) this.renderPage(p, Wiki.PageName);
+ var f = $('favorites'); if(f) this.renderPage(f, "Favorites");
+ },
+ /* show popup alert, which allows any html msg to be displayed */
+ alert: function(msg){
+ return alert(msg); //standard js
+
+ },
+ /* show popup prompt, which allows any html msg to be displayed and replied to */
+ prompt: function(msg, defaultreply, callback){
+ return callback( prompt(msg,defaultreply) ); //standard js
+
+ },
+
+ renderPage: function(page, name){
+ this.$pageHandlers.each(function(obj){
+ obj.render(page, name)
+ });
+ },
+ addPageRender: function(fn){
+ if(!this.$pageHandlers) this.$pageHandlers = [];
+ this.$pageHandlers.push(fn);
+ },
+
+ setFocus: function(){
+ /* plain.jsp, login.jsp, prefs/profile, prefs/prefs, find */
+ ['editorarea','j_username','loginname','assertedName','query2'].some(function(el){
+ el = $(el);
+ if(el && el.visible()) { el.focus(); return true; }
+ return false;
+ });
+ },
+
+ getUrl: function(pagename){
+ return this.PageUrl.replace(/%23%24%25/, pagename);
+ },
+
+ /* retrieve pagename from any wikipage url format */
+ getPageName: function(url){
+ var s = this.PageUrl.escapeRegExp().replace(/%23%24%25/, '(.+)'),
+ res = url.match(new RegExp(s));
+ return (res ? res[1] : false);
+ },
+
+ //ref org.apache.wiki.parser.MarkupParser.cleanLink()
+ //trim repeated whitespace
+ //allow letters, digits and punctuation chars: ()&+,-=._$
+ cleanLink: function(p){
+ return p.trim().replace(/\s+/g,' ')
+ .replace(/[^0-9A-Za-z\u00C0-\u1FFF\u2800-\uFFFD()&+,-=._$ ]/g, '');
+ },
+
+ changeOrientation: function(){
+ var fav = $('prefOrientation').getValue();
+ $('wikibody')
+ .removeClass('fav-left').removeClass('fav-right')
+ .addClass(fav);
+ //$('collapseFavs').fireEvent('click').fireEvent('click'); //refresh sliding favorites
+ },
+
+ /* make hover menu with fade effect */
+ makeMenuFx: function(btn, menu){
+ var btn = $(btn), menu = $(menu);
+ if(!btn || !menu) return;
+
+ var popfx = menu.effect('opacity', {wait:false}).set(0);
+ btn.adopt(menu).set({
+ 'href':'#',
+ 'events':{
+ 'mouseout': function(){ popfx.start(0) },
+ 'mouseover': function(){ Wiki.locatemenu(btn,menu); popfx.start(0.9) }
+ }
+ });
+ },
+
+ //FIXME
+ locatemenu: function(base,el){
+ var win = {'x': window.getWidth(), 'y': window.getHeight()},
+ scroll = {'x': window.getScrollLeft(), 'y': window.getScrollTop()},
+ corner = base.getPosition(),
+ offset = {'x': base.offsetWidth-el.offsetWidth, 'y': base.offsetHeight },
+ popup = {'x': el.offsetWidth, 'y': el.offsetHeight},
+ prop = {'x': 'left', 'y': 'top'};
+
+ for (var z in prop){
+ var pos = corner[z] + offset[z]; /*top-left corner of base */
+ if ((pos + popup[z] - scroll[z]) > win[z]) pos = win[z] - popup[z] + scroll[z];
+ el.setStyle(prop[z], pos);
+ };
+ },
+
+ parseLocationHash: function(){
+ if(this.url && this.url == location.href ) return;
+ this.url = location.href;
+ var h = location.hash;
+ if( h=="" ) return;
+ h = h.replace(/^#/,'');
+
+ var el = $(h);
+ while( $type(el) == 'element' ){
+ if( el.hasClass('hidetab') ){
+ TabbedSection.click.apply($('menu-'+el.id));
+ } else if( el.hasClass('tab') ){
+ /* accordion -- need to find accordion toggle object */
+ } else if( el.hasClass('collapsebody') ){
+ /* collapsible box -- need to find the toggle button */
+ } else if(!el.visible() ){
+ //alert('not visible'+el.id);
+ //fixme need to find the correct toggler
+ //el.show(); //eg collapsedBoxes: fixme
+ }
+ el = el.getParent();
+ }
+
+ location = location.href; /* now jump to the #hash */
+ },
+
+ /* SubmitOnce: disable all buttons to avoid double submit */
+ submitOnce: function(form){
+ window.onbeforeunload = null; /* regular exit of this page -- see jspwiki-edit.js */
+ (function(){
+ $A(form.elements).each(function(e){
+ if( (/submit|button/i).test(e.type)) e.disabled = true;
+ });
+ }).delay(10);
+ return true;
+ },
+
+ submitUpload: function(form, progress){
+ $('progressbar').setStyle('visibility','visible');
+ this.progressbar =
+ Wiki.jsonrpc.periodical(1000, this, ["progressTracker.getProgress",[progress],function(result){
+ result = result.stripScripts(); //xss vulnerability
+ if(!result.code) $('progressbar').getFirst().setStyle('width',result+'%').setHTML(result+'%');
+ }]);
+
+ return Wiki.submitOnce(form);
+ },
+
+ addEditLinks: function(){
+ if( $("previewcontent") || !this.PermissionEdit || this.prefs.get('SectionEditing') != 'on') return;
+
+ var aa = new Element('a',{'class':'editsection'}).setHTML('quick.edit'.localize()),
+ i = 0,
+ url = this.EditUrl;
+
+ url = url + (url.contains('?') ? '&' : '?') + 'section=';
+
+ this.getSections().each( function(el){
+ el.adopt(aa.set({'href':url + i++ }).clone());
+ });
+
+ },
+ /*
+ Function: getSections
+ Returns the list of all section headers, excluding the header of the
+ Table Of Contents.
+ */
+ getSections: function(){
+ return $$('#pagecontent *[id^=section]').filter(
+ function(item){ return(item.id != 'section-TOC') }
+ );
+ },
+
+ $jsonid : 10000,
+ jsonrpc: function(method, params, fn) {
+ new Ajax( Wiki.JsonUrl, {
+ postBody: Json.toString({"id":Wiki.$jsonid++, "method":method, "params":params}),
+ method: 'post',
+ onComplete: function(result){
+ var r = Json.evaluate(result,true);
+ if(r){
+ if(r.result){ fn(r.result) }
+ else if(r.error){ fn(r.error) }
+ }
+ }
+ }).request();
+ }
+}
+
+
+/** 110 WikiSlimbox
+ ** Inspired http://www.digitalia.be/software/slimbox by Christophe Bleys
+ ** %%slimbox [...] %%
+ ** %%slimbox-img [some-image.jpg] %%
+ ** %%slimbox-ajax [some-page links] %%
+ **/
+var WikiSlimbox = {
+
+ render: function(page, name){
+ var i = 0,
+ lnk = new Element('a',{'class':'slimbox'}).setHTML('»');
+
+ $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']);
+
+ $ES(filter.join(','),slim).each(function(el){
+ var href = el.src||el.href,
+ rel = (el.className.test('inline|attachment')) ? 'img' : 'ajax';
+
+ if((rel=='img') && !href.test('(.bmp|.gif|.png|.jpg|.jpeg)(\\?.*)?$','i')) return;
+
+ lnk.clone().setProperties({
+ 'href':href,
+ 'rel':group+' '+rel,
+ 'title':el.alt||el.getText()
+ }).injectBefore(el);
+
+ if(el.src) el.replaceWith(new Element('a',{
+ 'class':'attachment',
+ 'href':el.src
+ }).setHTML(el.alt||el.getText()));
+ });
+ });
+ if(i) Lightbox.init();
+ //new Asset.javascript(Wiki.TemplateUrl+'scripts/slimbox.js');
+ }
+}
+Wiki.addPageRender(WikiSlimbox);
+
+/*
+ Slimbox v1.31 - The ultimate lightweight Lightbox clone
+ by Christophe Beyls (http://www.digitalia.be) - MIT-style license.
+ Inspired by the original Lightbox v2 by Lokesh Dhakar.
+
+ Updated by Dirk Frederickx to fit JSPWiki needs
+ - minimum size of image canvas DONE
+ - add maximum size of image w.r.t window size DONE
+ - CLOSE icon -> close x text iso icon DONE
+ - <<prev, next>> links added in visible part of screen DONE
+ - add size of picture to info window DONE
+ - spacebor, down arrow, enter : next image DONE
+ - up arrow : prev image DONE
+ - allow the same picture occuring several times DONE
+ - add support for external page links => slimbox_ex DONE
+*/
+var Lightbox = {
+
+ init: function(options){
+ this.options = $extend({
+ resizeDuration: 400,
+ resizeTransition: false, /*Fx.Transitions.sineInOut,*/
+ initialWidth: 250,
+ initialHeight: 250,
+ animateCaption: true,
+ errorMessage: "slimbox.error".localize()
+ }, options || {});
+
+ this.anchors=[];
+ $each(document.links, function(el){
+ if (el.rel && el.rel.test(/^lightbox/i)){
+ el.onclick = this.click.pass(el, this);
+ this.anchors.push(el);
+ }
+ }, this);
+ this.eventKeyDown = this.keyboardListener.bindAsEventListener(this);
+ this.eventPosition = this.position.bind(this);
+
+ /* Build float panel
+ <div id="lbOverlay"></div>
+ <div id="lbCenter">
+ <div id="lbImage">
+ <!-- img or iframe element is inserted here -->
+ </div>
+ </div>
+ <div id="lbBottomContainer">
+ <div id="lbBottom">
+ <div id="lbCaption">
+ <div id="lbNumber">
+ <a id="lbCloseLink"></a>
+ <div style="clear:both;"></div>
+ </div>
+ </div>
+ */
+ this.overlay = new Element('div', {'id': 'lbOverlay'}).inject(document.body);
+
+ this.center = new Element('div', {'id': 'lbCenter', 'styles': {'width': this.options.initialWidth, 'height': this.options.initialHeight, 'marginLeft': -(this.options.initialWidth/2), 'display': 'none'}}).inject(document.body);
+ new Element('a', {'id': 'lbCloseLink', 'href':'#', 'title':'slimbox.close.title'.localize()}).inject(this.center).onclick = this.overlay.onclick = this.close.bind(this);
+ this.image = new Element('div', {'id': 'lbImage'}).inject(this.center);
+
+ this.bottomContainer = new Element('div', {'id': 'lbBottomContainer', 'styles': {'display': 'none'}}).inject(document.body);
+ this.bottom = new Element('div', {'id': 'lbBottom'}).inject(this.bottomContainer);
+ //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);
+ 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);
+ this.prevLink.onclick = this.previous.bind(this);
+ this.nextLink.onclick = this.next.bind(this);
+
+ 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(),
+ resize: this.center.effects($extend({duration: this.options.resizeDuration, onComplete: nextEffect}, this.options.resizeTransition ? {transition: this.options.resizeTransition} : {})),
+ image: this.image.effect('opacity', {duration: 500, onComplete: nextEffect}),
+ bottom: this.bottom.effect('margin-top', {duration: 400, onComplete: nextEffect})
+ };
+
+ 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();
+ },
+
+ click: function(link){
+ var rel = link.rel.split(' ');
+ if (rel[0].length == 8) return this.open([[url, title, rel[1]]], 0);
+
+ var imageNum=0, images = [];
+ this.anchors.each(function(el){
+ var elRel = el.rel.split(' ');
+ if (elRel[0]!=rel[0]) return;
+ if((el.href==link.href) && (el.title==link.title)) imageNum = images.length;
+ images.push([el.href, el.title, elRel[1]]);
+ });
+ return this.open(images, imageNum);
+ },
+
+ open: function(images, imageNum){
+ this.images = images;
+ this.position();
+ this.setup(true);
+ this.top = window.getScrollTop() + (window.getHeight() / 15);
+ this.center.setStyles({top: this.top, display: ''});
+ this.fx.overlay.start(0.7);
+ return this.changeImage(imageNum);
+ },
+
+ position: function(){
+ this.overlay.setStyles({top: window.getScrollTop(), height: window.getHeight()});
+ },
+
+ setup: function(open){
+ var elements = $A(document.getElementsByTagName('object'));
+ elements.extend(document.getElementsByTagName(window.ie ? 'select' : 'embed'));
+ elements.each(function(el){
+ if (open) el.lbBackupStyle = el.style.visibility;
+ el.style.visibility = open ? 'hidden' : el.lbBackupStyle;
+ });
+ var fn = open ? 'addEvent' : 'removeEvent';
+ window[fn]('scroll', this.eventPosition)[fn]('resize', this.eventPosition);
+ document[fn]('keydown', this.eventKeyDown);
+ this.step = 0;
+ },
+
+ 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 13: case 32: case 39: case 40: case 78: this.next(); break;
+ default: return;
+ }
+ new Event(event).stop();
+ },
+
+ previous: function(){
+ return this.changeImage(this.activeImage-1);
+ },
+
+ next: function(){
+ return this.changeImage(this.activeImage+1);
+ },
+
+ changeImage: function(imageNum){
+ if (this.step || (imageNum < 0) || (imageNum >= this.images.length)) return false;
+ this.step = 1;
+ this.activeImage = imageNum;
+
+ this.center.style.backgroundColor = '';
+ this.bottomContainer.style.display = this.prevLink.style.display = this.nextLink.style.display = 'none';
+ this.fx.image.hide();
+ this.center.className = 'lbLoading';
+
+ this.preload = new Image();
+ this.image.empty().setStyle('overflow','hidden');
+ if( this.images[imageNum][2] == 'img' ){
+ this.preload.onload = this.nextEffect.bind(this);
+ this.preload.src = this.images[imageNum][0];
+ } 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',
+ src:this.images[imageNum][0]
+ }).inject(this.image);
+ this.nextEffect(); //asynchronous loading?
+
+ }
+ return false;
+ },
+
+ ajaxFailure: function (){
+ this.ajaxFailed = true;
+ this.image.setHTML('').adopt(this.error.clone());
+ this.nextEffect();
+ },
+
+ nextEffect: function(){
+ switch (this.step++){
+ case 1:
+ this.center.className = '';
+ this.caption.empty().adopt(new Element('a', {
+ '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';
+
+ var w = Math.max(this.options.initialWidth,this.preload.width),
+ h = Math.max(this.options.initialHeight,this.preload.height),
+ ww = Window.getWidth()-10,
+ wh = Window.getHeight()-120;
+ if(this.images[this.activeImage][2]!='img' &&!this.ajaxFailed){ w = 6000; h = 3000; }
+ if(w > ww) { h = Math.round(h * ww/w); w = ww; }
+ if(h > wh) { w = Math.round(w * wh/h); h = wh; }
+
+ 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+' ['+this.preload.width+'×'+this.preload.height+']');
+ } else {
+ this.so.style.width=w+'px';
+ this.so.style.height=h+'px';
+ }
+
+ if (this.options.animateCaption) this.bottomContainer.setStyles({height: '0px', display: ''});
+
+ this.fxs.start({
+ '0': { height: [this.image.offsetHeight], width: [this.image.offsetWidth], marginLeft: [-this.image.offsetWidth/2] },
+ '1': { opacity: [1] }
+ });
+
+ break;
+ case 2:
+ //this.center.style.backgroundColor = '#000';
+ this.image.setStyle('overflow','auto');
+ this.bottomContainer.setStyles({ top: (this.top + this.center.clientHeight)+'px', marginLeft: this.center.style.marginLeft });
+ if (this.options.animateCaption){
+ this.fx.bottom.set(-this.bottom.offsetHeight);
+ this.bottomContainer.style.height = '';
+ this.fx.bottom.start(0);
+ break;
+ }
+ this.bottomContainer.style.height = '';
+ case 3:
+ if (this.activeImage) this.prevLink.style.display = '';
+ if (this.activeImage != (this.images.length - 1)) this.nextLink.style.display = '';
+ this.step = 0;
+ }
+ },
+
+ close: function(){
+ if (this.step < 0) return;
+ this.step = -1;
+ if (this.preload){
+ this.preload.onload = Class.empty;
+ this.preload = null;
+ }
+ for (var f in this.fx) this.fx[f].stop();
+ this.center.style.display = this.bottomContainer.style.display = 'none';
+ this.fx.overlay.chain(this.setup.pass(false, this)).start(0);
+ this.image.empty();
+ return false;
+ }
+};
+
+
+/** Class: Tabbed Section (130)
+ Creates tabs, based on some css-class information
+ Use in jspwiki: %%tabbedSection %%tab-FirstTab .. %% %%
+
+ Following markup:
+ <div class="tabbedSection">
+ <div class="tab-FirstTab">..<div>
+ <div class="tab-SecondTab">..<div>
+ </div>
+
+ is changed into
+ <div class="tabmenu"><span><a activetab>..</a></span>..</div>
+ <div class="tabbedSection tabs">
+ <div class="tab-firstTab ">
+ <div class="tab-SecondTab hidetab">
+ </div>
+ **/
+var TabbedSection = {
+
+ render: function(page, name){
+ // 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);
+
+ // 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);
+
+ tt.getChildren().each(function(tab,i) {
+ //find nested %%tab-XXX
+ var clazz = tab.className;
+ if( !clazz.test('^tab-') ) return;
+
+ if( !tab.id || (tab.id=="") ) tab.id = clazz; //unique id
+
+ (i==0) ? tab.removeClass('hidetab') : tab.addClass('hidetab');
+
+ new Element('div',{'class':'clearbox'}).inject(tab);
+
+ var title = clazz.substr(4).deCamelize(); //drop 'tab-' prefix
+ new Element('a', {
+ 'id':'menu-'+tab.id,
+ 'class':(i==0) ? 'activetab' : '',
+ 'events':{ 'click': this.click }
+ }).appendText(title).inject(menu);
+
+ },this);
+ }, this);
+ },
+
+ click: function(){
+ var menu = $(this).getParent(),
+ tabs = menu.getNext();
+
+ menu.getChildren().removeClass('activetab');
+ this.addClass('activetab');
+
+ tabs.getChildren().addClass('hidetab');
+ tabs.getElement( '#'+ this.id.substr(5)).removeClass('hidetab');
+ }
+
+}
+Wiki.addPageRender(TabbedSection);
+
+
+
+/* 140 SearchBox
+ * FIXME: remember 10 most recent search topics (cookie based)
+ * Extended with quick links for view, edit and clone (ref. idea of Ron Howard - Nov 05)
+ * Refactored for mootools, April 07
+ */
+var SearchBox = {
+
+ onPageLoad: function(){
+ this.onPageLoadQuickSearch();
+ this.onPageLoadFullSearch();
+ },
+
+ onPageLoadQuickSearch : function(){
+ var q = $('query'); if( !q ) return;
+ 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});
+ //} else {
+ $('recentClear').addEvent('click', this.clear.bind(this));
+
+ this.recent = Wiki.prefs.get('RecentSearch'); if(!this.recent) return;
+
+ var ul = new Element('ul',{'id':'recentItems'}).inject($('recentSearches').show());
+ this.recent.each(function(el){
+ // xss vulnerability JSPWIKI-384
+ el = el.stripScripts();
+ new Element('a',{
+ 'href':'#',
+ 'events': {'click':function(){ q.value = el; q.form.submit(); }}
+ }).setHTML(el).inject( new Element('li').inject(ul) );
+ });
+ //}
+ },
+
+ 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+)$/);
+ if(s && s.length==3){
+ q2.value = s[1];
+ $('start').value = s[2];
+ changescope();
+ }
+ }
+ },
+
+ /* reset the start page before rerunning the ajax search */
+ runfullsearch0: function(){
+ $('start').value='0';
+ this.runfullsearch();
+ },
+
+ runfullsearch: function(e){
+ var q2 = this.query2.value;
+ if( !q2 || (q2.trim()=='')) {
+ $('searchResult2').empty();
+ return;
+ }
+ $('spin').show();
+
+ var scope = $('scope'),
+ match= q2.match(/^(?:author:|name:|contents:|attachment:)/) ||"";
+
+ $each(scope.options, function(option){
+ if (option.value == match) option.selected = true;
+ });
+
+ new Ajax(Wiki.TemplateUrl+'AJAXSearch.jsp', {
+ postBody: $('searchform2').toQueryString(),
+ update: 'searchResult2',
+ method: 'post',
+ onComplete: function() {
+ $('spin').hide();
+ GraphBar.render($('searchResult2'));
+ Wiki.prefs.set('PrevQuery', q2);
+ }
+ }).request();
+
+ location.hash = '#'+q2+":"+$('start').value; /* push the query into the url history */
+ },
+
+ submit: function(){
+ var v = this.query.value.stripScripts(); //xss vulnerability
+ if( v == this.query.defaultValue) this.query.value = '';
+ if( !this.recent ) this.recent=[];
+ if( !this.recent.test(v) ){
+ if(this.recent.length > 9) this.recent.pop();
+ this.recent.unshift(v);
+ Wiki.prefs.set('RecentSearch', this.recent);
+ }
+ },
+
+ clear: function(){
+ this.recent = [];
+ Wiki.prefs.remove('RecentSearch');
+ $('recentSearches','recentClear').hide();
+ },
+
+ ajaxQuickSearch: function(){
+ var qv = this.query.value.stripScripts() ;
+ if( (qv==null) || (qv.trim()=="") || (qv==this.query.defaultValue) ) {
+ $('searchOutput').empty();
+ return;
+ }
+ $('searchTarget').setHTML('('+qv+') :');
+ $('searchSpin').show();
+
+ Wiki.jsonrpc('search.findPages', [qv,20], function(result){
+ $('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.getUrl(el.map.page) }).setHTML(el.map.page),
+ new Element('span',{'class':'small'}).setHTML(" ("+el.map.score+")")
+ ).inject(frag);
+ });
+ $('searchOutput').empty().adopt(frag);
+ Wiki.locatemenu( $('query'), $('searchboxMenu') );
+ });
+ } ,
+
+ /* navigate to url, after smart pagename handling */
+ navigate: function(url, promptText, clone, search){
+ var p = Wiki.PageName,
+ defaultResult = (clone) ? p+'sbox.clone.suffix'.localize() : p,
+ s = this.query.value;
+ if(s == this.query.defaultValue) s = '';
+
+ var handleResult = function(s){
+ if(s == '') return;
+ if(!search) s = Wiki.cleanLink(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);
+ } else {
+ Wiki.prompt(promptText, defaultResult, handleResult.bind(this));
+ }
+ }
+}
+
+
+/**
+ ** 150 GraphBar Object: also used on the findpage
+ ** %%graphBars ... %%
+ ** convert numbers inside %%gBar ... %% tags to graphic horizontal bars
+ ** no img needed.
+ ** supported parameters: bar-color and bar-maxsize
+ ** e.g. %%graphBars-e0e0e0 ... %% use color #e0e0e0, default size 120
+ ** e.g. %%graphBars-blue-red ... %% blend colors from blue to red
+ ** e.g. %%graphBars-red-40 ... %% use color red, maxsize 40 chars
+ ** e.g. %%graphBars-vertical ... %% vertical bars
+ ** e.g. %%graphBars-progress ... %% progress bars in 2 colors
+ ** e.g. %%graphBars-gauge ... %% gauge bars in gradient colors
+ **/
+
+/* minimal variant of the Color class, inspired by mootools */
+var Color = new Class({
+
+ _HTMLColors: {
+ black :"000000", green :"008000", silver :"c0c0c0", lime :"00ff00",
+ gray :"808080", olive :"808000", white :"ffffff", yellow:"ffff00",
+ maroon :"800000", navy :"000080", red :"ff0000", blue :"0000ff",
+ purple :"800080", teal :"008080", fuchsia:"ff00ff", aqua :"00ffff"
+ },
+
+ initialize: function(color, type){
+ if(!color) return false;
+ type = type || (color.push ? 'rgb' : 'hex');
+ if(this._HTMLColors[color]) color = this._HTMLColors[color];
+ var rgb = (type=='rgb') ? color : color.toString().hexToRgb(true);
+ if(!rgb) return false;
+ rgb.hex = rgb.rgbToHex();
+ return $extend(rgb, Color.prototype);
+ },
+
+ mix: function(){
+ var colors = $A(arguments),
+ rgb = this.copy(),
+ alpha = (($type(colors[colors.length - 1]) == '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');
+ },
+
+ invert: function(){
+ return new Color(this.map(function(value){
+ return 255 - value;
+ }));
+ }
+
+});
+
+var GraphBar =
+{
+ render: function(page, name){
+ $ES('*[class^=graphBars]',page).each( function(g){
+ var lbound = 20, //max - lowerbound size of bar
+ ubound = 320, //min - upperbound size of bar
+ vwidth = 20, //vertical bar width
+ color1 = null, // bar color
+ color2 = null, // 2nd bar color used depending on bar-type
+ isGauge = false, // gauge bar
+ isProgress = false, // progress bar
+ isHorizontal = true,// horizontal or vertical orientation
+ parms = g.className.substr(9).split('-'),
+ barName = parms.shift(), //first param is optional barName
+ size,bars,barData,border;
+
+ parms.each(function(p){
+ p = p.toLowerCase();
+ if(p == "vertical") { isHorizontal = false; }
+ else if(p == "progress") { isProgress = true; }
+ else if(p == "gauge") { isGauge = true; }
+ else if(p.indexOf("min") == 0) { lbound = p.substr(3).toInt(); }
+ 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;
+ else if(!color2) color2 = p;
+ }
+ });
+ if( !color2 && color1) color2 = (isGauge || isProgress) ? color1.invert() : color1;
+
+ if( lbound > ubound ) { var m = ubound; ubound=lbound; ubound=m; }
+ size = ubound-lbound;
+
+ bars = $ES('.gBar'+barName, g); //collect all gBar elements
+ if( (bars.length==0) && barName && (barName!="")){ // check table data
+ bars = this.getTableValues(g, barName);
+ }
+ if( !bars ) return;
+
+ barData = this.parseBarData( bars, lbound, size );
+ 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'
+ barEL = new Element('span',{'class':'graphBar'}),
+ pb = b.getParent(); // parent of gBar element
+
+ if(isHorizontal){
+ barEL.setHTML('x');
+ if(isProgress){
+ bar2.extend(bar1.obj);
+ bar1.set(border+'Width',ubound-barData[j]).set('marginLeft','-1ex');
+ }
+ } else { // isVertical
+ if(pb.getTag()=='td') { pb = new Element('div').wrapChildren(pb); }
+
+ pb.setStyles({'height':ubound+b.getStyle('lineHeight').toInt(), 'position':'relative'});
+ b.setStyle('position', 'relative'); //needed for inserted spans ;-)) hehe
+ 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){
+ if(color1){ bar1.set('borderColor', color1.hex); }
+ 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); };
+
+ },this);
+
+ },this);
+ },
+
+ // parse bar data types and scale according to lbound and size
+ parseBarData: function(nodes, lbound, size){
+ var barData=[],
+ maxValue=Number.MIN_VALUE,
+ minValue=Number.MAX_VALUE,
+ num=date=true;
+
+ nodes.each(function(n,i){
+ var s = n.getText();
+ barData.push(s);
+ num &= !isNaN(s.toFloat());
+ /* chrome accepts numbers as valid Dates !! */
+ date &= !isNaN(Date.parse(s)) && s.test(/[^\d]/);
+ });
+
+ barData = barData.map(function(b){
+ if(date){ b = new Date(Date.parse(b) ).valueOf(); }
+ else if(num){ b = parseFloat( b.match(Number.REparsefloat) ); }
+
+ 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);
+ return barData.map(function(b){
+ return ( (size*(b-minValue)) + lbound).toInt();
+ });
+ },
+
+ /* Fetch set of gBar values from a table
+ * Check first-row to match field-name: return array with col values
+ * Check first-column to match field-name: return array with row values
+ * insert SPANs as place-holder of the missing gBars
+ */
+ getTableValues: function(node, fieldName){
+ var table = $E('table', node); if(!table) return false;
+ var tlen = table.rows.length;
+
+ if( tlen > 1 ){ /* check for COLUMN based table */
+ var r = table.rows[0];
+ for( var h=0; h < r.cells.length; h++ ){
+ if( $getText( r.cells[h] ).trim() == fieldName ){
+ var result = [];
+ for( var i=1; i< tlen; i++)
+ result.push( new Element('span').wrapChildren(table.rows[i].cells[h]) );
+ return result;
+ }
+ }
+ }
+ for( var h=0; h < tlen; h++ ){ /* check for ROW based table */
+ var r = table.rows[h];
+ if( $getText( r.cells[0] ).trim() == fieldName ){
+ var result = [];
+ for( var i=1; i< r.cells.length; i++)
+ result.push( new Element('span').wrapChildren(r.cells[i]) );
+ return result;
+ }
+ }
+ return false;
+ }
+}
+Wiki.addPageRender(GraphBar);
+
+
+/** 200 Collapsible list and boxes **/
+var Collapsible =
+{
+ pims : [], // all me cookies
+
+ render: function(page, name){
+ page = $(page); if(!page) return;
+
+ var cookie = Wiki.Context.test(/view|edit|comment/) ? "JSPWikiCollapse"+ name: "";
+
+ if(!this.bullet) {
+ this.bullet = new Element('div',{'class':'collapseBullet'}).setHTML('•');
+ }
+
+ this.pims.push({
+ 'name':cookie,
+ 'value':'',
+ 'initial': (cookie ? Cookie.get(cookie) : "")
+ });
+ $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);
+ }, 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'}),
+ bullet = this.bullet.clone(),
+ isclosed = el.hasClass('collapsebox-closed');
+
+ while(title.nextSibling) body.appendChild(title.nextSibling); // wrap other siblings
+ el.appendChild(body);
+
+ if(isclosed) el.removeClass('collapsebox-closed').addClass('collapsebox');
+ bullet.injectTop( title.addClass('collapsetitle') );
+ this.newBullet(bullet, body, !isclosed, title );
+ },
+
+ // 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 containing 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
+ var emptyLI = true;
+ for( var n = li.firstChild; n ; n = n.nextSibling ) {
+ if((n.nodeType == 3 ) && ( n.nodeValue.trim() == "" ) ) continue; //keep searching
+ if((n.nodeName == "UL") || (n.nodeName == "OL")) break; //seems like an empty li
+ emptyLI = false;
+ break;
+ }
+ if( emptyLI ) return;
+
+ new Element('div',{'class':'collapsebody'}).wrapChildren(li);
+ var bullet = this.bullet.clone().injectTop(li);
+ if(ulol) this.newBullet(bullet, ulol, (ulol.getTag()=='ul'));
+ },this);
+ },
+
+ newBullet: function(bullet, body, isopen, clicktarget){
+ var ck = this.pims.getLast(); //read cookie
+ isopen = this.parseCookie(isopen);
+ if(!clicktarget) clicktarget = bullet;
+
+ var bodyfx = body.setStyle('overflow','hidden')
+ .effect('height', {
+ wait:false,
+ onStart:this.renderBullet.bind(bullet),
+ onComplete:function(){ if(bullet.hasClass('collapseOpen')) body.setStyle('height','auto'); }
+ });
+
+ bullet.className = (isopen ? 'collapseClose' : 'collapseOpen'); //ready for rendering
+ clicktarget.addEvent('click', this.clickBullet.bindWithEvent(bullet, [ck, ck.value.length-1, bodyfx]))
+ .addEvent('mouseenter', function(){ clicktarget.addClass('hover')} )
+ .addEvent('mouseleave', function(){ clicktarget.removeClass('hover')} );
+
+ bodyfx.fireEvent('onStart');
+ if(!isopen) bodyfx.set(0);
+ },
+
+ renderBullet: function(){
+ if(this.hasClass('collapseClose')){
+ this.setProperties({'title':'collapse'.localize(), 'class':'collapseOpen'}).setHTML('-'); /* » */
+ } else {
+ this.setProperties({'title':'expand'.localize(), 'class':'collapseClose'}).setHTML('+'); /* « */
+ }
+ },
+
+ clickBullet: function( event, ck, bulletidx, bodyfx){
+ var collapse = this.hasClass('collapseOpen'),
+ 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.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});
+
+ }
+ },
+
+ // parse initial cookie versus actual document
+ // returns true if collapse status is open
+ parseCookie: function( isopen ){
+ var ck = this.pims.getLast(),
+ cursor = ck.value.length,
+ token = (isopen ? 'o' : 'c');
+
+ if(ck.initial && (ck.initial.length > cursor)){
+ var cookieToken = ck.initial.charAt( cursor );
+
+ if( ( isopen && (cookieToken == 'c') )
+ || ( !isopen && (cookieToken == 'o') ) ) token = cookieToken ;
+
+ if(token != cookieToken) ck.initial = null; //mismatch with initial cookie
+ }
+ ck.value += token; //append and save currentcookie
+
+ return(token == 'o');
+ }
+};
+Wiki.addPageRender(Collapsible);
+
+
+/** 230 Sortable -- Sort tables **/
+//TODO cache table ok, cache datatype for each column
+var Sortable =
+{
+ render: function(page,name){
+ this.DefaultTitle = "sort.click".localize();
+ this.AscendingTitle = "sort.ascending".localize();
+ this.DescendingTitle = "sort.descending".localize();
+
+ $ES('.sortable table',page).each(function(table){
+ if( table.rows.length <= 2 ) return;
+
+ $A(table.rows[0].cells).each(function(th){
+ th=$(th);
+ if(th.getTag()=='th'){
+ th.addEvent('click', this.sort.bind(this,th) )
+ .addClass('sort')
+ .title=this.DefaultTitle;
+ }
+ },this);
+ },this);
+ },
+
+ sort: function(th){
+ var table = getAncestorByTagName(th, "table" ),
+ filter = (table.filterStack),
+ rows = (table.sortCache || []),
+ colidx = 0, //target column to sort
+ body = $T(table);
+ th = $(th);
+
+ //todo add spinner while sorting
+ //validate header row
+ $A(body.rows[0].cells).each(function(thi, i){
+ if(thi.getTag() != 'th') return;
+ if(th == thi) { colidx=i; return; }
+ thi.removeClass('sortAscending').removeClass('sortDescending')
+ .addClass('sort').title = Sortable.DefaultTitle;
+ });
+
+ if(rows.length == 0){ //if data not yet cached
+ $A(body.rows).each(function(r,i){
+ if((i==0) || ((i==1) && (filter))) return;
+ rows.push( r );
+ });
+ };
+ var datatype = Sortable.guessDataType(rows,colidx);
+
+ //do the actual sorting
+ if(th.hasClass('sort')){
+ rows.sort( Sortable.createCompare(colidx, datatype) )
+ }
+ else rows.reverse();
+
+ var fl=th.hasClass('sortDescending');
+ th.removeClass('sort').removeClass('sortAscending').removeClass('sortDescending');
+ th.addClass(fl ? 'sortAscending': 'sortDescending')
+ .title= fl ? Sortable.DescendingTitle: Sortable.AscendingTitle;
+
+ var frag = document.createDocumentFragment();
+ rows.each( function(r,i){ frag.appendChild(r); });
+ body.appendChild(frag);
+ table.sortCache = rows;
+ if(table.zebra) table.zebra();
+ },
+
+ guessDataType: function(rows, colidx){
+
+ var num=date=ip4=euro=kmgt=true;
+
+ rows.each(function(r,i){
+
+ var v = r.cells[colidx];
+
+ v = v.getAttribute('jspwiki:sortvalue') || $getText(v);
+ v = v.clean().toLowerCase();
+
+ if(num) num = !isNaN(parseFloat(v));
+ /* chrome accepts numbers as valid Dates !! */
+ if(date) date = !isNaN(Date.parse(v)) && v.test(/[^\d]/);
+ if(ip4) ip4 = v.test(/(?:\\d{1,3}\\.){3}\\d{1,3}/); //169.169.0.1
+ if(euro) euro = v.test(/^[£$â¬][0-9.,]+/);
+ if(kmgt) kmgt = v.test(/(?:[0-9.,]+)\s*(?:[kmgt])b/); //2 MB, 4GB, 1.2kb, 8Tb
+
+ });
+
+ return (kmgt) ? 'kmgt': (euro) ? 'euro': (ip4) ? 'ip4': (date) ? 'date': (num) ? 'num': 'string';
+
+ },
+
+ convert: function(val, datatype){
+
+ switch( datatype ){
+
+ case "num" :
+ return parseFloat( val.match( Number.REparsefloat ) );
+
+ case "euro":
+ return parseFloat( val.replace(/[^0-9.,]/g,'') );
+
+ case "date":
+ return new Date( Date.parse( val ) );
+
+ case "ip4" :
+ var octet = val.split( "." );
+ return parseInt(octet[0]) * 1000000000 + parseInt(octet[1]) * 1000000 + parseInt(octet[2]) * 1000 + parseInt(octet[3]);
+
+ case "kmgt":
+ var v = val.toString().toLowerCase().match(/([0-9.,]+)\s*([kmgt])b/);
+ if(!v) return 0;
+ var z=v[2];
+ z = (z=='m') ? 3 : (z=='g') ? 6 : (z=='t') ? 9 : 0;
+ return v[1].toFloat()*Math.pow(10,z);
+
+ default:
+ return val.toString().toLowerCase();
+
+ }
+
+ },
+
+ createCompare: function( i, datatype ){
+
+ return function( row1, row2 ){
+
+ //fixme: should cache the converted sortable values
+ var v1 = row1.cells[i],
+ v2 = row2.cells[i],
+ val1 = Sortable.convert( v1.getAttribute('jspwiki:sortvalue') || $getText(v1), datatype ),
+ val2 = Sortable.convert( v2.getAttribute('jspwiki:sortvalue') || $getText(v2), datatype );
+
+ return (val1<val2) ? -1 : (val1>val2) ? 1 : 0;
+
+ }
+ }
+}
+Wiki.addPageRender(Sortable);
+
+/** 240 table-filters
+ ** inspired by http://www.codeproject.com/jscript/filter.asp
+ **/
+var TableFilter =
+{
+ render: function(page,name){
+ this.All = "filter.all".localize();
+ this.FilterRow = 1; //row number of filter dropdowns
+
+ $ES('.table-filter table',page).each( function(table){
+ if( table.rows.length < 2 ) return;
+
+ /*
+ $A(table.rows[0].cells).each(function(e,i){
+ var s = new Element('select',{
+ 'events': {
+ 'click':function(event){ event.stop(); }.bindWithEvent(),
+ 'change':TableFilter.filter
+ }
+ });
+ s.fcol = i; //store index
+ e.adopt(s);
+ },this);
+ */
+
+ var r = $(table.insertRow(TableFilter.FilterRow)).addClass('filterrow');
+ for(var j=0; j < table.rows[0].cells.length; j++ ){
+ var s = new Element('select',{
+ 'events': {
+ 'change':TableFilter.filter
+ }
+ });
+ s.fcol = j; //store index
+
+ new Element('th').adopt(s).inject(r);
+ }
+ table.filterStack = [];
+ TableFilter.buildEmptyFilters(table);
+ });
+ },
+
+ buildEmptyFilters: function(table){
+ for(var i=0; i < table.rows[0].cells.length; i++){
+ var ff = table.filterStack.some(function(f){ return f.fcol==i });
+ if(!ff) TableFilter.buildFilter(table, i);
+ }
+ if(table.zebra) table.zebra();
+ },
+
+ // this function initialises a column dropdown filter
+ buildFilter: function(table, col, selectedValue){
+ // Get a reference to the dropdownbox.
+ var select = table.rows[TableFilter.FilterRow].cells[col].firstChild;
+ //var select = $(table.rows[0].cells[col]).getLast();
+ if(!select) return; //empty dropdown
+ select.options.length = 0;
+
+ var rows=[];
+ $A(table.rows).each(function(r,i){
+ if((i==0) || (i==TableFilter.FilterRow)) return;
+ if(r.style.display == 'none') return;
+ rows.push( r );
+ });
+ rows.sort(Sortable.createCompare(col, Sortable.guessDataType(rows,col)));
+
+ //add only unique strings to the dropdownbox
+ select.options[0]= new Option(this.All, this.All);
+ var value;
+ rows.each(function(r,i){
+ var v = $getText(r.cells[col]).clean().toLowerCase();
+ if(v == value) return;
+ value = v;
+ //if(v.length > 32) v = v.substr(0,32)+ "...";
+ //select.options[select.options.length] = new Option(v, value);
+ select.options[select.options.length] = new Option(v.trunc(32), value);
+ });
+ (select.options.length <= 2) ? select.hide() : select.show();
+ if(selectedValue != undefined) {
+ select.value = selectedValue;
+ } else {
+ select.options[0].selected = true;
+ }
+ },
+
+ filter: function(){ //onchange handler of filter dropdowns
+ var col = this.fcol,
+ value = this.value,
+ table = getAncestorByTagName(this, 'table');
+ if( !table || table.style.display == 'none') return;
+
+ // First check if the column is allready in the filter.
+ if(table.filterStack.every(function(f,i){
+ if(f.fcol != col) return true;
+ if(value == TableFilter.All) table.filterStack.splice(i, 1);
+ else f.fValue = value;
+ return false;
+ }) ) table.filterStack.push( {fValue:value, fcol:col} );
+
+ $A(table.rows).each(function(r,i){ //show all
+ r.style.display='';
+ });
+
+ table.filterStack.each(function(f){ //now filter the right rows
+ var v = f.fValue, c = f.fcol;
+ TableFilter.buildFilter(table, c, v);
+
+ var j=0;
+ $A(table.rows).each(function(r,i){
+ if((i==0) || (i==TableFilter.FilterRow)) return;
+ if(v != $getText(r.cells[c]).clean().toLowerCase()) r.style.display = 'none';
+ });
+ });
+ TableFilter.buildEmptyFilters(table); //fill remaining dropdowns
+ }
+}
+Wiki.addPageRender(TableFilter);
+
+
+/** 250 Categories: turn wikipage link into AJAXed popup **/
+var Categories =
+{
+ render: function (page,name){
+
+ $ES('.category a.wikipage',page).each(function(link){
+ var page = Wiki.getPageName(link.href);
+ if(!page) return;
+ var wrap = new Element('span').injectBefore(link).adopt(link),
+ popup = new Element('div',{'class':'categoryPopup'}).inject(wrap),
+ popfx = popup.effect('opacity',{wait:false}).set(0);
+
+ link.addClass('categoryLink')
+ .setProperties({ href:'#', title: "category.title".localize(page) })
+ .addEvent('click', function(e){
+ new Event(e).stop(); //dont jump to top of page ;-)
+
+ new Ajax( Wiki.TemplateUrl + 'AJAXCategories.jsp', {
+ postBody: '&page=' + page,
+ update: popup,
+ onComplete: function(){
+ link.setProperty('title', '').removeEvent('click');
+ wrap.addEvent('mouseover', function(e){ popfx.start(0.9); })
+ .addEvent('mouseout', function(e){ popfx.start(0); });
+ popup.setStyle('left', link.getPosition().x);
+ popup.setStyle('top', link.getPosition().y+16);
+ popfx.start(0.9);
+
+ $ES('li,div.categoryTitle',popup).each(function(el){
+ el.addEvent('mouseout',function(){ this.removeClass('hover')})
+ .addEvent('mouseover',function(){ this.addClass('hover')});
+ });
+
+
+ }
+ }).request();
+ });
+ });
+ }
+}
+Wiki.addPageRender(Categories);
+
+
+/** 280 ZebraTable
+ ** Color odd/even rows of table differently
+ ** 1) odd rows get css class odd (ref. jspwiki.css )
+ ** %%zebra-table ... %%
+ **
+ ** 2) odd rows get css style='background=<color>'
+ ** %%zebra-<odd-color> ... %%
+ **
+ ** 3) odd rows get odd-color, even rows get even-color
+ ** %%zebra-<odd-color>-<even-color> ... %%
+ **
+ ** colors are specified in HEX (without #) format or html color names (red, lime, ...)
+ **/
+var ZebraTable = {
+ render: function(page,name){
+ $ES('*[class^=zebra]',page).each(function(z){
+ var parms = z.className.split('-'),
+ isDefault = parms[1].test('table'),
+ c1 = '',
+ c2 = '';
+ if(parms[1]) c1= new Color(parms[1],'hex');
+ if(parms[2]) c2= new Color(parms[2],'hex');
+ $ES('table',z).each(function(t){
+ t.zebra = this.zebrafy.pass([isDefault, c1,c2],t);
+ t.zebra();
+ },this);
+ },this);
+ },
+ zebrafy: function(isDefault, c1, c2){
+ var j=0;
+ $A($T(this).rows).each(function(r,i){
+ if(i==0 || (r.style.display=='none')) return;
+ if(isDefault) (j++ % 2) ? $(r).addClass('odd') : $(r).removeClass('odd');
+ else $(r).setStyle('background-color', (j++ % 2) ? c1 : c2 );
+ });
+ }
+}
+Wiki.addPageRender(ZebraTable);
+
+/** Highlight Word
+ ** Inspired by http://www.kryogenix.org/code/browser/searchhi/
+ ** Modified 21006 to fix query string parsing and add case insensitivity
+ ** Modified 20030227 by sgala@hisitech.com to skip words
+ ** with "-" and cut %2B (+) preceding pages
+ ** Refactored for JSPWiki -- now based on regexp
+ **/
+var HighlightWord =
+{
+ onPageLoad: function (){
+ var q = Wiki.prefs.get('PrevQuery');
+ Wiki.prefs.set('PrevQuery', '');
+ if( !q && document.referrer.test("(?:\\?|&)(?:q|query)=([^&]*)","g") ) q = RegExp.$1;
+ if( !q ) return;
+
+ 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") );
+ },
+
+ // recursive tree walk matching all text nodes
+ walkDomTree: function(node){
+ if( !node ) return;
+ for(var nn=null, n = node.firstChild; n ; n = nn) {
+ nn = n. nextSibling; /* prefetch nextSibling cause the tree will be modified */
+ this.walkDomTree(n);
+ }
+ // continue on text-nodes, not yet highlighted, with a word match
+ if( node.nodeType != 3 ) return;
+ if( node.parentNode.className == "searchword" ) return;
+ var s = node.innerText || node.textContent || '';
+
+ s = s.replace(/</g,'<'); /* pre text elements may contain <xml> element */
+
+ if( !this.reMatch.test( s ) ) return;
+ var tmp = new Element('span').setHTML(s.replace(this.reMatch,"<span class='searchword'>$1</span>"));
+
+ var f = document.createDocumentFragment();
+ while( tmp.firstChild ) f.appendChild( tmp.firstChild );
+
+ node.parentNode.replaceChild( f, node );
+ }
+}
+
+window.addEvent('load', function(){
+ Wiki.onPageLoad();
+
+ SearchBox.onPageLoad();
+ HighlightWord.onPageLoad();
+ Wiki.setFocus();
+ //console.profile();
+ //console.profileEnd();
+});
\ No newline at end of file
Added: jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-commonstyles.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-commonstyles.js?rev=1509803&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-commonstyles.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/jspwiki-commonstyles.js Fri Aug 2 18:37:54 2013
@@ -0,0 +1,467 @@
+/*
+ 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"); you 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.
+ */
+
+/*
+ * jspwiki-commonstyles.js
+ * Contains additional Dynmic Styles
+ *
+ * 114 Reflection (adds reflection to images): dynamic style
+ * 132 Accordion object: dynamic style
+ * 220 RoundedCorners: dynamic style
+ * 260 WikiTips: dynamic style
+ * 270 WikiColumns: dynamic style
+ * 300 Prettify: dynamic style
+ */
+
+
+/*
+Dynamic Style: Reflection (114)
+
+Inspired by Reflection.js at http://cow.neondragon.net/stuff/reflection/
+Freely distributable under MIT-style license.
+Adapted for JSPWiki/BrushedTemplate, D.Frederickx, Sep 06
+
+Use:
+ %%reflection-height-opacity [some-image.jpg] %%
+ */
+var WikiReflection = {
+
+ render: function(page,name){
+ $ES('*[class^=reflection]',page).each( function(w){
+ var parms = w.className.split('-');
+ $ES('img',w).each(function(img){
+ Reflection.add(img, parms[1], parms[2]);
+ });
+ });
+ }
+}
+Wiki.addPageRender(WikiReflection);
+
+/* FIXME : add delayed loading of reflection library */
+var Reflection = {
+
+ options: { height: 0.33, opacity: 0.5 },
+
+ add: function(img, height, opacity) {
+ //TODO Reflection.remove(image); --is this still needed?
+ height = (height ) ? height/100 : this.options.height;
+ opacity = (opacity) ? opacity/100: this.options.opacity;
+
+ var div = new Element('div').injectAfter(img).adopt(img),
+ imgW = img.width,
+ imgH = img.height,
+ rH = Math.floor(imgH * height); //reflection height
+
+ div.className = img.className.replace(/\breflection\b/, "");
+ div.style.cssText = img.backupStyle = img.style.cssText;
+ //div.setStyles({'width':img.width, 'height':imgH +rH, "maxWidth": imgW });
+ div.setStyles({'width':img.width, 'height':imgH +rH });
+ img.style.cssText = 'vertical-align: bottom';
+ //img.className = 'inline reflected'; //FIXME: is this still needed ??
+
+ if( window.ie ){
+ new Element('img', {'src': img.src, 'styles': {
+ 'width': imgW,
+ 'marginBottom': "-" + (imgH - rH) + 'px',
+ 'filter': 'flipv progid:DXImageTransform.Microsoft.Alpha(opacity='+(opacity*100)+', style=1, finishOpacity=0, startx=0, starty=0, finishx=0, finishy='+(height*100)+')'
+ }}).inject(div);
+ } else {
+ var r = new Element('canvas', {'width':imgW, 'height':rH, 'styles': {'width':imgW, 'height': rH}}).inject(div);
+ if( !r.getContext ) return;
+
+ var ctx = r.getContext("2d");
+ ctx.save();
+ ctx.translate(0, imgH-1);
+ ctx.scale(1, -1);
+ ctx.drawImage(img, 0, 0, imgW, imgH);
+ ctx.restore();
+ ctx.globalCompositeOperation = "destination-out";
+
+ var g = ctx.createLinearGradient(0, 0, 0, rH);
+ g.addColorStop( 0, "rgba(255, 255, 255, " + (1 - opacity) + ")" );
+ g.addColorStop( 1, "rgba(255, 255, 255, 1.0)" );
+ ctx.fillStyle = g;
+ ctx.rect( 0, 0, imgW, rH );
+ ctx.fill();
+ }
+ }
+}
+
+
+/** 132 Accordion for Tabs, Accordeons, CollapseBoxes
+ **
+ ** Following markup:
+ ** <div class="accordion">
+ ** <div class="tab-FirstTab">...<div>
+ ** <div class="tab-SecondTab">...<div>
+ ** </div>
+ **
+ ** is changed into
+ ** <div class="accordion">
+ ** <div class="toggle active">First Tab</div>
+ ** <div class="tab-FirstTab tab active">...</div>
+ ** <div class="toggle">Second Tab</div>
+ ** <div class="tab-SecondTab">...</div>
+ ** </div>
+ **/
+var WikiAccordion = {
+
+ render: function(page,name){
+
+ var toggle = new Element('div',{'class':'toggle'}),
+ bullet = new Element('div',{'class':'collapseBullet'});
+
+ $ES('.accordion, .tabbedAccordion, .leftAccordion, .rightAccordion',page).each( function(tt){
+
+ var toggles=[], contents=[], menu=false;
+ if(tt.hasClass('tabbedAccordion')){
+ menu = new Element('div',{'class':'menu top'}).injectBefore(tt);
+ }
+ else if(tt.hasClass('leftAccordion')){
+ menu = new Element('div',{'class':'menu left'}).injectBefore(tt);
+ }
+ else if(tt.hasClass('rightAccordion')){
+ menu = new Element('div',{'class':'menu right'}).injectBefore(tt);
+ }
+
+ tt.getChildren().each(function(tab) {
+ if( !tab.className.test('^tab-') ) return;
+
+ //FIXME use class to make tabs visible during printing
+ //(i==0) ? tab.removeClass('hidetab'): tab.addClass('hidetab');
+
+ var title = tab.className.substr(4).deCamelize(),
+ t = toggle.clone().appendText(title);
+ menu ? t.inject(menu) : bullet.clone().injectTop(t.injectBefore(tab));
+
+ toggles.push(t);
+ contents.push(tab.addClass('tab'));
+ });
+
+ new Accordion(toggles, contents, {
+ height: true,
+ alwaysHide: !menu,
+ onComplete: function(){
+ var el = $(this.elements[this.previous]);
+ if (el.offsetHeight > 0) el.setStyle('height', 'auto');
+ },
+ onActive: function(toggle,content){
+ toggle.addClass('active');
+ var b = toggle.getFirst();/*bullet*/
+ if(b) b.setProperties({'title':'collapse'.localize(), 'class':'collapseOpen'}).setHTML('-'); /* » */
+ content.addClass('active');//.removeClass('xhidetab');
+ },
+ onBackground: function(toggle,content){
+ content.setStyle('height', content['offsetHeight']);
+ toggle.removeClass('active');
+ var b = toggle.getFirst();/*bullet*/
+ if(b) b.setProperties({'title':'expand'.localize(), 'class':'collapseClose'}).setHTML('+'); /* « */
+ content.removeClass('active');//.addClass('xhidetab');
+ }
+ });
+ });
+ bullet=toggle=null; //avoid memory leaks
+ }
+}
+Wiki.addPageRender(WikiAccordion);
+
+
+/** 220 RoundedCorners --experimental
+ ** based on Nifty corners by Allesandro Fulciniti
+ ** www.pro.html.it
+ ** Refactored for JSPWiki
+ **
+ ** JSPWiki syntax:
+ **
+ ** %%roundedCorners-<corners>-<color>-<borderColor>
+ ** %%
+ **
+ ** roundedCorners-yyyy-ffc5ff-c0c0c0
+ **
+ ** corners: "yyyy" where first y: top-left, 2nd y: top-right,
+ ** 3rd y: bottom-left; 4th y: bottom-right
+ ** value can be: "y": Normal rounded corner (lowercase y)
+ ** "s": Small rounded corner (lowercase s)
+ ** "n": Normal square corner
+ **
+ **/
+var RoundedCorners =
+{
+ /** Definition of CORNER dimensions
+ ** Normal Normal+Border Small Small+Border Big
+ ** .....+++ .....BBB ..+++ ..BBB ........+++
+ ** ...+++++ ...BB+++ .++++ .B+++ .....++++++
+ ** ..++++++ ..B+++++ +++++ B++++ ...++++++++
+ ** .+++++++ .B++++++ ..+++++++++
+ ** .+++++++ .B++++++ .++++++++++
+ ** ++++++++ B+++++++ .++++++++++
+ ** .++++++++++
+ ** +++++++++++
+ **
+ ** legend: . background, B border, + forground color
+ **/
+ $Top: {
+ 'y' : /* normal */
+ [ { margin: "5px", height: "1px", borderSide: "0", borderTop: "1px" }
+ , { margin: "3px", height: "1px", borderSide: "2px" }
+ , { margin: "2px", height: "1px", borderSide: "1px" }
+ , { margin: "1px", height: "2px", borderSide: "1px" }
+ ] ,
+ 's' : /* small */
+ [ { margin: "2px", height: "1px", borderSide: "0", borderTop: "1px" }
+ , { margin: "1px", height: "1px", borderSide: "1px" }
+ ] ,
+ 'b' : /* big */
+ [ { margin: "8px", height: "1px", borderSide: "0", borderTop: "1px" }
+ , { margin: "6px", height: "1px", borderSide: "2px" }
+ , { margin: "4px", height: "1px", borderSide: "1px" }
+ , { margin: "3px", height: "1px", borderSide: "1px" }
+ , { margin: "2px", height: "1px", borderSide: "1px" }
+ , { margin: "1px", height: "3px", borderSide: "1px" }
+ ]
+ },
+
+ /**
+ ** Usage:
+ ** RoundedCorners.register( "#header", ['yyyy', '00f000', '32cd32'] );
+ **/
+ $registry: {},
+ register: function(selector, parms){
+ this.$registry[selector] = parms;
+ return this;
+ },
+
+ render: function(page,name){
+ /* make reverse copies for bottom definitions */
+
+ this.$Bottom = {};
+ for(var i in this.$Top){
+ this.$Bottom[i] = this.$Top[i].slice(0).reverse();
+ }
+
+ for(var selector in this.$registry){ // CHECK NEEDED
+ var n = $$(selector),
+ p = this.$registry[selector];
+ this.exec(n, p[0], p[1], p[2], p[3]);
+ }
+
+ $ES('*[class^=roundedCorners]',page).each(function(el){
+ var p = el.className.split('-');
+ if(p.length >= 2) this.exec([el], p[1], p[2], p[3], p[4] );
+ },this);
+ },
+
+ exec: function(nodes, corners, color, borderColor, background){
+ corners = (corners || "yyyy") + 'nnnn';
+ color = new Color(color) || 'transparent';
+ borderColor = new Color(borderColor);
+ background = new Color(background);
+
+ var c = corners.split('');
+ /* c[0]=top-left; c[1]=top-right; c[2]=bottom-left; c[3]=bottom-right; */
+
+ nodes.each(function(n){
+ if( n.$passed ) return;
+
+ var top = this.addCorner(this.$Top, c[0], c[1], color, borderColor, n),
+ bottom = this.addCorner(this.$Bottom, c[2], c[3], color, borderColor, n);
+
+ if(top || bottom) {
+ this.addBody(n, color, borderColor);
+
+ if(top){
+ var p = n.getStyle('padding-top').toInt();
+ top.setStyle('margin-top', p-top.getChildren().length);
+ n.setStyle('padding-top',0);
+ top.injectTop(n);
+ }
+
+ if(bottom){
+ var p = n.getStyle('padding-bottom').toInt();
+ bottom.setStyle('margin-bottom', p-bottom.getChildren().length);
+ n.setStyle('padding-bottom',0);
+ n.adopt(bottom);
+ }
+ }
+ if(borderColor) n.setStyle('border','none');
+ n.$passed=true;
+ },this);
+ top=bottom=null;
+ },
+
+ getTemplate: function(template, corners){
+ var t = false;
+ if(corners != 'nn') for(var item in template){
+ if(corners.contains(item)){
+ t = template[item];
+ break;
+ }
+ }
+ return t;
+ },
+
+ addCorner: function(corner, left, right, color, border, n){
+
+ corner = this.getTemplate(corner, left+right);
+ if(!corner) return false;
+
+ var padl = n.getStyle('padding-left').toInt(),
+ padr = n.getStyle('padding-right').toInt();
+ var node = new Element('b',{'class':'roundedCorners','styles':{
+ 'display':'block',
+ 'margin-left':-1*padl,
+ 'margin-right':-1*padr
+ } });
+
+ corner.each(function(line){
+ var el = new Element('div', {'styles': {
+ 'height':line.height,
+ 'overflow':'hidden',
+ 'border-width':'0',
+ 'background-color':color.hex
+ } });
+
+ if(border.hex){
+ el.setStyles({'border-color':border.hex,'border-style':'solid'});
+
+ if(line.borderTop){
+ el.setStyles({'border-top-width':line.borderTop,'height':'0'});
+ }
+ }
+ if(left != 'n') el.setStyle('margin-left', line.margin);
+ if(right != 'n') el.setStyle('margin-right', line.margin);
+
+ if(border.hex){
+ el.setStyles({
+ 'border-left-width': (left == 'n') ? '1px': line.borderSide,
+ 'border-right-width': (right == 'n') ? '1px': line.borderSide
+ });
+ }
+ node.adopt(el);
+ });
+ return node;
+ },
+
+ // move all children of the node inside a DIV and set color and bordercolor
+ addBody: function(n, color, border){
+
+ var padl = n.getStyle('padding-left').toInt(),
+ padr = n.getStyle('padding-right').toInt();
+
+ var container = new Element('div',{'styles':{
+ 'overflow':'hidden',
+ 'margin-left':-1*padl,
+ 'margin-right':-1*padr,
+ 'padding-left':(padl==0) ? 4 : padl,
+ 'padding-right':(padr==0) ? 4 : padr,
+ 'background-color':color.hex
+ } }).wrapChildren(n);
+
+ if(border.hex){
+ //n.setStyles('border','');
+ var st = "1px solid " + border.hex
+ container.setStyles({'border-left':st, 'border-right': st });
+ }
+ }
+}
+Wiki.addPageRender(RoundedCorners);
+
+
+/**
+ ** 260 Wiki Tips:
+ **/
+var WikiTips =
+{
+ render: function(page,name) {
+ var tips = [];
+ $ES('*[class^=tip]',page).each( function(t){
+ var parms = t.className.split('-');
+ if( parms.length<=0 || parms[0] != 'tip' ) return;
+ t.className = "tip";
+
+ var body = new Element('span').wrapChildren(t).hide(),
+ caption = (parms[1]) ? parms[1].deCamelize(): "tip.default.title".localize();
+
+ tips.push(
+ new Element('span',{
+ 'class': 'tip-anchor',
+ 'title': caption + '::' + body.innerHTML
+ }).setHTML(caption).inject(t)
+ );
+ });
+ if( tips.length>0 ) new Tips( tips , {'className':'tip', 'Xfixed':true} );
+ }
+}
+Wiki.addPageRender(WikiTips);
+
+
+/**
+ ** 270 Wiki Columns
+ ** Dirk Frederickx, Mar 07
+ **/
+var WikiColumns =
+{
+ render: function(page,name) {
+ var tips = [];
+ $ES('*[class^=columns]',page).each( function(t){
+ var parms = t.className.split('-');
+ t.className='columns';
+ WikiColumns.buildColumns(t, parms[1] || 'auto');
+ });
+ },
+
+ buildColumns: function( el, width){
+ var breaks = $ES('hr',el);
+ if(!breaks || breaks.length==0) return;
+
+ var colCount = breaks.length+1;
+ width = (width=='auto') ? 98/colCount+'%' : width/colCount+'px';
+
+ var colDef = new Element('div',{'class':'col','styles':{'width':width}}),
+ col = colDef.clone().injectTop(el),
+ n;
+ while(n = col.nextSibling){
+ if(n.tagName && n.tagName.toLowerCase() == 'hr'){
+ col = colDef.clone();
+ $(n).replaceWith(col);
+ continue;
+ }
+ col.appendChild(n);
+ }
+ new Element('div',{'styles':{'clear':'both'}}).inject(el);
+ }
+}
+Wiki.addPageRender(WikiColumns);
+
+
+/* 300 Javascript Code Prettifier
+ * based on http://google-code-prettify.googlecode.com/svn/trunk/README.html
+ */
+var WikiPrettify = {
+ render: function(page,name){
+ var els = $ES('.prettify pre, .prettify code',page);
+ if(!els || els.length==0) return;
+ els.addClass('prettyprint');
+
+ //TODO: load assets .css and .js
+ //PRETTIFY: patch added to avoid processing of the same element
+ prettyPrint(page);
+ }
+}
+Wiki.addPageRender(WikiPrettify);