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

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

Added: jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Carousel.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Carousel.js?rev=1686927&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Carousel.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Carousel.js Mon Jun 22 20:11:42 2015
@@ -0,0 +1,342 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); fyou may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+/*
+Plugin: Viewer.Carousel
+    Viewer plugin for automatic cycling through elements.
+    Inspired on bootstrap"s implementation, relying on css3 transitions;
+    rewritten for mootools.
+
+Credit:
+    bootstrap-carousel.js v2.2.2 http://twitter.github.com/bootstrap/javascript.html#carousel
+
+Depends on:
+    Viewer
+
+DOM structure:
+
+    (start code)
+    div.carousel
+        a.xxx
+        a.xxx
+    (end)
+
+    becomes
+    (start code)
+    div.carousel[.slide]
+
+      ol.carousel-indicators
+        li.active[data-target="#myCarousel"][data-slide-to="0"]
+        li[data-target="#myCarousel"][data-slide-to="1"]
+        li[data-target="#myCarousel"][data-slide-to="2"]
+
+      <!-- Carousel items -->
+      div.carousel-inner
+        div.item.active
+          img | object | iframe
+        div.item
+          img | object | iframe
+        ...
+
+      <!-- Carousel nav -->
+      a.controls.prev[href="#myCarousel"][data-slide="prev"] &lt;
+      a.controls.next[href="#myCarousel"][data-slide="next"] &gt;
+    (end)
+
+Example:
+>    new Carousel(container, [el1, el2], {container:..., ...} );
+
+*/
+Viewer.Carousel = new Class({
+
+    Binds: ["build", "cycle", "stop", "next", "prev", "slid"],
+    Implements: [Events, Options],
+
+    options: {
+        cycle: 1e4, //=> when set, the carousel automatically cycles through all items
+        width: 400, // Default width of the carousel (in pixels)
+        height: 300 // Default height of the carousel (in pixels)
+    },
+
+    initialize: function(elements, options){
+
+        var self = this,
+            t = "transitionend";
+
+        options = self.setOptions(options).options;
+        //console.log("CAROUSEL Options: ", options);
+
+        self.css3 = Element.Events[t] ? t : null;
+        self.element = options.container;
+
+        Viewer.preloads( $$(elements), options, self.build );
+
+    },
+
+    build: function(elements, width, height){
+
+        var self = this,
+            items = [], indicators = [],
+            cycle = self.options.cycle,
+            NOP = function(){};
+
+
+
+        $$(elements).each( function(el){
+
+            items.push("div.item", [
+                el, { styles: {
+                    //add padding to center the item inside its container, but still fill 100% of the available space
+                    padding: Number(height - el.height).limit(0, height) / 2 + "px " +
+                             Number(width - el.width).limit(0, width) / 2 + "px"
+                }},
+                "div.carousel-caption", {
+                    html: (el.title || el.alt || el.get("text"))
+                }
+            ]);
+            indicators.push("li");
+        });
+        items[0] += ".active";
+        indicators[0] += ".active";
+
+        self.element.empty()
+            .set({
+                "class": "carousel",
+                //maxHeight,maxHeight will auto-scale the images if they are too big to fit
+                styles: { maxWidth: width, maxHeight: height },
+                events: {
+                    "click:relay(li)": function(){ self.to(this.getAllPrevious().length); },
+                    mouseenter: cycle ? self.stop : NOP,
+                    mouseleave: cycle ? self.cycle : NOP
+                }
+            })
+            .adopt([
+                "div.carousel-progress", /*ffs {"transitionDuration":self.cycle/1e3+"s"},*/
+                "ol.carousel-indicators",
+                    indicators,
+                "div.carousel-inner",
+                    items,
+                "a.controls.prev[html=&lt;]", {events: { click: self.prev }},
+                "a.controls.next[html=&gt;]", {events: { click: self.next }}
+                ].slick()
+            );
+
+        //self.cycle();  only start cycling after a first mouseenter , next()
+
+
+    },
+
+    get: function( selector ){
+        return this.element.getElements(selector);
+    },
+
+    /*
+    Function: cycle
+        Cycle through the carousel items.
+        - invoked on initialization
+        - invoked on mouseleave
+        - invokde at end of the sliding operations
+    */
+    cycle: function(/*event*/){
+
+        var self = this,
+            cycle = self.options.cycle;
+
+        if( cycle && !self.sliding ){
+            self.stop(); // make sure to first clear the tid
+            self.tid = self.next.delay( cycle );
+            self.element.addClass("sliding");
+        }
+
+    },
+
+    /*
+    Function: stop
+        Stop the autocycle mechanism.
+        - invoked on mouseenter
+        - invoked at start of the sliding operation
+    */
+    stop: function( /*event*/ ){
+
+        //console.log("stop ", this.tid, this.sliding, arguments);
+        clearTimeout( this.tid );
+        this.tid = null;
+        this.element.removeClass("sliding");
+
+    },
+
+    /*
+    Function: to
+        Slide directly to a specific carousel item.
+        Not yet used.
+    */
+    to: function( pos ){
+
+        var self = this,
+            items = self.get(".item"),
+            item = items[pos],
+            active = items.indexOf( items.filter(".active")[0] );
+
+        if ( !item ){ return; }
+
+        if( self.sliding ){
+
+            //console.log("concurrency betweeen slide() and pos() - wf "slid" event to occur");
+            self.element.addEvent("slid", self.to.pass(pos) );
+
+        } else if ( !item.match(".active") ){
+
+            self.slide( pos > active ? "next" : "prev", item );
+
+        }
+
+    },
+
+    next: function(){
+        if( !this.sliding ){ this.slide("next"); }
+    },
+
+    prev: function () {
+        if( !this.sliding ){ this.slide("prev"); }
+    },
+
+
+    /*
+    Function:slide
+        Move the carousel to the next item.
+        It fully relies on css3 transition.
+        If not supported, no animation-effects are applied (lazy me)
+
+    stable =>
+    >    .active  => left:0;
+    >    .next    => left:100%;
+    >    .prev    => left:-100%;
+
+    slide-type = next => Slide to left:
+    >    item.active.left   => left:-100%;
+    >    item.next.left     => left:0;
+
+    slide-type = prev => Slide to right:
+    >    item.active.right  => left:100%;
+    >    item.prev.right    => left:0;
+
+    Arguments
+        - type : "next","prev"
+        - next : element to be shown at end of the "slide" ( array )
+
+    */
+    slide: function(type, next){
+
+        var self = this,
+            active = self.get(".item.active")[0],
+            gonext = (type == "next"),
+            css3 = self.css3,
+            slid = self.slid;
+
+        self.sliding = true;
+        self.stop();
+
+        next = next ||
+            active[ gonext ? "getNext" : "getPrevious" ]() ||
+            active.getParent()[ gonext ? "getFirst" : "getLast" ]();
+
+        if( next.match(".active") ){ return; }
+
+        next.addClass( type ); //.next or .prev
+
+        self.fireEvent("slide");
+
+        if( css3 ){
+
+            //console.log("transition: "+css3)
+            next.offsetWidth; // force reflow -- is this really needed ?
+            $$(active, next).addClass( gonext ? "left" : "right" );
+            self.element.addEvent( css3, slid );
+
+        } else {
+
+            slid();
+
+        }
+
+    },
+
+    slid: function(){
+
+        var self = this,
+            items = self.get(".item"),
+            newActive = self.get(".item.next,.item.prev")[0];
+
+        if( newActive ){
+
+            items.set("class", "item");  //wipe out .active, .next, .prev, .left, .right
+            newActive.addClass("active");
+
+            self.get("li").set("class", "")[items.indexOf(newActive)].addClass("active");
+
+            self.sliding = false;
+            self.cycle();
+            self.fireEvent("slid", 0/*dummy*/, 1/*delay 1ms*/);
+
+        }
+
+    }
+
+});
+
+
+/*
+Extension : css3 native events
+    Extend mootools to support css3 native events
+    (needed by Viewer.Carousel)
+
+Credits:
+    Inspired by  https://github.com/amadeus/CSSEvents/
+
+Example:
+>    $(element).addEvent("transitionend",function(event){ ...})
+
+*/
+!function(css3){
+
+var B = Browser,
+    NativeEvents = Element.NativeEvents,
+    pfx = B.cssprefix = (B.safari || B.chrome || B.platform.ios) ? "webkit" : (B.opera) ? "o" : (B.ie) ? "ms" : "";
+
+    for ( style in css3 ){
+
+        var eventType = css3[style],
+            type = eventType.toLowerCase(),
+            aType = pfx ? pfx + eventType : type,
+            aTest = pfx ? pfx + style.capitalize() : style;
+
+        if( document.createElement("div").style[ aTest ] != null ){
+
+            NativeEvents[type] = NativeEvents[aType] = 2;
+            Element.Events[type] = { base: aType };
+
+        }
+
+        //console.log(Element.NativeEvents, Element.Events);
+
+    }
+
+}({transition: "TransitionEnd"});
+//})({transition:"TransitionStart",transition:"TransitionEnd",animation:"AnimationStart",animation:"AnimationIteration",animation:"AnimationEnd");

Added: jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Slimbox.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Slimbox.js?rev=1686927&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Slimbox.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.Slimbox.js Mon Jun 22 20:11:42 2015
@@ -0,0 +1,311 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); fyou may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+/*
+Plugin: Viewer.Slimbox
+
+    Slimbox clone, refactored for JSPWiki.
+    Added support for iframes, flash video.
+    Todo: html5 video.
+
+Credits:
+    Inspired by Slimbox by Christophe Bleys, (see http://www.digitalia.be/software/slimbox)
+    the mediaboxAdvanced by John Einselen (see http://iaian7.com/webcode/mediaboxAdvanced)
+    and the diabox by Mike Nelson. (see https://github.com/mnelson/diabox)
+
+DOM structure:
+    DOM structure of the JSPWiki Slimbox viewer.
+    (start code)
+    div#slmbx
+        div.modal               //semi transparent screen overlay
+        div.viewport(.spin)     //img, object or iframe element is inserted here
+            a.controls.caption
+            a.controls.next
+            a.controls.prev
+            a.controls.close
+    (end)
+*/
+Viewer.Slimbox = new Class({
+
+    Implements: Options,
+    Binds: ["attach", "key", "update", "resize"],
+
+    options: {
+        loop: true,  // (boolean) affects next/prev at last/first element
+        width: 800,  // (int px) default width of the box
+        height: 600, // (int px) default height of the box
+        hints: {     // default controls
+            btn: "Click to view {0}",
+            close: "&times;",
+            next: "&gt;",  //&#171;  Next
+            prev: "&lt;",  //&#187;  Previous
+            nofm: "[{0}/{1}]",              //[page/#pages]
+            size: " ({0}px &times; {1}px)",  // (height x width)
+            caption: " Go to {0}"
+        },
+        keys: {
+            close: ["esc", "x", "c"],
+            prev: ["left", "up", "p"],
+            next: ["enter", "space", "right", "down", "n"]
+        }
+    },
+
+    initialize: function(options){
+
+        var self = this.setOptions(options),
+            hints = self.options.hints,
+            controls = "a.controls.";
+
+        //helper function
+        function clickFn(){
+            if( this.match(".next")){ self.update(1); }
+            else if( this.match(".prev")){ self.update(-1); }
+            else { self.attach( /*O=close*/ ); }
+        }
+
+        $(document.body).grab([
+            "div.slmbx", { attach: self }, [
+                "div.slmodal", { events: { click: clickFn } },
+                "div.viewport", { attach: [self, "viewport"], events: { "click:relay(a)": clickFn } }, [
+                    //insert viewable iframe/object/img ...
+                    controls + "caption",
+                    controls + "next", { html: hints.next },
+                    controls + "prev", { html: hints.prev },
+                    controls + "close", { html: hints.close }
+                ]
+            ]
+        ].slick());
+
+    },
+
+    /*
+    Function: get
+        Retrieve DOM elements inside the slimbox container, based on a css selector.
+    Example:
+    >    this.get("a.next");
+    */
+    get: function( selector ){
+
+        return this.element.getElement(selector);
+
+    },
+
+    /*
+    Function: match
+        Check if the URL is recognized as a viewable object/image/html...
+    */
+    match: function(url){
+
+        return Viewer.match(url, this.options);
+
+    },
+
+    /*
+    Function: watch
+        Install click handlers on a group of images/objects/media links,
+        and optionally add slimbox click-buttons.
+
+    Arguments:
+        elements - set of DOM elements
+        btn - (optional) slick selector to insert a slimbox button after each viewable link
+    Returns
+        set of DOM elements viewable via Slimbox
+    Example
+    >   TheSlimbox.watch( $$(".slimbox a","a.slimbox-btn");
+
+    */
+    watch: function(elements, btn){
+
+        var self = this, caption;
+
+        elements = $$(elements).filter( function(el){
+            return self.match( el.src || el.href );
+        });
+
+        return elements.each( function(el, idx){
+
+            caption = el.get("text") || el.title || el.alt;
+
+            if( btn ){
+                el = btn.slick({
+                    href: el.src || el.href,
+                    title: self.options.hints.btn.xsubs(caption)
+                }).inject(el, "after");
+            }
+
+            el.addEvent("click", function(ev){ ev.stop(); self.show(elements, idx); });
+
+        });
+
+    },
+
+
+    /*
+    Function: show
+        Start the image/media viewer for a set of elements.
+    Arguments
+        elements - set of DOM elements to be viewed
+        cursor - index of first items to be viewed
+    */
+    show: function( elements, cursor ){
+
+        var self = this;
+        self.elements = elements;
+        self.cursor = cursor;
+        self.attach( 1 /*true*/ );
+        self.update( 0 );
+
+    },
+
+    /*
+    Function: attach
+        Attach or de-tach eventhandlers from the slimbox dialogs.
+        Display or hide the modal and viewport. (css class .show)
+    */
+    attach: function( open ){
+
+        var self = this,
+            fn = open ? "addEvent" : "removeEvent";
+
+        ["object", Browser.ie6 ? "select" : "embed"].each(function(tag) {
+            $$(tag).each( function(el){
+                if( open ){ el._slimbox = el.style.visibility; }
+                el.style.visibility = open ? "hidden" : el._slimbox;
+            });
+        });
+
+        self.element.ifClass(open, "active");
+        self.reset();
+
+        document[fn]("keydown", self.key); //checkme: support arrow keys, etc.
+
+    },
+
+    reset: function(){
+
+        this.viewport.getElements(":not(.controls)").destroy();
+        this.preload = null;
+
+    },
+
+    /*
+    Function: key
+        Handle keystrokes.
+    */
+    key: function( event ){
+
+        var self = this,
+            keys = self.options.keys,
+            key = event.key;
+
+        //console.log("keydown ", key);
+        keys.close.contains(key) ? self.attach(/*O=close*/) :
+            keys.next.contains(key) ? self.update(1) :
+                keys.prev.contains(key) ? self.update(-1) :
+                    /*otherwise*/ key = 0;
+
+        if(key){ event.stop(); }
+
+    },
+
+    /*
+    Function: update
+        Updates the viewport and the controls with caption, next and previous links.
+        Implements cursor loop-around logic.
+
+    Arguments:
+        increment - move the cursor by increment, and display the new content
+    */
+    update: function( increment ){
+
+        var self = this,
+            options = self.options,
+            hints = options.hints,
+            elements = self.elements,
+
+            max = elements.length,
+            many = max > 1,
+
+            incr = function(num){
+                return options.loop ? (num >= max) ? 0 : (num < 0) ? max - 1 : num : num;
+            },
+            cursor = incr( self.cursor + increment ).limit( 0, max - 1 ), //new cursor value
+
+            el, url;
+
+        if( increment != 0 && (cursor == self.cursor)){ return; }
+
+        self.cursor = cursor;
+        self.get(".prev")[ (many && (incr(cursor - 1) >= 0 )) ? "show" : "hide"]();
+        self.get(".next")[ (many && (incr(cursor + 1) < max)) ? "show" : "hide"]();
+
+        el = elements[cursor];
+        url = el.href || el.src; //url = encodeURIComponent(url);
+
+        self.get(".caption").set({
+            href: url,
+            html: ( many ? hints.nofm.xsubs( cursor + 1, max)  : "" ) +
+                    hints.caption.xsubs( el.title || el.alt || el.get("text")/*||""*/)
+        });
+
+        self.viewport.addClass("loading");
+        //if( self.preload ){ self.preload.destroy(); self.preload = null;}
+        self.reset();
+        //alert("wait");
+        Viewer.preload( url, options, self.resize );
+
+    },
+
+    /*
+    Function: resize
+        Completes the resizing of the viewport, after loading the img, iframe or object.
+    */
+    resize: function( preload ){
+
+        var self = this,
+            isImage = preload.match("img"),
+            viewport = self.viewport,
+
+            wSize = window.getSize(),
+            width = preload.width.toInt().limit( 240, 0.9 * wSize.x ).toInt(),
+            height = preload.height.toInt().min( 0.9 * wSize.y ).toInt(),
+            caption = self.get(".caption");
+
+        self.preload = preload;
+
+        //append viewport dimensions in px to the caption
+        caption.set("html", caption.get("html") + self.options.hints.size.xsubs(width, height) );
+
+        // viewport has css set to { top:50%, left:50% } for automatic centered positioning
+        viewport
+            .removeClass("loading")
+            .setStyles({
+                backgroundImage: isImage ? "url(" + preload.src + ")" : "none",
+                //rely on css3 transitions... iso mootools morph
+                width: width, height: height, marginTop: -height / 2, marginLeft: -width / 2
+            });
+            //mootools transition, in case css3 would not be available
+            //.morph({ width:width, height:height, marginTop:-height/2, marginLeft:-width/2 });
+
+        if( !isImage ){ viewport.grab( preload ); }//now include the viewer in the dom
+
+    }
+
+});

Added: jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.js?rev=1686927&view=auto
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.js (added)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/behaviors/Viewer.js Mon Jun 22 20:11:42 2015
@@ -0,0 +1,325 @@
+/*
+    JSPWiki - a JSP-based WikiWiki clone.
+
+    Licensed to the Apache Software Foundation (ASF) under one
+    or more contributor license agreements.  See the NOTICE file
+    distributed with this work for additional information
+    regarding copyright ownership.  The ASF licenses this file
+    to you under the Apache License, Version 2.0 (the
+    "License"); fyou may not use this file except in compliance
+    with the License.  You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing,
+    software distributed under the License is distributed on an
+    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+    KIND, either express or implied.  See the License for the
+    specific language governing permissions and limitations
+    under the License.
+*/
+/*
+Viewer object
+    match(url,options): function to retrieve the media parms based on a url
+    preload(url,options,callback): preloads (created DOM object) the correct viewer
+        with the correct rendering paramaters (eg: used by Viewer.Slimbox)
+    preloads(elements,options,callback): preloads a set of viewer objects,
+        and calculates the minimals viewer-box dimensions (eg: used by Viewer.Carousel)
+
+    LIB: data-array of pairs [["re1",{parms1}],["re2",{parms2}],..]
+        used by match() and preload() to identify the correct viewer & parameters.
+        This array can be customised and extended.
+
+        regexp - (string) match against the url
+        parms - (function or object) returns the viewer parameters
+            "img" - to be rendered as IMG, directly in the browser
+            "url" - to be rendered as OBJECT (eg flash)
+            "src" - to be rendered as IFRAME
+            other-parameters with additional details
+*/
+!function(){
+
+this.Viewer = {
+
+    LIB: [],
+
+    match: function(url, options){
+
+        var result = {};
+
+        if( typeOf(url) == "element" ){ url = url.src || url.href; }
+
+        this.LIB.some( function(item){
+
+            return url.test( item[0], "i" )
+                //item[1] can be a value or a function(url,options)
+                && (result = Function.from(item[1])(url, options) );
+
+        });
+
+        //options.type = "img"|"url"|"src"
+        //options.type = "img";
+        //console.log(options.type);
+        if( options.type && !result[options.type] ){ return false; }
+
+
+        return result;
+    },
+
+
+    preload: function(element, options, callback ){
+
+        var match = this.match(element, options),
+            preload;
+
+        function done(){
+            //console.log( match.width, preload.width.toInt(), match.height, preload.height.toInt(), preload);
+            if( callback ){ callback( preload, preload.width.toInt(), preload.height.toInt() ); }
+        }
+
+        options = {
+            id: "VIEW." + String.uniqueID(),
+            width: options.width,
+            height: options.height
+        };
+
+        if( match.img ){
+
+            preload = new Image();
+            preload.onload = done;  //delayed onload to know height&width of the image
+            preload.alt = element.alt;
+            //preload.title = element.title;
+            preload.src = match.img;
+
+        } else {
+
+            //ffs: add branch for html5 enabled browsers & html5 enabled video sources
+            //if( match.url5 ) ...
+            if( match.url ){
+
+                preload = $(new Swiff( match.url, Object.merge(options, {
+                    params: {
+                        wmode: "transparent",//"opaque", //"direct",
+                        //bgcolor: "#FFFFFF",
+                        allowfullscreen: "true",
+                        allowscriptaccess: "always"
+                    }
+                }, match ) ) );
+
+            } else if( match.src ){
+
+                preload = new IFrame( Object.merge( options, match, { frameborder: 0 }));
+                //The actual loading starts only when the iframe gets added to the dom
+                //By default, the iframe is hidden during loading. (see Viewer.less)
+                document.body.adopt(preload);
+
+            } else {
+
+                preload = new Element("p.error[html=\"Error\"]");
+
+            }
+
+            done.delay(1); //sniff callback
+
+        }
+        //console.log("PRELOAD ", typeOf( preload ), preload );
+
+    },
+
+    preloads: function(elements, options, callback){
+
+        var countdown = elements.length, //counting the preloaded objects !
+            preloads = [],
+            w = options.width,
+            h = options.height;
+
+        function preloadCallback(preload, width, height){
+                preloads.push( preload );
+                w = w.max(width);
+                h = h.max(height.toInt());
+                //console.log("preloads.length, w,h);
+                if( !--countdown && callback ){ callback( preloads, w, h ); }
+        }
+
+        if( !countdown ){ return this.preload(elements, options, callback); }
+
+        while( elements[0] ){
+
+            this.preload( elements.shift(), options, preloadCallback);
+
+        }
+
+    }
+
+};
+
+var AdobeFlashPlayer = "clsid:D27CDB6E-AE6D-11cf-96B8-444553540000";
+
+Viewer.LIB.append([
+
+    [".(bmp|gif|png|jpg|jpeg|tiff)$", function(url){
+        return { img: url };
+    }],
+
+    //google viewer for common formats
+    [".(tiff|pdf|doc|docx|xls|xlsx|ppt|pptx|zip|rar)$", function(url){
+        return {
+            src: "http://docs.google.com/viewer?embedded=true&url=" + encodeURIComponent(url), //url,
+            width: 850,
+            height: 500
+        };
+    }],
+
+    //google maps
+    //FIXME
+    ["^https?://maps.google.com/maps?", function(url){
+
+        //href="https://maps.google.com/maps?q=Atomium,%20City%20of%20Brussels,%20Belgium&amp;output=embed"
+        return {
+            src: url + "&output=embed",
+            //src: url.replace("maps?","maps/embed?"),
+            //src: url.replace("maps.google.com/maps?q=","www.google.com/maps/embed?pb="),
+            width: 850,
+            height: 500
+        };
+
+    }],
+
+    ["^https?://www.google.com/maps/place/", function(url){
+
+        //href=https://www.google.com/maps/place/Atomium/@50.894941,4.341547,17z/data=!3m1!4b1!4m2!3m1!1s0x0:0x5293071d68a63709?hl=en-US
+        return {
+            src: url.replace("www.google.com/maps/place/", "/maps.google.com/maps?q=") + "&output=embed",
+            width: 850,
+            height: 500
+        };
+
+    }],
+
+    //add some mp3/audio player here
+
+    ["facebook.com", function(url){
+          url = "http://www.facebook.com/v/" + url.split("v=")[1].split("&")[0];
+          return {
+            url: url,
+            movie: url,
+            classid: AdobeFlashPlayer,
+            width: 756, //320,
+            height: 424 //240
+        };
+    }],
+
+    ["flickr.com", function(url){
+        return {
+            url: "http://www.flickr.com/apps/video/stewart.swf",
+            classid: AdobeFlashPlayer,
+            width: 500,
+            height: 375,
+            params: {flashvars: "photo_id=" + url.split("/")[5] + "&amp;show_info_box=true" }
+        };
+    }],
+
+    ["youtube.com/watch", function(url){
+        return {
+            //src: "http://www.youtube.com/embed/"+url.split("v=")[1],
+            url: "http://www.youtube.com/v/" + url.split("v=")[1],
+            width: 640,
+            height: 385  //385
+        };
+    }],
+
+    //youtube playlist
+    ["youtube.com/view", function(url){
+        return {
+            url: "http://www.youtube.com/p/" + url.split("p=")[1],
+            width: 480,
+            height: 385
+        };
+    }],
+
+    ["dailymotion.com", function(url){
+        return {
+            src: "http://www.dailymotion.com/embed/video/" + url.split("/")[4].split("_")[0],
+            //url:url,
+            width: 480,
+            height: 270 //381
+        };
+    }],
+
+    ["metacafe.com/watch", function(url){
+        //http://www.metacafe.com/watch/<id>/<title>/ => http://www.metacafe.com/fplayer/<id>/<title>.swf
+        return {
+            url: "http://www.metacafe.com/fplayer/" + url.split("/")[4] + "/.swf?playerVars=autoPlay=no",
+            //url:"http://www.metacafe.com/fplayer/" + url.split("watch/")[1].slice(0,-1) +".swf?playerVars=autoPlay=no",
+            width: 400,        //540    600
+            height: 350        //304    338
+        };
+    }],
+
+    ["vids.myspace.com", function(url){
+        return {
+            url: url,
+            width: 425,        //540    600
+            height: 360        //304    338
+        };
+    }],
+
+    ["veoh.com/watch/", function(url){
+        //url: "http://www.veoh.com/static/swf/webplayer/WebPlayer.swf?version=AFrontend.5.5.2.1001&permalinkId="+url.split("watch/")[1]+"&player=videodetailsembedded&videoAutoPlay=false&id=anonymous",
+        return {
+            url: "http://www.veoh.com/veohplayer.swf?permalinkId=" + url.split("watch/")[1] + "&player=videodetailsembedded&videoAutoPlay=false&id=anonymous",
+            width: 410,
+            height: 341
+        };
+    }],
+
+
+    ["https?://www.ted.com/talks/", function(url){
+    //http://www.ted.com/talks/doris_kim_sung_metal_that_breathes.html
+    //<iframe src="http://embed.ted.com/talks/doris_kim_sung_metal_that_breathes.html" width="560" height="315" frameborder="0" scrolling="no" webkitallowfullscreen="" mozallowfullscreen="" allowfullscreen=""></iframe>
+        return {
+            src: "http://embed.ted.com/talks/" + url.split("/")[4],
+            width: 853, //640, //560,
+            height: 480, //360, //315
+            scrolling: "no"
+        };
+    }],
+
+    ["viddler.com/", function(url){
+        return {
+            url: url,
+            classid: AdobeFlashPlayer,
+            width: 545, //437,
+            height: 451, //370,
+            params: {id: "viddler_" + url.split("/")[4], movie: url }
+        };
+    }],
+
+    ["http://vimeo.com/", function(url){
+        return {
+            //html5 compatible --- use iframe
+            //src: "http://player.vimeo.com/video/" + url.split("/")[3],
+            url: "http://www.vimeo.com/moogaloop.swf?server=www.vimeo.com&amp;clip_id=" + url.split("/")[3],
+            width: 640,
+            height: 360
+        };
+    }],
+
+    ["http://jsfiddle.net/", function(url){
+        return {
+            src: url + "embedded/",
+            width: 800,
+            height: 250
+        };
+    }],
+
+    ["https?://", function(url){
+        return {
+            //default : catch iframe urls ; allow scrolling of eg external site"s
+            src: url
+        };
+    }]
+
+]);
+
+}();

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Buttons.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Buttons.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Buttons.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Buttons.js Mon Jun 22 20:11:42 2015
@@ -32,7 +32,7 @@ Dialog.Buttons = new Class({
 	initialize: function(options){
 
         this.setClass('.buttons',options);
-        console.log("Dialog.Buttons",options);
+        //console.log("Dialog.Buttons",options);
 		this.parent(options);
 		this.setButtons( this.options.buttons );
 
@@ -46,7 +46,7 @@ Dialog.Buttons = new Class({
 	Example:
 		(start code)
 			myDialog.setButtons(['Ok','Cancel']);
-			
+
 			//FIXME???
 			myDialog.setButtons({
 				Ok:function(){ callback( input.get('value') ); },
@@ -61,7 +61,7 @@ Dialog.Buttons = new Class({
 
 		btns.empty().adopt( buttons.map(function(b){
 
-			return 'a.btn.btn-link.btn-sm'.slick({
+			return 'a.btn.btn-default.btn-sm'.slick({
 				html: b.localize(),
 				events:{ click: self.action.bind(self,b) }
 			});

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Chars.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Chars.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Chars.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Chars.js Mon Jun 22 20:11:42 2015
@@ -35,48 +35,45 @@ Inherits from:
 Dialog.Chars = new Class({
 
 	Extends: Dialog.Selection,
-	
+
 	options: {
 		//onAction: function(value){},
-		items: '.body td',
 		chars: [
-			'nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf',
-			'laquo|not|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para',
-			'middot|cedil|sup1|ordm|raquo|frac14|frac12|frac34|iquest|times|divide',
-			'Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc',
-			'Euml|Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde',
-			'Ouml|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|aacute',
-			'acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave',
-			'iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|oslash',
-			'ugrave|uacute|ucirc|uuml|thorn|yuml|OElig|oelig|Scaron|scaron|Yuml',
-			'ndash|mdash|lsquo|rsquo|ldquo|rdquo|dagger|Dagger|bull|hellip|permil',
-			'euro|trade|larr|uarr|rarr|darr|harr|crarr|loz|diams|infin'
+
+			'lsquo|rsquo|ldquo|rdquo|lsaquo|rsaquo|laquo|raquo|apos|quot|sbquo|bdquo',
+			'ndash|mdash|sect|para|dagger|Dagger|amp|lt|gt|copy|reg|trade',
+			'rarr|rArr|bull|middot|deg|plusmn|brvbar|times|divide|frac14|frac12|frac34',
+			'hellip|micro|cent|pound|euro|iquest|iexcl|uml|acute|cedil|circ|tilde',
+			'Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml',
+			'Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|Oslash',
+			'OElig|Scaron|Ugrave|Uacute|Ucirc|Uuml|Yacute|Yuml|THORN|szlig|agrave|aacute',
+			'acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave|iacute',
+			'icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|oslash|oelig|scaron',
+			'ugrave|uacute|ucirc|uuml|yacute|yuml|thorn|ordf|ordm|alpha|Omega|infin',
+		    'not|sup2|sup3|permil|larr|uarr|darr|harr|hArr|crarr|loz|diams'
 		]
 	},
 
 	initialize:function(options){
 
         this.setClass('.chars',options);
-        //options.cssClass = '.chars'+(options.cssClass||'')
 		this.parent(options);
 
 	},
 
 	setBody: function(){
 
-		/* inspired by smarkup */
-		var content = this.options.chars.map(function(line){
-
-			return '<tr>' +
-				line.split('|').map(function(c){
-					return '<td title="&amp;'+ c + ';">&'+ c + ';</td>';
-				}).join('') + '</tr>';
+        var rows = [];
+		this.options.chars.map( function(line){
+		    var cells = [];
+		    line.split('|').each( function(item){
+    			cells.push( 'td.item[title=&'+item+';]', {html:'&'+item+';'});
+		    });
+		    rows.push('tr',cells);
 
 		});
+		return this.parent( ['table',rows].slick() );
 
-		return this.parent( 
-		    'table'.slick({ html: '<tbody>'+content.join('')+'</tbody>' }) 
-		);
 	}
 
 });

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Color.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Color.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Color.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Color.js Mon Jun 22 20:11:42 2015
@@ -35,11 +35,11 @@ Example:
 	(start code)
 	<script>
 		var cd = new Dialog.Color( {
-			relativeTo: $('colorButton'),
-			wheelImage:'circle.png',
-			onChange:function(color){ $('mytarget').setStyle('background',color); }
+			relativeTo: $("colorButton"),
+			wheelImage:"circle.png",
+			onChange:function(color){ $("mytarget").setStyle("background",color); }
 		});
-		$('colorButton').addEvent('click', cd.toggle.bind(cd));
+		$("colorButton").addEvent("click", cd.toggle.bind(cd));
 	</script>
 	(end code)
 */
@@ -51,10 +51,10 @@ Dialog.Color = new Class({
 		//onAction: function(color){},
 		//onDrag: function(color){},
 		//onResize: function(){},
-		color:'#ffffff', //initial color
-		//buttons:['Done'],
+		color:"#ffffff", //initial color
+		//buttons:["Done"],
 		//colors: [],  //todo: colors array with predef pallette
-		//colorImage: 'scripts-dev/main/src/styles/generated-css/images/circle-256.png',
+		//colorImage: "scripts-dev/main/src/styles/generated-css/images/circle-256.png",
 		resize:{x:[96,256]}  //min/max limits for the resizer
 	},
 
@@ -65,26 +65,26 @@ Dialog.Color = new Class({
 			showNow = options.showNow,
 			setHSV = self.setHSV.bind(this);
 
-        //options.cssClass = '.color'+(options.cssClass||'')
-        this.setClass('.color',options);
+        this.setClass(".color",options);
 
-		options.caption = 'span.color'.slick();
+		options.caption = "span.color".slick();
 		options.body = [
-			'div.cursor',
-			'div.zone' //img = 'img'.slick({'src':options.colorImage||self.options.colorImage})
+			"div.cursor",
+			"div.zone" //img = "img".slick({"src":options.colorImage||self.options.colorImage})
 		].slick();
+
         cursor = self.cursor = options.body[0];
 
 		options.showNow =false;
 		self.parent(options);
-		
-/*		body = self.get('.body').makeResizable({
-			handle: 'div.resize'.slick().inject(self.element),
+
+/*		body = self.get(".body").makeResizable({
+			handle: "div.resize".slick().inject(self.element),
 			limit: self.options.resize,
 			onDrag: function(){ self.resize(this.value.now.x); }
 		});
 */
-        
+
 		new Drag(cursor,{
 			handle:cursor.getNext(),
 			style:false,
@@ -102,14 +102,14 @@ Dialog.Color = new Class({
 
 		color = (color||this.options.color).hexToRgb(true) || [255,255,255];
 		this.hsv = color.rgb2hsv();
-		//console.log(color+" "+this.hsv);
+		//console.log("Dialog.Color setValue() ",color+" "+this.hsv, this.hsv.hsv2rgb() );
 		return this.moveCursor();
 
 	},
 
 	/*
 	Function: resize
-		Resize the dialog body and fire the 'resize' event.
+		Resize the dialog body and fire the "resize" event.
 		Only use one dimension to ensure a square color box
 
 	Arguments:
@@ -118,9 +118,9 @@ Dialog.Color = new Class({
 	/*
 	resize: function( width ){
 
-		this.get('.body').setStyles({height:width, width:width});
+		this.get(".body").setStyles({height:width, width:width});
 		this.moveCursor( );
-		this.fireEvent('resize');
+		this.fireEvent("resize");
 
 	},
     */
@@ -129,16 +129,16 @@ Dialog.Color = new Class({
 	Function: setHSV
 		Recalculate the HSV-color based on x/y mouse coordinates.
 		After recalculation, the color-wheel cursor is repositioned
-		and the 'onChange' event is fired.
+		and the "onChange" event is fired.
 
 	Arguments:
 		cursor - DOM element
-		e - mouse drag event's
+		e - mouse drag event"s
 	*/
 	setHSV: function( cursor, e ){
 
 		var self = this,
-			body = self.get('.body').getCoordinates(),
+			body = self.get(".body").getCoordinates(),
 			v = [e.page.x - body.left, e.page.y - body.top],
 			W = body.width,
 			W2 = W/2,
@@ -155,7 +155,7 @@ Dialog.Color = new Class({
 			];
 
 		self.moveCursor( );
-		self.fireEvent('drag', self.getHex() );
+		self.fireEvent("drag", self.getHex() );
 
 	},
 
@@ -183,11 +183,11 @@ Dialog.Color = new Class({
 		var self = this,
 			hsv = self.hsv,
 			hex = self.getHex(),
-			w2 = self.get('.body').getSize().x/2,
+			w2 = self.get(".body").getSize().x/2,
 			radius = (hsv[0] / 360) * (Math.PI*2),
 			hypothenuse = (hsv[1] + (100-hsv[2])) / 100*(w2/2);
 
-		self.get('.color').set({
+		self.get(".color").set({
 			html: hex,
 			styles: {
 				color: new Color(hex).invert().hex,

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Find.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Find.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Find.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Find.js Mon Jun 22 20:11:42 2015
@@ -20,11 +20,11 @@
 */
 /*
 Function: Dialog.Find
-	Perform the find and replace operation on either the full textarea
-	or the selection of the textarea. It supports
-	regular expressions, case-(in)sensitive replace and global replace.
-	This is an event handler, typically linked with the submit button of the
-	find and replace dialog.
+    Perform the find and replace operation on either the full textarea
+    or the selection of the textarea. It supports
+    regular expressions, case-(in)sensitive replace and global replace.
+    This is an event handler, typically linked with the submit button of the
+    find and replace dialog.
 
 Arguments:
 
@@ -33,131 +33,139 @@ DOM-structure:
 */
 Dialog.Find = new Class({
 
-	Extends: Dialog,
-    Binds: ['find','replace'],
+    Extends: Dialog,
+    Binds: ["find", "replace"],
 
-	options: {
-	
-		//dialog: mandatory DOM element, caption and body are not allowed
-		draggable:true,
-		controls:{
-			f:  '[name=tbFIND]',
-			r:  '[name=tbREPLACE]',
-			h:  '.tbHITS', 
-			re: '[name=tbREGEXP]',
-			i:  '[name=tbMatchCASE]',
-			one:'[name=replace]',
-			all:'[name=replaceall]'
-		},
-		data:{
-			get:function(){},
-			set:function(){}
-		}
-	},
-
-	initialize:function(options){
-
-		var self = this.setOptions(options), 
-		    dialog = self.options.dialog,
-			controls; 
-
-        this.setClass('.find',options);
-
-		//convert to $(elements)
-		controls = self.controls = Object.map( self.options.controls, function(el){
-			return dialog.getElement(el);
-		});
-
-		self.parent( options );
-		
-		console.log("Dialog.Find initialize:",controls);
-		
-		controls.f.addEvents({ 
-		    keyup: self.find, 
-		    focus: self.find
-		});
-		dialog.addEvents({
-		    'change:relay([type=checkbox])': function(){ controls.f.focus(); } ,
-		    'click:relay(button)': self.replace  		
-		}); 
-
-	},
-
-	show: function(){
-		//1. make sure the find controls are visible
-		this.parent();
-		//2. focus the find input field, and auto-trigger find()
-		this.controls.f.focus();
-	},
-
-	// keypress, focus
-	find: function(){
-
-		var self = this,
-			controls = self.controls,
-			find = controls.f,
-			hits = controls.h,
-			findText = find.value,
-			result = '';
-
-		if( findText != '' ){
-
-			result = self.buildRE( findText );
-			if( typeOf(result)=='regexp' ){
-				result = self.options.data.get().match( self.buildRE(findText,true) );
-				if(result){ result = result.length; }
-			}
-
-		}
-
-		if( hits ){ hits.set('html',result); }
-		
-		controls.r.ifClass(!result,'disabled');		
-		controls.one.ifClass(!result,'disabled');		
-		controls.all.ifClass(!result,'disabled');
-		//TODO : one,all should remain disabled until r has content ..	
-			
-		find.focus();
-	},
-
-	// click replace or replace-all button
-	replace: function(e){
-
-		var self = this,
-			controls = self.controls,
-			replace = controls.r,
-			find = controls.f,
-			data = self.options.data;
-		
-		data.set(
-			data.get().replace(
-				self.buildRE(find.value, e.target == controls.all), 
-				replace ? replace.value : ''
-			)
-		);
-		find.focus();
-	},
-
-	buildRE: function( findText, global ){
-
-		var controls = this.controls,
-			isRegExp = controls.re && controls.re.checked,
-			reGlobal = global ? 'g':'',
-			reMatchCase	= (controls.i && controls.i.checked) ? '':'i';
-
-		try {
-		
-			return RegExp(
-				isRegExp ? findText : findText.escapeRegExp(),
-				reGlobal + reMatchCase + 'm'
-			);
+    options: {
 
-		} catch(e){
+        //dialog: (mandatory) DOM element, caption and body are not allowed
+        draggable: true,
+        controls: {
+            f: "[name=tbFIND]",
+            r: "[name=tbREPLACE]",
+            h: ".tbHITS",
+            re: "[name=tbREGEXP]",
+            i: "[name=tbMatchCASE]",
+            one: "[name=replace]",
+            all: "[name=replaceall]"
+        },
+        data: {
+            get: function(){},
+            set: function(){}
+        }
+    },
 
-			return "<span title='" + e + "'>!#@</span>";
+    initialize: function(options){
 
-		}
+        var self = this.setOptions(options),
+            dialog = self.options.dialog,
+            controls;
 
-	}
+        this.setClass(".find", options);
+
+        //convert to $(elements)
+        controls = self.controls = Object.map( self.options.controls, function(el){
+
+            return dialog.getElement(el);
+        });
+
+        self.parent( options );
+
+        controls.f.addEvents({
+            keyup: self.find,
+            focus: self.find
+        });
+
+        dialog.addEvents({
+            "change:relay([type=checkbox])": function(){ controls.f.focus(); },
+            "click:relay(button)": self.replace
+        });
+
+    },
+
+    show: function(){
+        //1. make sure the find controls are visible
+        this.parent();
+        //2. focus the find input field, and auto-trigger find()
+        this.controls.f.focus();
+    },
+
+    // keypress, focus
+    find: function(){
+
+        var self = this,
+            controls = self.controls,
+            findText = controls.f.value,
+            result,
+            setter,
+            disabled = "disabled";
+
+        if( findText != "" ){
+
+            result = self.buildRE( findText );
+
+            if (result instanceof RegExp){
+
+                result = self.options.data.get().match( self.buildRE(findText, true) );
+                if( result ){ result = result.length; }
+
+            }
+
+        }
+
+        if( controls.h ){ controls.h.innerHTML = result || ""; }
+
+        setter = /*isNumber?*/ +result ? "erase" : "set";
+        controls.r[setter](disabled, disabled);
+        controls.one[setter](disabled, disabled);
+        controls.all[setter](disabled, disabled);
+
+        controls.f.focus();
+    },
+
+    // click replace or replace-all button
+    replace: function(e){
+
+        var self = this,
+            controls = self.controls,
+            replace = controls.r,
+            find = controls.f,
+            data = self.options.data;
+
+        data.set(
+
+            data.get().replace(
+
+                self.buildRE(find.value, e.target == controls.all),
+
+                replace ? replace.value : ""
+            )
+        );
+
+        find.focus();
+    },
+
+
+    buildRE: function( findText, global ){
+
+        var controls = this.controls,
+            isRegExp = controls.re && controls.re.checked,
+            reGlobal = global ? "g" : "",
+            reMatchCase = ( controls.i && controls.i.checked ) ? "" : "i";
+
+        try {
+
+            return RegExp(
+                isRegExp ? findText : findText.escapeRegExp(),
+                reGlobal + reMatchCase + "m"
+            );
+
+        } catch(e){
+
+            return "<span title='" + e + "'>!#@</span>";
+
+        }
+
+    }
 
 });

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Font.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Font.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Font.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Font.js Mon Jun 22 20:11:42 2015
@@ -45,7 +45,7 @@ Example
 Dialog.Font = new Class({
 
 	Extends:Dialog.Selection,
-	
+
 	options: {
 		fonts: {
 			'arial':'Arial',
@@ -54,6 +54,7 @@ Dialog.Font = new Class({
 			'garamond':'Garamond',
 			'georgia':'Georgia',
 			'helvetica':'Helvetica',
+			'HelveticaNeue-Light':'Helvetica Neue Light',
 			'impact':'Impact',
 			'times new roman':'Times',
 			'tahoma':'Tahoma',
@@ -66,14 +67,13 @@ Dialog.Font = new Class({
 
 		var self = this, fonts = options.fonts;
 
-        //options.cssClass = '.font'+(options.cssClass||'')
-        this.setClass('.font',options);
-		options.body = fonts ? fonts : self.options.fonts;
+        self.setClass('.font',options);
+		options.body = options.fonts || self.options.fonts;
 
 		self.parent(options);
 
-		self.getItems().each(function(li){
-			li.setStyle('font-family', li.get('title') );
+		self.element.getElements('.item').each( function( item ){
+			item.setStyle('font-family', item.get('title') );
 		});
 
 	}

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.Selection.js Mon Jun 22 20:11:42 2015
@@ -39,114 +39,115 @@ Example:
 		body:"a|b|c|d",
 		caption:"Snippet Dialog",
 		autoClose:true,
-		onClick:function(v){ alert('clicked '+v) }
+		onClick:function(v){ alert("clicked "+v) }
 	});
 	new Dialog.Selection({
 		body:[a,b,c,d],
 		caption:"Snippet Dialog",
-		onClick:function(v){ alert('clicked '+v) }
+		onClick:function(v){ alert("clicked "+v) }
 	});
 	new Dialog.Selection({
-		body:{'avalue':'a','bvalue':'b','cvalue':'c'},
+		body:{"avalue":"a","bvalue":"b","cvalue":"c"},
 		caption:"Snippet Dialog",
-		onClick:function(v){ alert('clicked '+v) }
+		onClick:function(v){ alert("clicked "+v) }
 	});
 	(end code)
 */
 Dialog.Selection = new Class({
 
 	Extends: Dialog,
-	
+
 	options: {
 		//onAction: function(value){},
 		//selected: <some value>
-		cssClass: 'dialog selection',
-		autoClose: true,
-		items: '.body li'
+		cssClass: "dialog selection",
+		autoClose: true
 	},
 
 	initialize:function( options ){
 
-        this.setClass('.selection',options);
-        this.selected = options.selected || '';
+        this.setClass(".selection",options);
+        this.selected = options.selected || "";
 		this.parent( options );
 
-        console.log('Dialog.Selection ', this.element.className);
+        //console.log("Dialog.Selection ", this.element.className);
 	},
 
 	setBody: function(content){
 
-		var self = this;
-console.log('Dialog.Selection body ',content);
-		if(!content){ content = self.options.body; }
-
-		//turn 'multi|value|string' into [array]
-		if( typeOf(content) == 'string' ){ content = content.split('|'); }
-
-		//turn [array] into {object} with name:value pairs
-		if( typeOf(content) == 'array' ){ content = content.associate(content); }
-
-		//turn {object} in DOM elements (ul/li collection)
-		if( typeOf(content) == 'object' ){
-		
-			content = 'ul'.slick({ 
-				html: Object.keys(content).map( function(key){
-					return '<li title="'+key+'">'+content[key]/*.trunc(36)*/+'</li>';
-				})
+		var self = this, items=[];
+
+        //console.log("Dialog.Selection body ",content);
+		if( !content ){ content = self.options.body; }
+
+		//convert "multi|value|string" into [array]
+		if( typeOf(content) == "string" ){ content = content.split("|"); }
+
+		//convert [array] into {object} with name:value pairs
+		if( typeOf(content) == "array" ){ content = content.associate(content); }
+
+		//convert {object} in DOM elements (ul/li collection)
+		if( typeOf(content) == "object" ){
+
+			Object.each(content, function(value, key){
+
+			    items.push( value == "" ?
+			        "li.divider" :
+			        "li.item[title=" + key + "]", {html: value}
+			    );
+
 			});
-			
+			content = ["ul",items].slick();
+
 		}
 
-		if( typeOf(content) == 'element' ){
+		if( typeOf( content ) == "element" ){
 
 			//first move the content elements into the body and highlight the selected item
 			self.parent( content ).setValue( self.selected );
 
 			//then add the click & hover event handlers
-			self.getItems().addEvents({
-				//click: self.action.bind(self),
-				click: function(){ self.action( this); },
-				mouseleave: function(){ this.removeClass('hover'); },
-				mouseenter: function(){ this.addClass('hover'); }
+			self.element.addEvent("click:relay(.item)", function(e){
+			    e.stop();
+                self.action( this.get("title") );
 			});
+
+
 		}
-		
+
 		return self;
 	},
-	
+
 	/*
 	Function: setValue
 		Store the selected value. (this.selected).
-		And highlight the selected item (if any) 
+		And highlight the selected item (if any)
 	*/
-	setValue: function(value){
+	setValue: function( value ){
 
-		var selected = "selected", els;
+		var self = this, selected = "selected", element;
 
-		//remove previous selected item, if any 
-		els = this.get('.'+selected); 
-		if(els){ els.removeClass(selected); } 
+		element = self.get("." + selected);
+		if( element ){ element.removeClass(selected); }
 
-		els = this.getItems('[title^='+value+']');
-		if(els[0]){ els[0].addClass(selected); }
+        //console.log("Dialog.Selection setValue",value);
+		element = self.get( ".item[title^=" + value + "]" );
+		if( element ){ element.addClass(selected); }
 
-		this[selected] = value;
+		self[selected] = value;
 
-		return this;	
+		return self;
 	},
 
 	getValue: function(){
-		return this.selected;	
+		return this.selected;
 	},
 
-	action: function(item){
-		var value = item.get('title');
-		this.setValue(value).parent(value);
-	},
+	action: function( value ){
 
+		//console.log("Dialog.Selection action() ",value);
+		this.setValue( value ).parent(value);
 
-	getItems: function( filter ){
-		return this.element.getElements(this.options.items+(filter||''));
 	}
 
-});
+});
\ No newline at end of file

Modified: jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.js
URL: http://svn.apache.org/viewvc/jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.js?rev=1686927&r1=1686926&r2=1686927&view=diff
==============================================================================
--- jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.js (original)
+++ jspwiki/trunk/jspwiki-war/src/main/scripts/dialog/Dialog.js Mon Jun 22 20:11:42 2015
@@ -40,49 +40,49 @@ Options:
 		When present, it overrules the caption and body elements.
 	caption - (optional) DOM element
 	body - (optional) DOM element
-	cssClass - css class for dialog box, default is 'dialog'
+	cssClass - css class for dialog box, default is "dialog"
 	style - (optional) additional css style for the dialog box
-	relativeTo - DOM element to position the dialog box
-	resize - resize callback, default null which implies no resize.
-	showNow - (default true) show the dialogbox at initialisation time
-	draggable - (default true) make the dialogbox draggable
+	relativeTo - the dialog will be positioned below the 'relativeTo' DOM element
+	showNow - (default false) show the dialogbox at initialisation time
+	draggable - (default false) make the dialogbox draggable
 
 Events:
+	onBeforeOpen- fires before the dialog gets shown
 	onOpen- fires when the dialog is shown
 	onClose - fires when the dialog is hidden
 	onResize - fires when the dialog is resized
 
 DOM Structure:
 	(start code)
-	<div class='dialog'>
-		<div class='caption'> ... </div>
-		<a class='close'>&#215<a>
-		<div class='body'> ... dialog main body ... </div>
-		<div class='buttons'> ... dialog buttons ... </div>
+	<div class="dialog">
+		<div class="caption"> ... </div>
+		<a class="close">&#215<a>
+		<div class="body"> ... dialog main body ... </div>
+		<div class="buttons"> ... dialog buttons ... </div>
 	</div>
 	(end)
 
 Example:
+    Create dialogs from Javascript
 	(start code)
 	var dialog = new Dialog({
-		caption:self.ApplicationName || 'JSPWiki',
-		showNow:false,
-		relativeTo:$('query')
+		caption:self.ApplicationName || "JSPWiki",
+		showNow:true,
+		body:"<p>This is a test dialog<br />Isn't this nice &amp; simple?</p>",
+		relativeTo:$("query")
 	});
-	dialog.setBody( $('some-dialog') ).show();
-
+	//adopt one or more DOM elements as body of the DIALOG
+	dialog.setBody( $("some-dialog") ).show();
 	(end)
 
 
 	(start code)
-	var button = $('colorButton');
+	var button = $("colorButton");
 	var cd = new Dialog.Color({
 		relativeTo:button,
-		onChange:function(color){ $('target').setStyle('background',color);}
+		onChange:function(color){ $("target").setStyle("background",color);}
 	});
-	button.addEvent('click', cd.toggle.bind(cd));
-
-	cd.dispose();
+	button.addEvent("click", cd.toggle.bind(cd));
 	(end)
 */
 var Dialog = new Class({
@@ -90,11 +90,12 @@ var Dialog = new Class({
 	Implements: [Events, Options],
 
 	options:{
-		cssShow: 'show',
+		cssShow: "show",
+		cssClass: "",
 		styles: {},
 		//dialog: DOM-element
-		//caption: ''
-		//body: 'innerHTML' or DOM-element
+		//caption: ""
+		//body: "innerHTML" or DOM-element
 		//autoClose: false,
 		//showNow: false,
 		//draggable: false
@@ -107,85 +108,114 @@ var Dialog = new Class({
 
 		var self = this, el;
 
-        //options.cssClass = '.dialog'+(options.cssClass||'');
-        this.setClass('.dialog',options);
-        //console.log(options.cssClass);
-
-		this.setOptions(options);
-		console.log("DIALOG Initialize ",this.options.cssClass);
+        this.setClass(".dialog",options);
+		this.setOptions( options );
 
+        console.log("Dialog.initialize");
 		options = self.options;
 
 		el = self.element = options.dialog || self.build(options);
 
-		el.getElements('.close').addEvent('click', self.hide.bind(self) );
+		el.getElements(".close").addEvent("click", self.hide.bind(self) );
 
 		//make dialog draggable; only possible when el is position absolute
-		if( (el.getStyle('position')=='absolute') && options.draggable ){
+		if( (el.getStyle("position") == "absolute") && options.draggable ){
 
 			new Drag(el,{
-				handle: (self.get('.caption') || el).setStyle('cursor','move')
+				handle: (self.get(".caption") || el).setStyle("cursor", "move")
 			});
 
 		}
 
-		//CHECKME: self.resetPosition();
 		self[ options.showNow ? "show": "hide"]();
 	},
 
 	toElement: function(){
+
 		return this.element;
+
 	},
+
 	/*
 	Function: get
-		Retrieve DOM elements inside the dialog container, based on a css selector.
+		Retrieve the first DOM element inside the dialog container, matching the css selector.
 	Example:
-	>	this.get('.body');
-	>	this.get('.body li');
+	>	this.get(".body li");
 	*/
+
 	get: function(selector){
+
 		return this.element.getElement(selector);
+
 	},
 
-    setClass: function(clazz,options){
-        options.cssClass = clazz+(options.cssClass||'');
+    setClass: function(clazz, options){
+
+        options.cssClass = clazz + (options.cssClass || "");
+        console.log("Dialog.setClass ", options.cssClass );
+
     },
 
 	destroy: function(){
+
 		this.element.destroy();
+
 	},
 
 	show: function(){
-	
-	console.log("DIALOG show",this.options.cssClass,this.element.className);
-		this.fireEvent('beforeOpen', this)
-			.setPosition()
-			.element.addClass(this.options.cssShow);
-		return this.fireEvent('open', this);
+
+	    //console.log("DIALOG show: cssShow:",this.options.cssShow," class: ",this.element.className, this.element);
+		this.fireEvent("beforeOpen", this);
+
+        //always recalculate the position of the dialog, unless draggable
+        //because the 'relativeTo' element could change (eg scroll,...)
+		if( !this.options.draggable || !this.hasPosition ){
+
+		    this.setPosition();
+		    this.hasPosition = true;
+
+		}
+
+		this.element.addClass(this.options.cssShow);
+
+	    return this.fireEvent("open", this);
+
 	},
 
 	hide: function(){
-		this.fireEvent('beforeClose', this)
-			.element.removeClass(this.options.cssShow);
-		return this.fireEvent('close', this);
+
+        //do not send unnecessary close events
+        if( this.hasPosition ){
+
+		    this.fireEvent("beforeClose", this)
+			    .element.removeClass(this.options.cssShow);
+
+		    this.fireEvent("close", this);
+
+		}
+		return this;
 	},
 
 	isVisible: function(){
+
 		return this.element.hasClass(this.options.cssShow);
+
 	},
 
 	toggle: function(){
-		return this[this.isVisible() ? 'hide' : 'show']();
+
+		return this[this.isVisible() ? "hide" : "show"]();
+
 	},
 
 	/*
 	Function: action
-		Fires the ''action'' event.
+		Fires the ""action"" event.
 		When the autoClose option is set, the dialog will also be hidden.
 	*/
 	action: function(value){
-		//console.log('action: '+value+" close:"+self.options.autoClose);
-		this.fireEvent('action', value);
+		console.log("Dialog action: ",value," close:"+this.options.autoClose);
+		this.fireEvent("action", value);
 		if( this.options.autoClose ){ this.hide(); }
 	},
 
@@ -195,27 +225,24 @@ var Dialog = new Class({
 	*/
 	build: function( options ){
 
-        //console.log("DIALOG build ",options.cssClass);
+        console.log("DIALOG build ",options.cssClass, options.styles);
 
 		var element = this.element = [
-		    'div'+options.cssClass, {styles:options.styles}, [
-			    'a.close',{ html:'&#215;'},
-			    'div.body'
+		    "div" + options.cssClass, {styles: options.styles}, [
+			    "a.close",{ html: "&#215;"},
+			    "div.body"
 			]
 		].slick().inject(document.body);
 
         if( options.relativeTo ){
 			//make sure to inject the dialog close to the relativeTo element
-			//so that any relative positioned parent doesn't intervene
-			element.inject($(options.relativeTo), 'before');
+			//so that any relative positioned parent doesn"t intervene
+			element.inject($(options.relativeTo), "before");
 		}
-		
-console.log("DIALOG build ",this.element.className);
+
 		this.setBody( options.body );
 		if( options.caption ) this.setCaption( options.caption );
 
-console.log("DIALOG build ",this.element.className);
-
 		return element;
 	},
 
@@ -226,18 +253,18 @@ console.log("DIALOG build ",this.element
 		content - string or DOM element
 	Example:
 		> setBody( "this is a new dialog content");
-		> setBody( new Element('span',{'class','error'}).set('html','Error encountered') );
+		> setBody( new Element("span",{"class","error"}).set("html","Error encountered") );
 	*/
 	setBody: function(content){
 
-		var body = this.get('.body') || this.element,
+		var body = this.get(".body") || this.element,
 		    type = typeOf(content);
 
 		body.empty();
 
-		if( type=='string') body.set('html',content);
-		if( type=='element') body.adopt(content);
-		if( type=='elements') body.adopt(content);
+		if( type == "string" ){ body.set("html",content); }
+		if( type == "element" ){ body.adopt(content); }
+		if( type == "elements" ){ body.adopt(content); }
 
 		return this;
 	},
@@ -245,20 +272,20 @@ console.log("DIALOG build ",this.element
 
 	setCaption: function(caption){
 
-		var cptn = this.get('.caption') ||'div.caption'.slick().inject(this.element,'top');
+		var cptn = this.get(".caption") ||"div.caption".slick().inject(this.element,"top");
 			type = typeOf(caption);
 
 		cptn.empty();
 
-		if( type=='string') cptn.set('html',caption);
-		if( type=='element') cptn.adopt(caption);
+		if( type == "string" ){ cptn.set("html",caption); }
+		if( type == "element" ){ cptn.adopt(caption); }
 
 		return this;
 	},
 
 	setValue: function(value){
 
-		console.log('DIALOG  '+value);
+		console.log("DIALOG  " + value);
 		return this.setBody(value);
 
 	},
@@ -278,32 +305,32 @@ console.log("DIALOG build ",this.element
 		var w = window, ws, x, y, pos,
 			el = this.element;
 
-		if(!relativeTo){ relativeTo = this.options.relativeTo; }
-		pos = (relativeTo && 'getCoordinates' in relativeTo) ? relativeTo : document.id(relativeTo);
-		
-		if( el.getStyle('position') == 'absolute' ){
-
-			if( pos ){
-
-				pos = pos.getCoordinates();
-				//console.log(JSON.encode(pos));
-				x = pos.left; y = pos.bottom; //align at the bottom of the relativeTo element
-
-			} else {	// center dialog box
-
-				//todo: should be adjusted everytime the screen is resized or scrolled ?
-				ws = w.getScroll();
-				w = w.getSize();
-				pos = el.getCoordinates();
-				x = ws.x + w.x/2 - pos.width/2;
-				y = ws.y + w.y/2 - pos.height/2;
+		if( !relativeTo ){ relativeTo = this.options.relativeTo; }
+
+		pos = (relativeTo && "getCoordinates" in relativeTo) ? relativeTo : document.id(relativeTo);
+
+		if( pos ){
 
-			}
+			pos = pos.getCoordinates();  //relative to document,  for textarea, coord. of caret in ta
 
-			el.setPosition({x:x,y:y});
-			//el.morph({left: x, top:y}); -- move this to css/transition
+			//console.log(JSON.encode(pos));
+			x = pos.left; y = pos.bottom; //align at the bottom of the relativeTo element
+
+		} else {	// center dialog box
+
+			//todo: should be adjusted everytime the screen is resized or scrolled ?
+			ws = w.getScroll();
+			w = w.getSize();
+			pos = el.getCoordinates();
+			x = ws.x + w.x/2 - pos.width/2;
+			y = ws.y + w.y/2 - pos.height/2;
 
 		}
+
+        //console.log("Dialog: setPosition()  x:",x," y:",y, el, this.options.relativeTo, pos);
+		el.setPosition({x:x,y:y});
+		//el.morph({left: x, top:y}); -- move this to css/transition
+
 		return this;
 	}