You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by js...@apache.org on 2009/03/19 12:27:44 UTC

svn commit: r755934 [2/2] - in /camel/trunk/components/camel-web/src/main: java/org/apache/camel/web/resources/ webapp/WEB-INF/ webapp/WEB-INF/decorators/ webapp/js/ webapp/js/th/ webapp/org/apache/camel/web/resources/RouteResource/ webapp/org/apache/c...

Added: camel/trunk/components/camel-web/src/main/webapp/js/th/css.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/th/css.js?rev=755934&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/th/css.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/th/css.js Thu Mar 19 11:27:43 2009
@@ -0,0 +1,132 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is jquery-css-parser.
+ *
+ * The Initial Developer of the Original Code is Daniel Wachsstock.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *     Bespin Team (bespin@mozilla.com)
+ *
+ * ORIGINAL MIT-licensed CODE LICENSE HEADER FOLLOWS:
+
+// jQuery based CSS parser
+// documentation: http://youngisrael-stl.org/wordpress/2009/01/16/jquery-css-parser/
+// Version: 1.0
+// Copyright (c) 2009 Daniel Wachsstock
+// MIT license:
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+ * ***** END LICENSE BLOCK ***** */
+
+
+dojo.provide("th.css"); 
+
+dojo.declare("th.css.CSSParser", null, {
+    parse: function(str, ret) {
+        // parses the passed stylesheet into an object with properties containing objects with the attribute names and values
+        if (!ret) ret = {};          
+        
+        dojo.forEach(this.munge(str, false).split('`b%'), function(css){              
+            css = css.split('%b`'); // css[0] is the selector; css[1] is the index in munged for the cssText  
+            if (css.length < 2) return; // invalid css
+            css[0] = this.restore(css[0]);
+            var obj = ret[css[0]] || {};
+            ret[css[0]] = dojo.mixin(obj, this.parsedeclarations(css[1]));
+        }, this);  
+         
+        return ret;
+    },
+
+    // replace strings and brace-surrounded blocks with %s`number`s% and %b`number`b%. By successively taking out the innermost
+    // blocks, we ensure that we're matching braces. No way to do this with just regular expressions. Obviously, this assumes no one
+    // would use %s` in the real world.
+    // Turns out this is similar to the method that Dean Edwards used for his CSS parser in IE7.js (http://code.google.com/p/ie7-js/)
+    REbraces: /{[^{}]*}/,
+    
+    REfull: /\[[^\[\]]*\]|{[^{}]*}|\([^()]*\)|function(\s+\w+)?(\s*%b`\d+`b%){2}/, // match pairs of parentheses, brackets, and braces and function definitions.
+    
+    REatcomment: /\/\*@((?:[^\*]|\*[^\/])*)\*\//g, // comments of the form /*@ text */ have text parsed
+    // we have to combine the comments and the strings because comments can contain string delimiters and strings can contain comment delimiters
+    // var REcomment = /\/\*(?:[^\*]|\*[^\/])*\*\/|<!--|-->/g; // other comments are stripped. (this is a simplification of real SGML comments (see http://htmlhelp.com/reference/wilbur/misc/comment.html) , but it's what real browsers use)
+    // var REstring = /\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*'/g; // match escaped characters and strings
+    
+    REcomment_string:
+      /(?:\/\*(?:[^\*]|\*[^\/])*\*\/)|(\\.|"(?:[^\\\"]|\\.|\\\n)*"|'(?:[^\\\']|\\.|\\\n)*')/g,
+    
+    REmunged: /%\w`(\d+)`\w%/,
+    
+    uid: 0, // unique id number
+    
+    munged: {}, // strings that were removed by the parser so they don't mess up searching for specific characters
+
+    munge: function(str, full) {
+        str = str
+            .replace(this.REatcomment, '$1') // strip /*@ comments but leave the text (to let invalid CSS through)
+            .replace(this.REcomment_string, dojo.hitch(this, function (s, string) { // strip strings and escaped characters, leaving munged markers, and strip comments
+                if (!string) return '';
+                var replacement = '%s`'+(++this.uid)+'`s%';
+                this.munged[this.uid] = string.replace(/^\\/, ''); // strip the backslash now
+                return replacement;
+            }));
+       
+        // need a loop here rather than .replace since we need to replace nested braces
+        var RE = full ? this.REfull : this.REbraces;
+        while (match = RE.exec(str)) {
+            replacement = '%b`'+(++this.uid)+'`b%';
+            this.munged[this.uid] = match[0];
+            str = str.replace(RE, replacement);
+        }           
+        return str;
+    },
+
+    restore: function(str) {
+        if (str === undefined) return str;
+        while (match = this.REmunged.exec(str)) {
+            str = str.replace(this.REmunged, this.munged[match[1]]);
+        }
+        return dojo.trim(str);
+    },
+
+    parsedeclarations: function(index){ // take a string from the munged array and parse it into an object of property: value pairs
+        var str = this.munged[index].replace(/(?:^\s*[{'"]\s*)|(?:\s*([^\\])[}'"]\s*$)/g, '$1'); // find the string and remove the surrounding braces or quotes
+        str = this.munge(str); // make sure any internal braces or strings are escaped
+        var parsed = {};   
+        dojo.forEach(str.split(';'), function (decl) {
+            decl = decl.split(':');
+            if (decl.length < 2) return;
+            parsed[this.restore(decl[0])] = this.restore(decl[1]);
+        }, this);
+        return parsed;
+    }
+});
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/th/css.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/th/docs.txt
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/th/docs.txt?rev=755934&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/th/docs.txt (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/th/docs.txt Thu Mar 19 11:27:43 2009
@@ -0,0 +1,29 @@
+style (anything that could affect painting)
+- backgroundColor
+* backgroundImage
+* color
+- font
+- noClip
+- display (show, block, inline, none; not laid out and not painted)
+- visibility (visible, hidden; laid out but not painted)
+- defaultSize (used by SplitPanel, HorizontalTree)
+- border
+- backgroundColorOdd (used by List, HorizontalTree)
+- scrollTopImage (used by ScrollBar)
+- scrollMiddleImage (used by ScrollBar)
+- scrollBottomImage (used by ScrollBar)
+- scrollHandleTopImage (used by ScrollBar)
+- scrollHandleMiddleImage (used by ScrollBar)
+- scrollHandleBottomImage (used by ScrollBar)
+
+attributes (not related to painting)
+- regions (used by SplitPanel)
+  - size (% or px)
+  - contents (component)
+- orientation (TH.HORIZONTAL, TH.VERTICAL; used by SplitPanel, Splitter)
+- text (used by Label)
+
+events
+- dragstart (fired by ResizeNib, Splitter; start position)
+- dragstop (fired by ResizeNib, Splitter; startPos, currentPos)
+- drag (fired by ResizeNib, Splitter; startPos, currentPos)
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/th/docs.txt
------------------------------------------------------------------------------
    svn:mime-type = text/plain

Added: camel/trunk/components/camel-web/src/main/webapp/js/th/helpers.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/th/helpers.js?rev=755934&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/th/helpers.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/th/helpers.js Thu Mar 19 11:27:43 2009
@@ -0,0 +1,139 @@
+//  ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1
+// 
+// The contents of this file are subject to the Mozilla Public License  
+// Version
+// 1.1 (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.mozilla.org/MPL/
+// 
+// Software distributed under the License is distributed on an "AS IS"  
+// basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the  
+// License
+// for the specific language governing rights and limitations under the
+// License.
+// 
+// The Original Code is Bespin.
+// 
+// The Initial Developer of the Original Code is Mozilla.
+// Portions created by the Initial Developer are Copyright (C) 2009
+// the Initial Developer. All Rights Reserved.
+// 
+// Contributor(s):
+// 
+// ***** END LICENSE BLOCK *****
+//  
+
+dojo.provide("th.helpers");
+
+dojo.mixin(th.helpers, {
+    isPercentage: function(str){  // TODO: make more robust 
+        return (str.indexOf && str.indexOf("%") != -1);
+    }
+});
+
+dojo.declare("th.helpers.EventHelpers", null, { 
+    // only works on a Scene at the moment as it uses  
+    wrapEvent: function(e, root) {
+        // compute the canvas-local coordinates
+        var coords = dojo.coords(this.canvas, true);
+        var x = e.clientX - coords.x;
+        var y = e.clientY - coords.y;
+        
+        var component = root.getComponentForPosition(x, y, true);
+        e.thComponent = component;
+
+        this.addComponentXY(e, root, component);
+    },
+    
+    // changes clientX and clientY from space of source to space of dest; no change wraught if dest incompatible with source
+    addComponentXY: function(e, source, dest) {
+        if (!dest.bounds) {
+            console.log("No dest bounds - " + dest.declaredClass);
+            console.log(dest.bounds);
+            console.log(dest);
+            return;
+        }
+
+        // compute the canvas-local coordinates
+        var coords = dojo.coords(this.canvas, true);
+        var x = e.clientX - coords.x;
+        var y = e.clientY - coords.y;
+   
+        var nxy = { x: x, y: y };
+
+        var c = dest;
+        while (c) {
+            nxy.x -= c.bounds.x;
+            nxy.y -= c.bounds.y;
+            c = c.parent;
+
+            if (c == source) {
+                e.componentX = nxy.x;
+                e.componentY = nxy.y;
+                return;
+            }
+        }
+    }
+}); 
+  
+dojo.declare("th.helpers.ComponentHelpers", null, {  	
+    // returns hash with some handy short-cuts for painting
+    d: function() {  
+        return {
+           b: (this.bounds) ? { x: this.bounds.x, y: this.bounds.y, w: this.bounds.width, h: this.bounds.height,
+                                iw: this.bounds.width - this.getInsets().left - this.getInsets().right,
+                                ih: this.bounds.height - this.getInsets().top - this.getInsets().bottom } : {},
+           i: { l: this.getInsets().left, r: this.getInsets().right, t: this.getInsets().top, b: this.getInsets().bottom,
+                w: this.getInsets().left + this.getInsets().right, h: this.getInsets().top + this.getInsets().bottom }
+        }
+    },
+
+    shouldPaint: function() {
+        return (this.shouldLayout() && this.style.visibility != "hidden");
+    },
+
+    shouldLayout: function() {
+        return (this.style.display != "none");
+    },
+
+    emptyInsets: function() {
+        return { left: 0, right: 0, bottom: 0, top: 0 };
+    }
+}); 
+
+dojo.declare("th.helpers.ContainerHelpers", null, {
+    getScene: function() {
+        var container = this;
+        while (!container.scene && container.parent) container = container.parent;
+        return container.scene;
+    },
+
+    getChildById: function(id) {
+        for (var i = 0; i < this.children.length; i++) {
+            if (this.children[i].id == id) return this.children[i];
+        }
+    },
+
+    getComponentForPosition: function(x, y, recurse) {
+        for (var i = 0; i < this.children.length; i++) {
+            if (!this.children[i].bounds) continue;
+            
+            if (this.children[i].bounds.x <= x && this.children[i].bounds.y <= y
+                    && (this.children[i].bounds.x + this.children[i].bounds.width) >= x
+                    && (this.children[i].bounds.y + this.children[i].bounds.height) >= y) {
+                if (!recurse) return this.children[i];
+                return (this.children[i].getComponentForPosition) ?
+                       this.children[i].getComponentForPosition(x - this.children[i].bounds.x, y - this.children[i].bounds.y, recurse) :
+                       this.children[i];
+            }
+        }
+        return this;
+    },
+
+    removeAll: function() {
+        this.remove(this.children);
+    }
+});
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/th/helpers.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/th/models.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/th/models.js?rev=755934&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/th/models.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/th/models.js Thu Mar 19 11:27:43 2009
@@ -0,0 +1,50 @@
+//  ***** BEGIN LICENSE BLOCK *****
+// Version: MPL 1.1
+// 
+// The contents of this file are subject to the Mozilla Public License  
+// Version
+// 1.1 (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.mozilla.org/MPL/
+// 
+// Software distributed under the License is distributed on an "AS IS"  
+// basis,
+// WITHOUT WARRANTY OF ANY KIND, either express or implied. See the  
+// License
+// for the specific language governing rights and limitations under the
+// License.
+// 
+// The Original Code is Bespin.
+// 
+// The Initial Developer of the Original Code is Mozilla.
+// Portions created by the Initial Developer are Copyright (C) 2009
+// the Initial Developer. All Rights Reserved.
+// 
+// Contributor(s):
+// 
+// ***** END LICENSE BLOCK *****
+// 
+
+dojo.provide("th.models");
+
+dojo.declare("th.models.LazyTreeModel", null, {
+    placeholder: "(placeholder)",
+
+    loading: "(loading)",
+
+    root: this.placeholder,
+
+    getRoot: function() {
+        return this.root;
+    },
+
+    getChildren: function(parent) {
+    },
+
+    loadChildren: function(parent) {
+    },
+
+    childrenLoaded: function(parent, children) {        
+    }
+});
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/th/models.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/th/th.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/th/th.js?rev=755934&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/th/th.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/th/th.js Thu Mar 19 11:27:43 2009
@@ -0,0 +1,554 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (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.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+dojo.provide("th.th");  
+
+/*
+    Constants
+ */ 
+dojo.mixin(th, {
+    VERTICAL: "v",
+    HORIZONTAL: "h"    
+});
+
+/*
+    Event bus; all listeners and events pass through a single global instance of this class.
+ */ 
+dojo.declare("th.Bus", null, {
+    constructor: function() {
+        // map of event name to listener; listener contains a selector, function, and optional context object
+        this.events = {};
+    },
+
+    // register a listener with an event
+    bind: function(event, selector, listenerFn, listenerContext) {
+        var listeners = this.events[event];
+        if (!listeners) {
+            listeners = [];
+            this.events[event] = listeners;
+        }
+        selector = dojo.isArray(selector) ? selector : [ selector ];
+        for (var z = 0; z < selector.length; z++) {
+            for (var i = 0; i < listeners.length; i++) {
+                if (listeners[i].selector == selector[z] && listeners[i].listenerFn == listenerFn) return;
+            }
+            listeners.push({ selector: selector[z], listenerFn: listenerFn, context: listenerContext });
+        }
+    },
+
+    // removes any listeners whose selectors have the *same identity* as the passed selector
+    unbind: function(selector) {
+        for (var event in this.events) {
+            var listeners = this.events[event];
+
+            for (var i = 0; i < listeners.length; i++) {
+                if (listeners[i].selector === selector) {
+                    this.events[event] = dojo.filter(listeners, function(item){ return item != listeners[i]; });                    
+                    listeners = this.events[event];
+                    i--;
+                }
+            }
+        }
+    },
+
+    // notify all listeners of an event
+    fire: function(eventName, eventDetails, component) {
+        var listeners = this.events[eventName];
+        if (!listeners || listeners.length == 0) return;
+
+        // go through each listener registered for the fired event and check if the selector matches the component for whom
+        // the event was fired; if there is a match, dispatch the event
+        for (var i = 0; i < listeners.length; i++) {
+            // if the listener selector is a string...
+            if (listeners[i].selector.constructor == String) {
+                // check if the string starts with a hash, indicating that it should match by id
+                if (listeners[i].selector.charAt(0) == "#") {
+                    if (component.id == listeners[i].selector.substring(1)) {
+                        this.dispatchEvent(eventName, eventDetails, component, listeners[i]);
+                    }
+                // otherwise check if it's the name of the component class
+                } else if (listeners[i].selector == component.declaredClass) {
+                    this.dispatchEvent(eventName, eventDetails, component, listeners[i]);
+                }
+            // otherwise check if the selector is the current component
+            } else if (listeners[i].selector == component) {
+                this.dispatchEvent(eventName, eventDetails, component, listeners[i]);
+            }
+        }
+    },
+
+    // invokes the listener function
+    dispatchEvent: function(eventName, eventDetails, component, listener) {
+        eventDetails.thComponent = component;
+
+        // check if there is listener context; if so, execute the listener function using that as the context
+        if (listener.context) {
+            listener.listenerFn.apply(listener.context, [ eventDetails ]);
+        } else {
+            listener.listenerFn(eventDetails);
+        }
+    }
+});
+
+// create the global event bus
+th.global_event_bus = new th.Bus();
+
+dojo.declare("th.Scene", th.helpers.EventHelpers, { 
+    bus: th.global_event_bus,
+
+    css: {},
+
+    sheetCount: 0,
+    currentSheet: 0,
+    cssLoaded: false,
+    renderRequested: false,
+    renderAllowed: true,
+
+    constructor: function(canvas) {
+        this.canvas = canvas;
+
+        dojo.connect(window, "resize", dojo.hitch(this, function() {
+            this.render();
+        })); 
+
+        this.root = new th.components.Panel({ id: "root", style: {
+//            backgroundColor: "pink" // for debugging         
+        } });
+        this.root.scene = this; 
+
+        var testCanvas = document.createElement("canvas");
+        this.scratchContext = testCanvas.getContext("2d");
+        bespin.util.canvas.fix(this.scratchContext);
+
+        dojo.connect(window, "mousedown", dojo.hitch(this, function(e) {
+            this.wrapEvent(e, this.root);
+
+            this.mouseDownComponent = e.thComponent;
+
+            th.global_event_bus.fire("mousedown", e, e.thComponent);
+        }));
+
+        dojo.connect(window, "dblclick", dojo.hitch(this, function(e) {
+            this.wrapEvent(e, this.root);
+
+            th.global_event_bus.fire("dblclick", e, e.thComponent);
+        }));
+
+        dojo.connect(window, "click", dojo.hitch(this, function(e) {
+            this.wrapEvent(e, this.root);
+
+            th.global_event_bus.fire("click", e, e.thComponent);
+        }));
+
+        dojo.connect(window, "mousemove", dojo.hitch(this, function(e) {
+            this.wrapEvent(e, this.root);
+
+            th.global_event_bus.fire("mousemove", e, e.thComponent);
+
+            if (this.mouseDownComponent) {
+                this.addComponentXY(e, this.root, this.mouseDownComponent);
+                th.global_event_bus.fire("mousedrag", e, this.mouseDownComponent);
+            }
+        }));
+
+        dojo.connect(window, "mouseup", dojo.hitch(this, function(e) {
+            if (!this.mouseDownComponent) return;
+
+            this.addComponentXY(e, this.root, this.mouseDownComponent);
+            th.global_event_bus.fire("mouseup", e, this.mouseDownComponent);
+
+            delete this.mouseDownComponent;
+        }));
+
+        this.parseCSS();
+    },
+
+    render: function(forceRendering) { 
+        if (!this.renderAllowed && !forceRendering) {
+            return;
+        }
+        if (!this.cssLoaded) { 
+            this.renderRequested = true;
+            return;
+        }
+        this.layout();
+        this.paint();
+    },
+
+    layout: function() {
+        if (this.root) {
+            this.root.bounds = { x: 0, y: 0, width: this.canvas.width, height: this.canvas.height };
+            this.root.layoutTree();
+        }
+    },
+
+    paint: function(component) {
+        if (!this.cssLoaded) {
+            this.renderRequested = true;
+            return;
+        }
+
+        if (!component) component = this.root;
+
+        //if (component === this.root) console.log("root paint");
+
+        if (component) {
+            if (!component.opaque && component.parent) {
+                return this.paint(component.parent);
+            }
+
+            var ctx = this.canvas.getContext("2d");
+            bespin.util.canvas.fix(ctx);
+
+            ctx.save();
+
+            var parent = component.parent;
+            var child = component;
+            while (parent) {
+                ctx.translate(child.bounds.x, child.bounds.y);
+                child = parent;
+                parent = parent.parent;
+            }
+             
+            ctx.clearRect(0, 0, component.bounds.width, component.bounds.height);
+            ctx.beginPath();
+            ctx.rect(0, 0, component.bounds.width, component.bounds.height);
+            ctx.closePath();
+            ctx.clip(); 
+            component.paint(ctx);  
+            
+            ctx.restore();
+        }
+    },
+
+    parseCSS: function() { 
+        var links = [];   
+        var s, l = document.getElementsByTagName('link');
+		for (var i=0; i < l.length; i++){ 
+		    s = l[i];
+			if (s.rel.toLowerCase().indexOf('stylesheet') >= 0&&s.href) {
+			    links.push(s.href);
+			}
+		} 
+        if (links.length == 0) {
+            this.cssLoaded = true;
+            return;
+        }
+        this.sheetCount = links.length;
+        dojo.forEach(links, function(link) {            
+            dojo.xhrGet({
+                url: link, 
+                load: dojo.hitch(this, function(response) {
+                    this.processCSS(response);
+                })
+            });
+        }, this);
+    },
+
+    processCSS: function(stylesheet) {
+        this.css = new th.css.CSSParser().parse(stylesheet, this.css);  
+
+        if (++this.currentSheet == this.sheetCount) {
+            this.cssLoaded = true;
+            if (this.renderRequested) {
+                this.render();
+                this.renderRequested = false;
+            }
+        }
+    }
+});
+
+dojo.declare("th.Border", th.helpers.ComponentHelpers, {
+    constructor: function(parms) {
+        if (!parms) parms = {};
+        this.style = parms.style || {};
+        this.attributes = parms.attributes || {};
+    },
+
+    getInsets: function() {
+        return this.emptyInsets();
+    },
+
+    paint: function(ctx) {}
+});   
+    
+dojo.declare("th.Component", th.helpers.ComponentHelpers, {
+    constructor: function(parms) { 
+        if (!parms) parms = {};
+        this.bounds = parms.bounds || {};
+        this.style = parms.style || {};
+        this.attributes = parms.attributes || {};
+        this.id = parms.id;
+        this.border = parms.border;
+        this.opaque = parms.opaque || true;
+    
+        this.bus = th.global_event_bus; 
+    },
+    
+    // used to obtain a throw-away canvas context for performing measurements, etc.; may or may not be the same canvas as that used to draw the component
+    getScratchContext: function() {
+        var scene = this.getScene();
+        if (scene) return scene.scratchContext;
+    },
+    
+    getPreferredHeight: function(width) {},
+    
+    getPreferredWidth: function(height) {},
+    
+    getInsets: function() {
+        return (this.border) ? this.border.getInsets() : this.emptyInsets();
+    },
+    
+    paint: function(ctx) {
+        console.log("default component paint");
+    },
+    
+    repaint: function() {
+        this.getScene().paint(this);
+    }
+});
+
+dojo.declare("th.Container", [th.Component, th.helpers.ContainerHelpers], {
+    constructor: function() {       
+        this.children = [];
+    },
+    
+    add: function() {
+        for (var z = 0; z < arguments.length; z++) {
+            component = dojo.isArray(arguments[z]) ? arguments[z] : [ arguments[z] ]; 
+            this.children = this.children.concat(component);
+            for (var i = 0; i < component.length; i++) {
+                component[i].parent = this;
+            }
+        }
+    },
+
+    remove: function() {
+        for (var z = 0; z < arguments.length; z++) {
+            component = dojo.isArray(arguments[z]) ? arguments[z] : [ arguments[z] ];
+            for (var i = 0; i < component.length; i++) {
+                var old_length = this.children.length;
+                this.children = dojo.filter(this.children, function(item){ return item != component[i]; });
+
+                // if the length of the array has changed since I tried to remove the current component, assume it was removed and clear the parent
+                if (old_length != this.children.length) delete component[i].parent;
+            }
+        }
+    },
+    
+    replace: function(component, index) {
+        this.bus.unbind(this.children[index]);
+        component.parent = this;
+        this.children[index] = component;
+    },
+
+    paint: function(ctx) {
+        if (this.shouldPaint()) {
+            this.paintSelf(ctx);
+            this.paintChildren(ctx);
+        }
+    },
+
+    paintSelf: function(ctx) {},
+
+    paintChildren: function(ctx) {
+        for (var i = 0; i < this.children.length; i++ ) {
+            if (!this.children[i].shouldPaint()) continue;
+
+            if (!this.children[i].bounds) {
+                // console.log("WARNING: child " + i + " (type: " + this.children[i].declaredClass + ", id: " + this.children[i].id + ") of parent with id " + this.id + " of type " + this.declaredClass + " has no bounds and could not be painted");
+                continue;
+            }
+
+            ctx.save();
+            try {
+                ctx.translate(this.children[i].bounds.x, this.children[i].bounds.y);
+            } catch (error) {
+                // console.log("WARNING: child " + i + " (type: " + this.children[i].declaredClass + ", id: " + this.children[i].id + ") of parent with id " + this.id + " of type " + this.declaredClass + " has malformed bounds and could not be painted");
+                // console.log(this.children[i].bounds);
+                ctx.restore();
+                continue;
+            }
+
+            try {
+                if (!this.children[i].style["noClip"]) {
+                    ctx.beginPath();
+                    ctx.rect(0, 0, this.children[i].bounds.width, this.children[i].bounds.height);
+                    ctx.closePath();
+                    ctx.clip();
+                }
+            } catch(ex) {
+                // console.log("Bounds problem");
+                // console.log(this.children[i].declaredClass);
+                // console.log(this.children[i].bounds);
+            }
+
+            ctx.save();
+            this.children[i].paint(ctx);
+            ctx.restore();
+
+            if (this.children[i].style.border) {
+                this.children[i].style.border.component = this.children[i];
+                ctx.save();
+                this.children[i].style.border.paint(ctx);
+                ctx.restore();
+            }
+
+            ctx.restore();
+        }
+    },
+
+    // lays out this container and any sub-containers
+    layoutTree: function() {
+        this.layout();
+        for (var i = 0; i < this.children.length; i++) {  
+            if (this.children[i].layoutTree) this.children[i].layoutTree();
+        }
+    },
+
+    layout: function() {
+        var d = this.d();
+        if (this.children.length > 0) {
+            var totalWidth = this.bounds.width - d.i.w;
+            var individualWidth = totalWidth / this.children.length;
+            for (var i = 0; i < this.children.length; i++) {
+                this.children[i].bounds = { x: (i * individualWidth) + d.i.l, y: d.i.t, width: individualWidth, height: this.bounds.height - d.i.h };
+            }
+        }
+    },
+
+    render: function() {
+        this.layoutTree();
+        this.repaint();
+    }
+});
+
+dojo.declare("th.Window", null, {
+    constructor: function(parms) {        
+        parms = parms || {};
+        
+        this.containerId = parms.containerId || false;
+        this.width = parms.width || 200;
+        this.height = parms.height || 300;
+        this.title = parms.title || 'NO TITLE GIVEN!';
+        this.y = parms.top || 50;
+        this.x = parms.left || 50;
+        this.isVisible = false;
+        this.closeOnClickOutside = !!parms.closeOnClickOutside;
+
+        // some things must be given
+        if(!parms.containerId) {
+            console.error('The "containerId" must be given!');
+            return;            
+        }
+        
+        if (dojo.byId(this.containerId)) {
+            console.error('There is already a element with the id "'+this.containerId+'"!');
+            return;
+        }
+                
+        if (!parms.userPanel) {
+            console.error('The "userPanel" must be given!');
+            return;
+        }
+        
+        // insert the HTML to the document for the new window and create the scene
+        dojo.byId('popup_insert_point').innerHTML += '<div id="'+this.containerId+'" class="popupWindow"></div>';
+        this.container = dojo.byId(this.containerId);
+        dojo.attr(this.container, { width: this.width, height: this.height, tabindex: '-1' });
+        this.container['moz-opaque'] = 'true';
+
+        this.container.innerHTML = "<canvas id='"+this.containerId+"_canvas'></canvas>";
+        this.canvas = dojo.byId(this.containerId + '_canvas');
+        dojo.attr(this.canvas, { width: this.width, height: this.height, tabindex: '-1' });
+        
+        this.scene = new th.Scene(this.canvas);
+        this.windowPanel = new th.components.WindowPanel(parms.title, parms.userPanel);
+        this.windowPanel.windowBar.parentWindow = this;  
+        this.scene.root.add(this.windowPanel);
+        
+        this.move(this.x, this.y);
+        
+        // add some listeners for closing the window
+        
+        // close the window, if the user clicks outside the window
+        dojo.connect(window, "mousedown", dojo.hitch(this, function(e) {
+            if (!this.isVisible || !this.closeOnClickOutside) return;
+
+            var d = dojo.coords(this.container);
+            if (e.clientX < d.l || e.clientX > (d.l + d.w) || e.clientY < d.t || e.clientY > (d.t + d.h)) {
+                this.toggle();
+            } else {
+                dojo.stopEvent(e);
+            }
+        }));
+        
+        // close the window, if the user pressed ESCAPE
+        dojo.connect(window, "keydown", dojo.hitch(this, function(e) {
+            if (!this.isVisible) return;
+            
+            if(e.keyCode == bespin.util.keys.Key.ESCAPE) {
+                this.toggle();
+                dojo.stopEvent(e);
+            }
+        }));
+    }, 
+         
+    toggle: function() {
+        this.isVisible = !this.isVisible;
+        
+        this.scene.bus.fire("toggle", {}, this);
+        
+        if (this.isVisible) {
+            this.container.style.display = 'block';
+            this.layoutAndRender();
+        } else {
+            this.container.style.display = 'none';
+        }
+    },
+    
+    layoutAndRender: function() {
+        this.scene.layout();
+        this.scene.render();
+    },
+    
+    centerUp: function() {
+        this.move(Math.round((window.innerWidth - this.width) * 0.5), Math.round((window.innerHeight - this.height) * 0.25));
+    },
+    
+    center: function() {
+        this.move(Math.round((window.innerWidth - this.width) * 0.5), Math.round((window.innerHeight - this.height) * 0.5));
+    },
+    
+    move: function(x, y) {
+        this.y = y;
+        this.x = x;
+        this.container.style.top = y + 'px';
+        this.container.style.left = x + 'px';
+    },
+    
+    getPosition: function() {
+        return { x: this.x, y: this.y };
+    }
+});

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/th/th.js
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp?rev=755934&r1=755933&r2=755934&view=diff
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp (original)
+++ camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp Thu Mar 19 11:27:43 2009
@@ -1,18 +1,36 @@
 <html>
 <head>
-  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title>Edit Route ${it.route.id}</title>
+  <script type='text/javascript' src="<c:url value='/js/dojo/dojo.js'/>"></script>
+  <script type='text/javascript' src="<c:url value='/js/bespin/editor/embed.js'/>"></script>
+  <script type='text/javascript' src="<c:url value='/js/route.js'/>"></script>
+
+  <title>Edit ${it.route.id}</title>
 </head>
 <body>
 
-<h2>Edit Route ${it.route.id}</h2>
-
-<div class="route">
+<form id="routeForm" action="<c:url value="/routes/${it.route.id}"/>" method="post">
+<table>
+  <tr>
+    <td>
+      <h2>Edit ${it.route.id}</h2>
+    </td>
+    <td>
+      <input type="button" value="Save" onclick="submitRoute()">
+    </td>
+    <td>
+      <textarea id="route" name="route" rows="1" cols="1"  style="visibility: hidden;"></textarea>
+    </td>
+  </tr>
+</table>
 
-<textarea rows="30" cols="80" name="body"><c:out value="${it.routeXml}" escapeXml="true" />
-</textarea>
+<div class="error">${it.error}</div>
 
+<div id="editor"
+     style="height: 300px; border: 10px solid #ddd; -moz-border-radius: 10px; -webkit-border-radius: 10px;">${it.routeXml}
 </div>
 
+</form>
+
+
 </body>
 </html>

Copied: camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/create.jsp (from r755542, camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp)
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/create.jsp?p2=camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/create.jsp&p1=camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp&r1=755542&r2=755934&rev=755934&view=diff
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RouteResource/edit.jsp (original)
+++ camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/create.jsp Thu Mar 19 11:27:43 2009
@@ -1,18 +1,40 @@
 <html>
 <head>
-  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
-  <title>Edit Route ${it.route.id}</title>
+  <script type='text/javascript' src="<c:url value='/js/dojo/dojo.js'/>"></script>
+  <script type='text/javascript' src="<c:url value='/js/bespin/editor/embed.js'/>"></script>
+  <script type='text/javascript' src="<c:url value='/js/route.js'/>"></script>
+
+  <title>Create New Route</title>
 </head>
 <body>
 
-<h2>Edit Route ${it.route.id}</h2>
-
-<div class="route">
+<form id="routeForm" action="<c:url value="/routes"/>" method="post">
+<table>
+  <tr>
+    <td>
+      <h2>Create New Route</h2>
+    </td>
+    <td>
+      <input type="button" value="Save" onclick="submitRoute()">
+    </td>
+    <td>
+      <textarea id="route" name="route" rows="1" cols="1"  style="visibility: hidden;"></textarea>
+    </td>
+  </tr>
+</table>
 
-<textarea rows="30" cols="80" name="body"><c:out value="${it.routeXml}" escapeXml="true" />
-</textarea>
+<div class="error">${it.error}</div>
 
+<div id="editor"
+     style="height: 300px; border: 10px solid #ddd; -moz-border-radius: 10px; -webkit-border-radius: 10px;">
+<route xmlns="http://camel.apache.org/schema/spring">
+  <from uri="seda:Some.Endpoint"/>
+  <to uri="seda:Some.Other.Endpoint"/>
+</route>
 </div>
 
+</form>
+
+
 </body>
 </html>

Modified: camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/index.jsp
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/index.jsp?rev=755934&r1=755933&r2=755934&view=diff
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/index.jsp (original)
+++ camel/trunk/components/camel-web/src/main/webapp/org/apache/camel/web/resources/RoutesResource/index.jsp Thu Mar 19 11:27:43 2009
@@ -16,7 +16,7 @@
   <c:forEach var="i" items="${it.routes}">
   <tr>
     <td>
-      <a href='<c:url value="/routes/${i.id}"/>'>${i.shortName}</a> ${i.description.text}
+      <a href='<c:url value="/routes/${i.id}/edit"/>'>${i.shortName}</a> ${i.description.text}
     </td>
     <td class="${i.status}">
       ${i.status}