You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by jk...@apache.org on 2006/03/11 22:19:18 UTC
svn commit: r385171 [15/24] - in
/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo:
./ src/ src/animation/ src/collections/ src/crypto/ src/data/ src/dnd/
src/event/ src/flash/ src/flash/flash6/ src/flash/flash8/ src/fx/ src/grap...
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DomWidget.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DomWidget.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DomWidget.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DomWidget.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,538 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.DomWidget");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.widget.Widget");
+dojo.require("dojo.dom");
+dojo.require("dojo.xml.Parse");
+dojo.require("dojo.uri.*");
+dojo.require("dojo.lang.func");
+
+dojo.widget._cssFiles = {};
+dojo.widget._templateCache = {};
+
+dojo.widget.defaultStrings = {
+ dojoRoot: dojo.hostenv.getBaseScriptUri(),
+ baseScriptUri: dojo.hostenv.getBaseScriptUri()
+};
+
+dojo.widget.buildFromTemplate = function() {
+ dojo.lang.forward("fillFromTemplateCache");
+}
+
+// static method to build from a template w/ or w/o a real widget in place
+dojo.widget.fillFromTemplateCache = function(obj, templatePath, templateCssPath, templateString, avoidCache){
+ // dojo.debug("avoidCache:", avoidCache);
+ var tpath = templatePath || obj.templatePath;
+ var cpath = templateCssPath || obj.templateCssPath;
+
+ // DEPRECATED: use Uri objects, not strings
+ if (tpath && !(tpath instanceof dojo.uri.Uri)) {
+ tpath = dojo.uri.dojoUri(tpath);
+ dojo.deprecated("templatePath should be of type dojo.uri.Uri");
+ }
+ if (cpath && !(cpath instanceof dojo.uri.Uri)) {
+ cpath = dojo.uri.dojoUri(cpath);
+ dojo.deprecated("templateCssPath should be of type dojo.uri.Uri");
+ }
+
+ var tmplts = dojo.widget._templateCache;
+ if(!obj["widgetType"]) { // don't have a real template here
+ do {
+ var dummyName = "__dummyTemplate__" + dojo.widget._templateCache.dummyCount++;
+ } while(tmplts[dummyName]);
+ obj.widgetType = dummyName;
+ }
+ var wt = obj.widgetType;
+
+ if((cpath)&&(!dojo.widget._cssFiles[cpath])){
+ dojo.style.insertCssFile(cpath);
+ obj.templateCssPath = null;
+ dojo.widget._cssFiles[cpath] = true;
+ }
+
+ var ts = tmplts[wt];
+ if(!ts){
+ tmplts[wt] = { "string": null, "node": null };
+ if(avoidCache){
+ ts = {};
+ }else{
+ ts = tmplts[wt];
+ }
+ }
+ if(!obj.templateString){
+ obj.templateString = templateString || ts["string"];
+ }
+ if(!obj.templateNode){
+ obj.templateNode = ts["node"];
+ }
+ if((!obj.templateNode)&&(!obj.templateString)&&(tpath)){
+ // fetch a text fragment and assign it to templateString
+ // NOTE: we rely on blocking IO here!
+ var tstring = dojo.hostenv.getText(tpath);
+ if(tstring){
+ var matches = tstring.match(/<body[^>]*>\s*([\s\S]+)\s*<\/body>/im);
+ if(matches){
+ tstring = matches[1];
+ }
+ }else{
+ tstring = "";
+ }
+ obj.templateString = tstring;
+ if(!avoidCache){
+ tmplts[wt]["string"] = tstring;
+ }
+ }
+ if((!ts["string"])&&(!avoidCache)){
+ ts.string = obj.templateString;
+ }
+}
+dojo.widget._templateCache.dummyCount = 0;
+
+dojo.widget.attachProperties = ["dojoAttachPoint", "id"];
+dojo.widget.eventAttachProperty = "dojoAttachEvent";
+dojo.widget.onBuildProperty = "dojoOnBuild";
+
+dojo.widget.attachTemplateNodes = function(rootNode, targetObj, events){
+ // FIXME: this method is still taking WAAAY too long. We need ways of optimizing:
+ // a.) what we are looking for on each node
+ // b.) the nodes that are subject to interrogation (use xpath instead?)
+ // c.) how expensive event assignment is (less eval(), more connect())
+ // var start = new Date();
+ var elementNodeType = dojo.dom.ELEMENT_NODE;
+
+ function trim(str){
+ return str.replace(/^\s+|\s+$/g, "");
+ }
+
+ if(!rootNode){
+ rootNode = targetObj.domNode;
+ }
+
+ if(rootNode.nodeType != elementNodeType){
+ return;
+ }
+ // alert(events.length);
+
+ var nodes = rootNode.getElementsByTagName("*");
+ var _this = targetObj;
+ for(var x=-1; x<nodes.length; x++){
+ var baseNode = (x == -1) ? rootNode : nodes[x];
+ // FIXME: is this going to have capitalization problems?
+ var attachPoint = [];
+ for(var y=0; y<this.attachProperties.length; y++){
+ var tmpAttachPoint = baseNode.getAttribute(this.attachProperties[y]);
+ if(tmpAttachPoint){
+ attachPoint = tmpAttachPoint.split(";");
+ for(var z=0; z<this.attachProperties.length; z++){
+ if((targetObj[attachPoint[z]])&&(dojo.lang.isArray(targetObj[attachPoint[z]]))){
+ targetObj[attachPoint[z]].push(baseNode);
+ }else{
+ targetObj[attachPoint[z]]=baseNode;
+ }
+ }
+ break;
+ }
+ }
+ // continue;
+
+ // FIXME: we need to put this into some kind of lookup structure
+ // instead of direct assignment
+ var tmpltPoint = baseNode.getAttribute(this.templateProperty);
+ if(tmpltPoint){
+ targetObj[tmpltPoint]=baseNode;
+ }
+
+ var attachEvent = baseNode.getAttribute(this.eventAttachProperty);
+ if(attachEvent){
+ // NOTE: we want to support attributes that have the form
+ // "domEvent: nativeEvent; ..."
+ var evts = attachEvent.split(";");
+ for(var y=0; y<evts.length; y++){
+ if((!evts[y])||(!evts[y].length)){ continue; }
+ var thisFunc = null;
+ var tevt = trim(evts[y]);
+ if(evts[y].indexOf(":") >= 0){
+ // oh, if only JS had tuple assignment
+ var funcNameArr = tevt.split(":");
+ tevt = trim(funcNameArr[0]);
+ thisFunc = trim(funcNameArr[1]);
+ }
+ if(!thisFunc){
+ thisFunc = tevt;
+ }
+
+ var tf = function(){
+ var ntf = new String(thisFunc);
+ return function(evt){
+ if(_this[ntf]){
+ _this[ntf](dojo.event.browser.fixEvent(evt));
+ }
+ };
+ }();
+ dojo.event.browser.addListener(baseNode, tevt, tf, false, true);
+ }
+ }
+
+ for(var y=0; y<events.length; y++){
+ //alert(events[x]);
+ var evtVal = baseNode.getAttribute(events[y]);
+ if((evtVal)&&(evtVal.length)){
+ var thisFunc = null;
+ var domEvt = events[y].substr(4); // clober the "dojo" prefix
+ thisFunc = trim(evtVal);
+ var tf = function(){
+ var ntf = new String(thisFunc);
+ return function(evt){
+ if(_this[ntf]){
+ _this[ntf](dojo.event.browser.fixEvent(evt));
+ }
+ }
+ }();
+ dojo.event.browser.addListener(baseNode, domEvt, tf, false, true);
+ }
+ }
+
+ var onBuild = baseNode.getAttribute(this.onBuildProperty);
+ if(onBuild){
+ eval("var node = baseNode; var widget = targetObj; "+onBuild);
+ }
+
+ // strip IDs to prevent dupes
+ baseNode.id = "";
+ }
+
+}
+
+dojo.widget.getDojoEventsFromStr = function(str){
+ // var lstr = str.toLowerCase();
+ var re = /(dojoOn([a-z]+)(\s?))=/gi;
+ var evts = str ? str.match(re)||[] : [];
+ var ret = [];
+ var lem = {};
+ for(var x=0; x<evts.length; x++){
+ if(evts[x].legth < 1){ continue; }
+ var cm = evts[x].replace(/\s/, "");
+ cm = (cm.slice(0, cm.length-1));
+ if(!lem[cm]){
+ lem[cm] = true;
+ ret.push(cm);
+ }
+ }
+ return ret;
+}
+
+
+dojo.widget.buildAndAttachTemplate = function(obj, templatePath, templateCssPath, templateString, targetObj) {
+ this.buildFromTemplate(obj, templatePath, templateCssPath, templateString);
+ var node = dojo.dom.createNodesFromText(obj.templateString, true)[0];
+ this.attachTemplateNodes(node, targetObj||obj, dojo.widget.getDojoEventsFromStr(templateString));
+ return node;
+}
+
+dojo.widget.DomWidget = function(){
+ dojo.widget.Widget.call(this);
+ if((arguments.length>0)&&(typeof arguments[0] == "object")){
+ this.create(arguments[0]);
+ }
+}
+dojo.inherits(dojo.widget.DomWidget, dojo.widget.Widget);
+
+dojo.lang.extend(dojo.widget.DomWidget, {
+ templateNode: null,
+ templateString: null,
+ preventClobber: false,
+ domNode: null, // this is our visible representation of the widget!
+ containerNode: null, // holds child elements
+
+ // Process the given child widget, inserting it's dom node as a child of our dom node
+ // FIXME: should we support addition at an index in the children arr and
+ // order the display accordingly? Right now we always append.
+ addChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
+ if(!this.isContainer){ // we aren't allowed to contain other widgets, it seems
+ dojo.debug("dojo.widget.DomWidget.addChild() attempted on non-container widget");
+ return null;
+ }else{
+ this.addWidgetAsDirectChild(widget, overrideContainerNode, pos, ref, insertIndex);
+ this.registerChild(widget, insertIndex);
+ }
+ return widget;
+ },
+
+ addWidgetAsDirectChild: function(widget, overrideContainerNode, pos, ref, insertIndex){
+ if((!this.containerNode)&&(!overrideContainerNode)){
+ this.containerNode = this.domNode;
+ }
+ var cn = (overrideContainerNode) ? overrideContainerNode : this.containerNode;
+ if(!pos){ pos = "after"; }
+ if(!ref){ ref = cn.lastChild; }
+ if(!insertIndex) { insertIndex = 0; }
+ widget.domNode.setAttribute("dojoinsertionindex", insertIndex);
+
+ // insert the child widget domNode directly underneath my domNode, in the
+ // specified position (by default, append to end)
+ if(!ref){
+ cn.appendChild(widget.domNode);
+ }else{
+ // FIXME: was this meant to be the (ugly hack) way to support insert @ index?
+ //dojo.dom[pos](widget.domNode, ref, insertIndex);
+
+ // CAL: this appears to be the intended way to insert a node at a given position...
+ if (pos == 'insertAtIndex'){
+ // dojo.debug("idx:", insertIndex, "isLast:", ref === cn.lastChild);
+ dojo.dom.insertAtIndex(widget.domNode, ref.parentNode, insertIndex);
+ }else{
+ // dojo.debug("pos:", pos, "isLast:", ref === cn.lastChild);
+ if((pos == "after")&&(ref === cn.lastChild)){
+ cn.appendChild(widget.domNode);
+ }else{
+ dojo.dom.insertAtPosition(widget.domNode, cn, pos);
+ }
+ }
+ }
+ },
+
+ // Record that given widget descends from me
+ registerChild: function(widget, insertionIndex){
+
+ // we need to insert the child at the right point in the parent's
+ // 'children' array, based on the insertionIndex
+
+ widget.dojoInsertionIndex = insertionIndex;
+
+ var idx = -1;
+ for(var i=0; i<this.children.length; i++){
+ if (this.children[i].dojoInsertionIndex < insertionIndex){
+ idx = i;
+ }
+ }
+
+ this.children.splice(idx+1, 0, widget);
+
+ widget.parent = this;
+ widget.addedTo(this);
+
+ // If this widget was created programatically, then it was erroneously added
+ // to dojo.widget.manager.topWidgets. Fix that here.
+ delete dojo.widget.manager.topWidgets[widget.widgetId];
+ },
+
+ removeChild: function(widget){
+ // detach child domNode from parent domNode
+ dojo.dom.removeNode(widget.domNode);
+
+ // remove child widget from parent widget
+ return dojo.widget.DomWidget.superclass.removeChild.call(this, widget);
+ },
+
+ getFragNodeRef: function(frag){
+ if( !frag["dojo:"+this.widgetType.toLowerCase()] ){
+ dojo.raise("Error: no frag for widget type " + this.widgetType +
+ ", id " + this.widgetId + " (maybe a widget has set it's type incorrectly)");
+ }
+ return (frag ? frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"] : null);
+ },
+
+ // Replace source domNode with generated dom structure, and register
+ // widget with parent.
+ postInitialize: function(args, frag, parentComp){
+ var sourceNodeRef = this.getFragNodeRef(frag);
+ // Stick my generated dom into the output tree
+ //alert(this.widgetId + ": replacing " + sourceNodeRef + " with " + this.domNode.innerHTML);
+ if (parentComp && (parentComp.snarfChildDomOutput || !sourceNodeRef)){
+ // Add my generated dom as a direct child of my parent widget
+ // This is important for generated widgets, and also cases where I am generating an
+ // <li> node that can't be inserted back into the original DOM tree
+ parentComp.addWidgetAsDirectChild(this, "", "insertAtIndex", "", args["dojoinsertionindex"], sourceNodeRef);
+ } else if (sourceNodeRef){
+ // Do in-place replacement of the my source node with my generated dom
+ if(this.domNode && (this.domNode !== sourceNodeRef)){
+ var oldNode = sourceNodeRef.parentNode.replaceChild(this.domNode, sourceNodeRef);
+ }
+ }
+
+ // Register myself with my parent, or with the widget manager if
+ // I have no parent
+ // TODO: the code below erroneously adds all programatically generated widgets
+ // to topWidgets (since we don't know who the parent is until after creation finishes)
+ if ( parentComp ) {
+ parentComp.registerChild(this, args.dojoinsertionindex);
+ } else {
+ dojo.widget.manager.topWidgets[this.widgetId]=this;
+ }
+
+ // Expand my children widgets
+ if(this.isContainer){
+ //alert("recurse from " + this.widgetId);
+ // build any sub-components with us as the parent
+ var fragParser = dojo.widget.getParser();
+ fragParser.createComponents(frag, this);
+ }
+ },
+
+ // method over-ride
+ buildRendering: function(args, frag){
+ // DOM widgets construct themselves from a template
+ var ts = dojo.widget._templateCache[this.widgetType];
+ if(
+ (!this.preventClobber)&&(
+ (this.templatePath)||
+ (this.templateNode)||
+ (
+ (this["templateString"])&&(this.templateString.length)
+ )||
+ (
+ (typeof ts != "undefined")&&( (ts["string"])||(ts["node"]) )
+ )
+ )
+ ){
+ // if it looks like we can build the thing from a template, do it!
+ this.buildFromTemplate(args, frag);
+ }else{
+ // otherwise, assign the DOM node that was the source of the widget
+ // parsing to be the root node
+ this.domNode = this.getFragNodeRef(frag);
+ }
+ this.fillInTemplate(args, frag); // this is where individual widgets
+ // will handle population of data
+ // from properties, remote data
+ // sets, etc.
+ },
+
+ buildFromTemplate: function(args, frag){
+ // var start = new Date();
+ // copy template properties if they're already set in the templates object
+ var avoidCache = false;
+ if(args["templatecsspath"]){
+ args["templateCssPath"] = args["templatecsspath"];
+ }
+ if(args["templatepath"]){
+ avoidCache = true;
+ args["templatePath"] = args["templatepath"];
+ }
+ dojo.widget.fillFromTemplateCache( this,
+ args["templatePath"],
+ args["templateCssPath"],
+ null,
+ avoidCache);
+ var ts = dojo.widget._templateCache[this.widgetType];
+ if((ts)&&(!avoidCache)){
+ if(!this.templateString.length){
+ this.templateString = ts["string"];
+ }
+ if(!this.templateNode){
+ this.templateNode = ts["node"];
+ }
+ }
+ var matches = false;
+ var node = null;
+ // var tstr = new String(this.templateString);
+ var tstr = this.templateString;
+ // attempt to clone a template node, if there is one
+ if((!this.templateNode)&&(this.templateString)){
+ matches = this.templateString.match(/\$\{([^\}]+)\}/g);
+ if(matches) {
+ // if we do property replacement, don't create a templateNode
+ // to clone from.
+ var hash = this.strings || {};
+ // FIXME: should this hash of default replacements be cached in
+ // templateString?
+ for(var key in dojo.widget.defaultStrings) {
+ if(dojo.lang.isUndefined(hash[key])) {
+ hash[key] = dojo.widget.defaultStrings[key];
+ }
+ }
+ // FIXME: this is a lot of string munging. Can we make it faster?
+ for(var i = 0; i < matches.length; i++) {
+ var key = matches[i];
+ key = key.substring(2, key.length-1);
+ var kval = (key.substring(0, 5) == "this.") ? this[key.substring(5)] : hash[key];
+ var value;
+ if((kval)||(dojo.lang.isString(kval))){
+ value = (dojo.lang.isFunction(kval)) ? kval.call(this, key, this.templateString) : kval;
+ tstr = tstr.replace(matches[i], value);
+ }
+ }
+ }else{
+ // otherwise, we are required to instantiate a copy of the template
+ // string if one is provided.
+
+ // FIXME: need to be able to distinguish here what should be done
+ // or provide a generic interface across all DOM implementations
+ // FIMXE: this breaks if the template has whitespace as its first
+ // characters
+ // node = this.createNodesFromText(this.templateString, true);
+ // this.templateNode = node[0].cloneNode(true); // we're optimistic here
+ this.templateNode = this.createNodesFromText(this.templateString, true)[0];
+ ts.node = this.templateNode;
+ }
+ }
+ if((!this.templateNode)&&(!matches)){
+ dojo.debug("weren't able to create template!");
+ return false;
+ }else if(!matches){
+ node = this.templateNode.cloneNode(true);
+ if(!node){ return false; }
+ }else{
+ node = this.createNodesFromText(tstr, true)[0];
+ }
+
+ // recurse through the node, looking for, and attaching to, our
+ // attachment points which should be defined on the template node.
+
+ this.domNode = node;
+ // dojo.profile.start("attachTemplateNodes");
+ this.attachTemplateNodes(this.domNode, this);
+ // dojo.profile.end("attachTemplateNodes");
+
+ // relocate source contents to templated container node
+ // this.containerNode must be able to receive children, or exceptions will be thrown
+ if (this.isContainer && this.containerNode){
+ var src = this.getFragNodeRef(frag);
+ if (src){
+ dojo.dom.moveChildren(src, this.containerNode);
+ }
+ }
+ },
+
+ attachTemplateNodes: function(baseNode, targetObj){
+ if(!targetObj){ targetObj = this; }
+ return dojo.widget.attachTemplateNodes(baseNode, targetObj,
+ dojo.widget.getDojoEventsFromStr(this.templateString));
+ },
+
+ fillInTemplate: function(){
+ // dj_unimplemented("dojo.widget.DomWidget.fillInTemplate");
+ },
+
+ // method over-ride
+ destroyRendering: function(){
+ try{
+ delete this.domNode;
+ }catch(e){ /* squelch! */ }
+ },
+
+ // FIXME: method over-ride
+ cleanUp: function(){},
+
+ getContainerHeight: function(){
+ dj_unimplemented("dojo.widget.DomWidget.getContainerHeight");
+ },
+
+ getContainerWidth: function(){
+ dj_unimplemented("dojo.widget.DomWidget.getContainerWidth");
+ },
+
+ createNodesFromText: function(){
+ dj_unimplemented("dojo.widget.DomWidget.createNodesFromText");
+ }
+});
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DropdownButton.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DropdownButton.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DropdownButton.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/DropdownButton.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,29 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+dojo.provide("dojo.widget.DropdownButton");
+
+dojo.deprecated("dojo.widget.DropdownButton", "use dojo.widget.ComboButton2", "0.4");
+
+// Draws a button with a down arrow;
+// when you press the down arrow something appears (usually a menu)
+
+dojo.require("dojo.widget.*");
+
+dojo.widget.tags.addParseTreeHandler("dojo:dropdownbutton");
+
+dojo.widget.DropdownButton = function(){
+ dojo.widget.Widget.call(this);
+
+ this.widgetType = "DropdownButton";
+}
+dojo.inherits(dojo.widget.DropdownButton, dojo.widget.Widget);
+
+dojo.requireAfterIf("html", "dojo.widget.html.DropdownButton");
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/Editor.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/Editor.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/Editor.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/Editor.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,497 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/* TODO:
+ * - font selector
+ * - test, bug fix, more features :)
+*/
+dojo.provide("dojo.widget.Editor");
+dojo.provide("dojo.widget.html.Editor");
+dojo.require("dojo.widget.*");
+dojo.require("dojo.widget.Toolbar");
+dojo.require("dojo.widget.RichText");
+dojo.require("dojo.widget.ColorPalette");
+dojo.require("dojo.string.extras");
+
+dojo.widget.tags.addParseTreeHandler("dojo:Editor");
+
+dojo.widget.html.Editor = function() {
+ dojo.widget.HtmlWidget.call(this);
+ this.contentFilters = [];
+}
+dojo.inherits(dojo.widget.html.Editor, dojo.widget.HtmlWidget);
+
+dojo.widget.html.Editor.itemGroups = {
+ textGroup: ["bold", "italic", "underline", "strikethrough"],
+ blockGroup: ["formatBlock", "fontName", "fontSize"],
+ justifyGroup: ["justifyleft", "justifycenter", "justifyright"],
+ commandGroup: ["save", "cancel"],
+ colorGroup: ["forecolor", "hilitecolor"],
+ listGroup: ["insertorderedlist", "insertunorderedlist"],
+ indentGroup: ["outdent", "indent"],
+ linkGroup: ["createlink", "insertimage", "inserthorizontalrule"]
+};
+
+dojo.widget.html.Editor.formatBlockValues = {
+ "Normal": "p",
+ "Main heading": "h2",
+ "Sub heading": "h3",
+ "Sub sub heading": "h4",
+ "Preformatted": "pre"
+};
+
+dojo.widget.html.Editor.fontNameValues = {
+ "Arial": "Arial, Helvetica, sans-serif",
+ "Verdana": "Verdana, sans-serif",
+ "Times New Roman": "Times New Roman, serif",
+ "Courier": "Courier New, monospace"
+};
+
+dojo.widget.html.Editor.fontSizeValues = {
+ "1 (8 pt)" : "1",
+ "2 (10 pt)": "2",
+ "3 (12 pt)": "3",
+ "4 (14 pt)": "4",
+ "5 (18 pt)": "5",
+ "6 (24 pt)": "6",
+ "7 (36 pt)": "7"
+};
+
+dojo.widget.html.Editor.defaultItems = [
+ "commandGroup", "|", "blockGroup", "|", "textGroup", "|", "colorGroup", "|", "justifyGroup", "|", "listGroup", "indentGroup", "|", "linkGroup"
+];
+
+// ones we support by default without asking the RichText component
+// NOTE: you shouldn't put buttons like bold, italic, etc in here
+dojo.widget.html.Editor.supportedCommands = ["save", "cancel", "|", "-", "/", " "];
+
+dojo.lang.extend(dojo.widget.html.Editor, {
+ widgetType: "Editor",
+
+ items: dojo.widget.html.Editor.defaultItems,
+ formatBlockItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.formatBlockValues),
+ fontNameItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.fontNameValues),
+ fontSizeItems: dojo.lang.shallowCopy(dojo.widget.html.Editor.fontSizeValues),
+
+ // used to get the properties of an item if it is given as a string
+ getItemProperties: function(name) {
+ var props = {};
+ switch(name.toLowerCase()) {
+ case "bold":
+ case "italic":
+ case "underline":
+ case "strikethrough":
+ props.toggleItem = true;
+ break;
+
+ case "justifygroup":
+ props.defaultButton = "justifyleft";
+ props.preventDeselect = true;
+ props.buttonGroup = true;
+ break;
+
+ case "listgroup":
+ props.buttonGroup = true;
+ break;
+
+ case "save":
+ case "cancel":
+ props.label = dojo.string.capitalize(name);
+ break;
+
+ case "forecolor":
+ case "hilitecolor":
+ props.name = name;
+ props.toggleItem = true; // FIXME: they aren't exactly toggle items
+ props.icon = this.getCommandImage(name);
+ break;
+
+ case "formatblock":
+ props.name = "formatBlock";
+ props.values = this.formatBlockItems;
+ break;
+
+ case "fontname":
+ props.name = "fontName";
+ props.values = this.fontNameItems;
+
+ case "fontsize":
+ props.name = "fontSize";
+ props.values = this.fontSizeItems;
+ }
+ return props;
+ },
+
+ validateItems: true, // set to false to add items, regardless of support
+ focusOnLoad: true,
+ minHeight: "1em",
+
+ _richText: null, // RichText widget
+ _richTextType: "RichText",
+
+ _toolbarContainer: null, // ToolbarContainer widget
+ _toolbarContainerType: "ToolbarContainer",
+
+ _toolbars: [],
+ _toolbarType: "Toolbar",
+
+ _toolbarItemType: "ToolbarItem",
+
+ buildRendering: function(args, frag) {
+ // get the node from args/frag
+ var node = frag["dojo:"+this.widgetType.toLowerCase()]["nodeRef"];
+ var trt = dojo.widget.createWidget(this._richTextType, {
+ focusOnLoad: this.focusOnLoad,
+ minHeight: this.minHeight
+ }, node)
+ var _this = this;
+ // this appears to fix a weird timing bug on Safari
+ setTimeout(function(){
+ _this.setRichText(trt);
+
+ _this.initToolbar();
+
+ _this.fillInTemplate(args, frag);
+ }, 0);
+ },
+
+ setRichText: function(richText) {
+ if(this._richText && this._richText == richText) {
+ dojo.debug("Already set the richText to this richText!");
+ return;
+ }
+
+ if(this._richText && !this._richText.isClosed) {
+ dojo.debug("You are switching richTexts yet you haven't closed the current one. Losing reference!");
+ }
+ this._richText = richText;
+ dojo.event.connect(this._richText, "close", this, "onClose");
+ dojo.event.connect(this._richText, "onLoad", this, "onLoad");
+ dojo.event.connect(this._richText, "onDisplayChanged", this, "updateToolbar");
+ if(this._toolbarContainer) {
+ this._toolbarContainer.enable();
+ this.updateToolbar(true);
+ }
+ },
+
+ initToolbar: function() {
+ // var tic = new Date();
+ if(this._toolbarContainer) { return; } // only create it once
+ this._toolbarContainer = dojo.widget.createWidget(this._toolbarContainerType);
+ var tb = this.addToolbar();
+ var last = true;
+ for(var i = 0; i < this.items.length; i++) {
+ if(this.items[i] == "\n") { // new row
+ tb = this.addToolbar();
+ } else {
+ if((this.items[i] == "|")&&(!last)){
+ last = true;
+ }else{
+ last = this.addItem(this.items[i], tb);
+ }
+ }
+ }
+ this.insertToolbar(this._toolbarContainer.domNode, this._richText.domNode);
+ // alert(new Date - tic);
+ },
+
+ // allow people to override this so they can make their own placement logic
+ insertToolbar: function(tbNode, richTextNode) {
+ dojo.html.insertBefore(tbNode, richTextNode);
+ //dojo.html.insertBefore(this._toolbarContainer.domNode, this._richText.domNode);
+ },
+
+ addToolbar: function(toolbar) {
+ this.initToolbar();
+ if(!(toolbar instanceof dojo.widget.html.Toolbar)) {
+ toolbar = dojo.widget.createWidget(this._toolbarType);
+ }
+ this._toolbarContainer.addChild(toolbar);
+ this._toolbars.push(toolbar);
+ return toolbar;
+ },
+
+ addItem: function(item, tb, dontValidate) {
+ if(!tb) { tb = this._toolbars[0]; }
+ var cmd = ((item)&&(!dojo.lang.isUndefined(item["getValue"]))) ? cmd = item["getValue"](): item;
+
+ var groups = dojo.widget.html.Editor.itemGroups;
+ if(item instanceof dojo.widget.ToolbarItem) {
+ tb.addChild(item);
+ } else if(groups[cmd]) {
+ var group = groups[cmd];
+ var worked = true;
+ if(cmd == "justifyGroup" || cmd == "listGroup") {
+ var btnGroup = [cmd];
+ for(var i = 0 ; i < group.length; i++) {
+ if(dontValidate || this.isSupportedCommand(group[i])) {
+ btnGroup.push(this.getCommandImage(group[i]));
+ }else{
+ worked = false;
+ }
+ }
+ if(btnGroup.length) {
+ var btn = tb.addChild(btnGroup, null, this.getItemProperties(cmd));
+ dojo.event.connect(btn, "onClick", this, "_action");
+ dojo.event.connect(btn, "onChangeSelect", this, "_action");
+ }
+ return worked;
+ } else {
+ for(var i = 0; i < group.length; i++) {
+ if(!this.addItem(group[i], tb)){
+ worked = false;
+ }
+ }
+ return worked;
+ }
+ } else {
+ if((!dontValidate)&&(!this.isSupportedCommand(cmd))){
+ return false;
+ }
+ if(dontValidate || this.isSupportedCommand(cmd)) {
+ cmd = cmd.toLowerCase();
+ if(cmd == "formatblock") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "formatBlock",
+ values: this.formatBlockItems
+ });
+ tb.addChild(select);
+ var _this = this;
+ dojo.event.connect(select, "onSetValue", function(item, value) {
+ _this.onAction("formatBlock", value);
+ });
+ } else if(cmd == "fontname") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "fontName",
+ values: this.fontNameItems
+ });
+ tb.addChild(select);
+ dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+ this.onAction("fontName", value);
+ }));
+ } else if(cmd == "fontsize") {
+ var select = dojo.widget.createWidget("ToolbarSelect", {
+ name: "fontSize",
+ values: this.fontSizeItems
+ });
+ tb.addChild(select);
+ dojo.event.connect(select, "onSetValue", dojo.lang.hitch(this, function(item, value) {
+ this.onAction("fontSize", value);
+ }));
+ } else if(dojo.lang.inArray(cmd, ["forecolor", "hilitecolor"])) {
+ var btn = tb.addChild(dojo.widget.createWidget("ToolbarColorDialog", this.getItemProperties(cmd)));
+ dojo.event.connect(btn, "onSetValue", this, "_setValue");
+ } else {
+ var btn = tb.addChild(this.getCommandImage(cmd), null, this.getItemProperties(cmd));
+ if(dojo.lang.inArray(cmd, ["save", "cancel"])) {
+ dojo.event.connect(btn, "onClick", this, "_close");
+ } else {
+ dojo.event.connect(btn, "onClick", this, "_action");
+ dojo.event.connect(btn, "onChangeSelect", this, "_action");
+ }
+ }
+ }
+ }
+ return true;
+ },
+
+ enableToolbar: function() {
+ if(this._toolbarContainer) {
+ this._toolbarContainer.domNode.style.display = "";
+ this._toolbarContainer.enable();
+ }
+ },
+
+ disableToolbar: function(hide){
+ if(hide){
+ if(this._toolbarContainer){
+ this._toolbarContainer.domNode.style.display = "none";
+ }
+ }else{
+ if(this._toolbarContainer){
+ this._toolbarContainer.disable();
+ }
+ }
+ },
+
+ _updateToolbarLastRan: null,
+ _updateToolbarTimer: null,
+ _updateToolbarFrequency: 500,
+
+ updateToolbar: function(force) {
+ if(!this._toolbarContainer) { return; }
+
+ // keeps the toolbar from updating too frequently
+ // TODO: generalize this functionality?
+ var diff = new Date() - this._updateToolbarLastRan;
+ if(!force && this._updateToolbarLastRan && (diff < this._updateToolbarFrequency)) {
+ clearTimeout(this._updateToolbarTimer);
+ var _this = this;
+ this._updateToolbarTimer = setTimeout(function() {
+ _this.updateToolbar();
+ }, this._updateToolbarFrequency/2);
+ return;
+ } else {
+ this._updateToolbarLastRan = new Date();
+ }
+ // end frequency checker
+
+ var items = this._toolbarContainer.getItems();
+ for(var i = 0; i < items.length; i++) {
+ var item = items[i];
+ if(item instanceof dojo.widget.html.ToolbarSeparator) { continue; }
+ var cmd = item._name;
+ if (cmd == "save" || cmd == "cancel") { continue; }
+ else if(cmd == "justifyGroup") {
+ try {
+ if(!this._richText.queryCommandEnabled("justifyleft")) {
+ item.disable(false, true);
+ } else {
+ item.enable(false, true);
+ var jitems = item.getItems();
+ for(var j = 0; j < jitems.length; j++) {
+ var name = jitems[j]._name;
+ var value = this._richText.queryCommandValue(name);
+ if(typeof value == "boolean" && value) {
+ value = name;
+ break;
+ } else if(typeof value == "string") {
+ value = "justify"+value;
+ } else {
+ value = null;
+ }
+ }
+ if(!value) { value = "justifyleft"; } // TODO: query actual style
+ item.setValue(value, false, true);
+ }
+ } catch(err) {}
+ } else if(cmd == "listGroup") {
+ var litems = item.getItems();
+ for(var j = 0; j < litems.length; j++) {
+ this.updateItem(litems[j]);
+ }
+ } else {
+ this.updateItem(item);
+ }
+ }
+ },
+
+ updateItem: function(item) {
+ try {
+ var cmd = item._name;
+ var enabled = this._richText.queryCommandEnabled(cmd);
+ item.setEnabled(enabled, false, true);
+
+ var active = this._richText.queryCommandState(cmd);
+ if(active && cmd == "underline") {
+ // don't activate underlining if we are on a link
+ active = !this._richText.queryCommandEnabled("unlink");
+ }
+ item.setSelected(active, false, true);
+ return true;
+ } catch(err) {
+ return false;
+ }
+ },
+
+ supportedCommands: dojo.widget.html.Editor.supportedCommands.concat(),
+
+ isSupportedCommand: function(cmd) {
+ // FIXME: how do we check for ActiveX?
+ var yes = dojo.lang.inArray(cmd, this.supportedCommands);
+ if(!yes) {
+ try {
+ var richText = this._richText || dojo.widget.HtmlRichText.prototype;
+ yes = richText.queryCommandAvailable(cmd);
+ } catch(E) {}
+ }
+ return yes;
+ },
+
+ getCommandImage: function(cmd) {
+ if(cmd == "|") {
+ return cmd;
+ } else {
+ return dojo.uri.dojoUri("src/widget/templates/buttons/" + cmd + ".gif");
+ }
+ },
+
+ _action: function(e) {
+ this._fire("onAction", e.getValue());
+ },
+
+ _setValue: function(a, b) {
+ this._fire("onAction", a.getValue(), b);
+ },
+
+ _close: function(e) {
+ if(!this._richText.isClosed) {
+ this._richText.close(e.getName().toLowerCase() == "save");
+ }
+ },
+
+ onAction: function(cmd, value) {
+ switch(cmd) {
+ case "createlink":
+ if(!(value = prompt("Please enter the URL of the link:", "http://"))) {
+ return;
+ }
+ break;
+ case "insertimage":
+ if(!(value = prompt("Please enter the URL of the image:", "http://"))) {
+ return;
+ }
+ break;
+ }
+ this._richText.execCommand(cmd, value);
+ },
+
+ fillInTemplate: function(args, frag) {
+ // dojo.event.connect(this, "onResized", this._richText, "onResized");
+ },
+
+ _fire: function(eventName) {
+ if(dojo.lang.isFunction(this[eventName])) {
+ var args = [];
+ if(arguments.length == 1) {
+ args.push(this);
+ } else {
+ for(var i = 1; i < arguments.length; i++) {
+ args.push(arguments[i]);
+ }
+ }
+ this[eventName].apply(this, args);
+ }
+ },
+
+ getHtml: function(){
+ this._richText.contentFilters = this.contentFilters;
+ return this._richText.getEditorContent();
+ },
+
+ getEditorContent: function(){
+ return this.getHtml();
+ },
+
+ onClose: function(save, hide){
+ this.disableToolbar(hide);
+ if(save) {
+ this._fire("onSave");
+ } else {
+ this._fire("onCancel");
+ }
+ },
+
+ // events baby!
+ onLoad: function(){},
+ onSave: function(){},
+ onCancel: function(){}
+});
+
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTree.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTree.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTree.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTree.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,376 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+/**
+ * Tree model does all the drawing, visual node management etc.
+ * Throws events about clicks on it, so someone may catch them and process
+ * Tree knows nothing about DnD stuff, covered in TreeDragAndDrop and (if enabled) attached by controller
+*/
+dojo.provide("dojo.widget.EditorTree");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.HtmlWidget");
+dojo.require("dojo.widget.EditorTreeNode");
+dojo.require("dojo.widget.EditorTreeSelector");
+dojo.require("dojo.widget.EditorTreeController");
+
+dojo.deprecated("dojo.widget.EditorTree", "refactored & moved to dojo.widget.Tree");
+
+
+// make it a tag
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTree");
+
+
+dojo.widget.EditorTree = function() {
+ dojo.widget.HtmlWidget.call(this);
+
+ this.eventNames = {
+ // new node built.. Well, just built
+ nodeCreate: "",
+ // expand icon clicked
+ treeClick: "",
+ // node icon clicked
+ iconClick: "",
+ // node title clicked
+ titleClick: ""
+ };
+
+ this.tree = this;
+ this.acceptDropSources = [];
+ this.actionsDisabled = [];
+
+}
+dojo.inherits(dojo.widget.EditorTree, dojo.widget.HtmlWidget);
+
+/* extend DOES NOT copy recursively */
+dojo.lang.extend(dojo.widget.EditorTree, {
+ widgetType: "EditorTree",
+
+ isContainer: true,
+
+ acceptDropSources: "",
+
+ templateCssPath: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/EditorTree.css"),
+
+ templateString: '<div class="dojoTree"></div>',
+
+ /* Model events */
+ eventNames: null,
+ eventNaming: "default",
+
+ isExpanded: true, // consider this "root node" to be always expanded
+
+ isTree: true,
+
+ objectId: "",
+
+
+ //
+ // these icons control the grid and expando buttons for the whole tree
+ //
+
+ blankIconSrc: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_blank.gif"),
+
+ gridIconSrcT: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_t.gif"), // for non-last child grid
+ gridIconSrcL: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_l.gif"), // for last child grid
+ gridIconSrcV: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_v.gif"), // vertical line
+ gridIconSrcP: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_p.gif"), // for under parent item child icons
+ gridIconSrcC: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_c.gif"), // for under child item child icons
+ gridIconSrcX: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_x.gif"), // grid for sole root item
+ gridIconSrcY: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_y.gif"), // grid for last rrot item
+ gridIconSrcZ: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_grid_z.gif"), // for under root parent item child icon
+
+ expandIconSrcPlus: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_expand_plus.gif"),
+ expandIconSrcMinus: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_expand_minus.gif"),
+ expandIconSrcLoading: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/treenode_loading.gif"),
+
+
+ iconWidth: 18,
+ iconHeight: 18,
+
+
+ //
+ // tree options
+ //
+
+ showGrid: true,
+ showRootGrid: true,
+
+ selector: null,
+
+
+ actionIsDisabled: function(action) {
+ var _this = this;
+ return dojo.lang.inArray(_this.actionsDisabled, action)
+ },
+
+
+ actions: {
+ ADDCHILD: "ADDCHILD"
+ },
+
+
+ getInfo: function() {
+ var info = {
+ widgetId: this.widgetId,
+ objectId: this.objectId
+ }
+
+ return info;
+ },
+
+ initialize: function(args, frag){
+
+ var _this = this;
+
+
+ //this.actionsDisabled = this.actionsDisabled.split(",");
+ for(var i=0; i<this.actionsDisabled.length; i++) {
+ this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+ }
+
+
+
+ if (this.eventNaming == "default") { // IE || FF
+
+ for (eventName in this.eventNames) {
+ this.eventNames[eventName] = this.widgetId+"/"+eventName;
+ }
+ }
+
+
+ if (args['controller']) {
+ var controller = dojo.widget.manager.getWidgetById(args['controller']);
+
+ controller.subscribeTree(this); // controller listens to my events
+ }
+
+ if (args['selector']) {
+ this.selector = dojo.widget.manager.getWidgetById(args['selector']);
+ } else {
+ this.selector = new dojo.widget.createWidget("EditorTreeSelector");
+ }
+
+ this.containerNode = this.domNode;
+
+ },
+
+
+
+ postCreate: function() {
+ this.buildTree();
+ },
+
+ buildTree: function() {
+
+ dojo.html.disableSelection(this.domNode);
+
+ for(var i=0; i<this.children.length; i++){
+ this.children[i].parent = this; // root nodes have tree as parent
+
+ var node = this.children[i].buildNode(this, 0);
+
+
+ this.domNode.appendChild(node);
+ }
+
+
+
+ if (!this.showRootGrid){
+ for(var i=0; i<this.children.length; i++){
+ this.children[i].expand();
+ }
+ }
+
+
+ },
+
+
+
+ /**
+ * Move child to newParent as last child
+ * redraw tree and update icons
+ */
+ changeParent: function(child, newParent, index) {
+// dojo.debug("Move "+child+" to "+newParent+" index "+index)
+
+ //dojo.debug(dojo.widget.manager.getWidgetById('1.3').containerNode.style.display);
+
+ var destIdx = index;
+/*
+ if (child.parent === newParent && child.getParentIndex()<=index) {
+ dojo.debug("shift dest index")
+ destIdx--; // shift index cause child.length is less by 1 after removal
+ }
+ */
+
+ /* do actual parent change here. Write remove child first */
+ child.parent.removeChild(child);
+
+ newParent.addChild(child, destIdx);
+
+ },
+
+ // FIXME: removeChild may leak because events do not get cleaned on removal like:
+ // dojo.event.browser.clean( parent.removeChild( child ) );
+ // From the other hand, if I clean events I have to reinsert'em later..
+ // maybe supply "clean" parameter ?
+ removeChild: function(child) {
+
+ var parent = child.parent;
+
+ var children = parent.children;
+
+ for(var i=0; i<children.length; i++){
+ if(children[i] === child){
+ children.splice(i, 1);
+ break;
+ }
+ }
+
+ dojo.dom.removeNode(child.domNode);
+
+
+ parent.updateIconTree();
+
+ return child;
+
+ },
+
+
+
+ // not called for initial tree building. See buildNode instead.
+ // builds child html node if needed
+ // index is "last node" by default
+ addChild: function(child, index){
+
+
+ dojo.profile.start("AddChild");
+
+ if (dojo.lang.isUndefined(index)) {
+ index = this.children.length;
+ }
+
+ if (!child.isTreeNode){
+ dojo.raise("You can only add EditorTreeNode widgets to a "+this.widgetType+" widget!");
+ return;
+ }
+
+ // usually it is impossible to change "isFolder" state, but if anyone wants to add a child to leaf,
+ // it is possible program-way.
+ if (this.isTreeNode){
+ if (!this.isFolder) { // just became a folder.
+ this.setFolder();
+ }
+ }
+
+ // adjust tree
+ var _this = this;
+ dojo.lang.forEach(child.getDescendants(), function(elem) { elem.tree = _this.tree; });
+
+ // fix parent
+ child.parent = this;
+
+
+ // no dynamic loading for those who are parents already
+ if (this.isTreeNode) {
+ this.state = this.loadStates.LOADED;
+ }
+
+ // if node exists - adjust its depth, otherwise build it
+ if (child.domNodeInitialized) {
+ //dojo.debug(this.widgetType)
+ var d = this.isTreeNode ? this.depth : -1;
+ //dojo.debug('Depth is '+this.depth);
+ child.adjustDepth( d - child.depth + 1 );
+ } else {
+ child.depth = this.isTreeNode ? this.depth+1 : 0;
+ child.buildNode(child.tree, child.depth);
+ }
+
+
+ //dojo.debug(child.domNode.outerHTML)
+
+ if (index < this.children.length) {
+
+ //dojo.debug('insert '+index)
+ //dojo.debugShallow(child);
+
+ // insert
+ dojo.dom.insertBefore(child.domNode, this.children[index].domNode);
+ } else {
+ this.containerNode.appendChild(child.domNode);
+ }
+
+ /*
+ if (index == this.children.length && this.children.length == 0) {
+ this.containerNode.style.display = 'block';
+ }
+ */
+
+ this.children.splice(index, 0, child);
+
+ dojo.profile.end("AddChild");
+
+ dojo.profile.start("updateIconTree");
+
+ //this.updateIconTree();
+ //dojo.debug("Update my icons: "+child)
+ child.updateIcons();
+ if (child.isFirstNode() && child.getNextSibling()) {
+ //dojo.debug("Update expand for"+child.getNextSibling())
+ child.getNextSibling().updateExpandIcon();
+ }
+ if (child.isLastNode() && child.getPreviousSibling()) {
+ //dojo.debug("Update expand for"+child.getPreviousSibling())
+ child.getPreviousSibling().updateExpandIcon();
+ }
+
+
+ dojo.profile.end("updateIconTree");
+
+
+ },
+
+ makeBlankImg: function() {
+ var img = document.createElement('img');
+
+ img.style.width = this.iconWidth + 'px';
+ img.style.height = this.iconHeight + 'px';
+ img.src = this.blankIconSrc;
+ img.style.verticalAlign = 'middle';
+
+ return img;
+ },
+
+
+ updateIconTree: function(){
+
+ //dojo.debug("Update icons for "+this)
+ if (!this.isTree) {
+ this.updateIcons();
+ }
+
+ for(var i=0; i<this.children.length; i++){
+ this.children[i].updateIconTree();
+ }
+
+ },
+
+ toString: function() {
+ return "["+this.widgetType+" ID:"+this.widgetId+"]"
+ }
+
+
+
+
+
+});
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeContextMenu.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeContextMenu.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeContextMenu.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeContextMenu.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,143 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.EditorTreeContextMenu");
+dojo.provide("dojo.widget.EditorTreeMenuItem");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.io.*");
+dojo.require("dojo.widget.Menu2");
+
+dojo.deprecated("dojo.widget.EditorTreeContextMenu", "use dojo.widget.TreeContextMenu");
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTreeContextMenu");
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTreeMenuItem");
+
+
+
+dojo.widget.EditorTreeContextMenu = function() {
+ dojo.widget.PopupMenu2.call(this);
+
+
+}
+
+
+dojo.inherits(dojo.widget.EditorTreeContextMenu, dojo.widget.PopupMenu2);
+
+dojo.lang.extend(dojo.widget.EditorTreeContextMenu, {
+
+ widgetType: "EditorTreeContextMenu",
+
+ open: function(x, y, parentMenu, explodeSrc){
+
+ var result = dojo.widget.PopupMenu2.prototype.open.apply(this, arguments);
+
+ /* publish many events here about structural changes */
+ dojo.event.topic.publish(this.eventNames.open, { menu:this });
+
+ return result;
+ },
+
+ bindToTree: function(tree) {
+ /* add context menu to all nodes that exist already */
+ var nodes = tree.getDescendants();
+
+ for(var i=0; i<nodes.length; i++) {
+ if (!nodes[i].isTreeNode) continue;
+ this.bindDomNode(nodes[i].labelNode);
+ }
+
+
+ /* bind context menu to all nodes that will be created in the future (e.g loaded from server)*/
+ var _this = this;
+ dojo.event.topic.subscribe(tree.eventNames.nodeCreate,
+ function(message) { _this.bindDomNode(message.source.labelNode); }
+ );
+ }
+
+
+
+
+});
+
+
+
+
+
+
+dojo.widget.EditorTreeMenuItem = function() {
+ dojo.widget.MenuItem2.call(this);
+
+}
+
+
+dojo.inherits(dojo.widget.EditorTreeMenuItem, dojo.widget.MenuItem2);
+
+
+dojo.lang.extend(dojo.widget.EditorTreeMenuItem, {
+
+ widgetType: "EditorTreeMenuItem",
+
+ // treeActions menu item performs following actions (to be checked for permissions)
+ treeActions: "",
+
+ initialize: function(args, frag) {
+
+ this.treeActions = this.treeActions.split(",");
+ for(var i=0; i<this.treeActions.length; i++) {
+ this.treeActions[i] = this.treeActions[i].toUpperCase();
+ }
+
+ },
+
+ getTreeNode: function() {
+ var menu = this;
+
+ while (! (menu instanceof dojo.widget.EditorTreeContextMenu) ) {
+ menu = menu.parent;
+ }
+
+ var source = menu.getTopOpenEvent().target;
+
+ while (!source.getAttribute('treeNode') && source.tagName != 'body') {
+ source = source.parentNode;
+ }
+ if (source.tagName == 'body') {
+ dojo.raise("treeNode not detected");
+ }
+ var treeNode = dojo.widget.manager.getWidgetById(source.getAttribute('treeNode'));
+
+ return treeNode;
+ },
+
+
+ menuOpen: function(message) {
+ var treeNode = this.getTreeNode();
+
+ this.setDisabled(false); // enable by default
+
+ var _this = this;
+ dojo.lang.forEach(_this.treeActions,
+ function(action) {
+ _this.setDisabled( treeNode.actionIsDisabled(action) );
+ }
+ );
+
+ },
+
+ toString: function() {
+ return "["+this.widgetType+" node "+this.getTreeNode()+"]";
+ }
+
+});
+
+
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeController.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeController.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeController.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeController.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,754 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.EditorTreeController");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.dnd.TreeDragAndDrop");
+dojo.require("dojo.json")
+dojo.require("dojo.io.*");
+
+
+dojo.deprecated("dojo.widget.EditorTreeController", "moved to dojo.widget.Tree*Controller family");
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTreeController");
+
+
+dojo.widget.EditorTreeController = function() {
+ dojo.widget.HtmlWidget.call(this);
+
+ this.eventNames = {
+ select : "",
+ deselect : "",
+ collapse: "",
+ expand: "",
+ dblselect: "", // select already selected node.. Edit or whatever
+
+ move: "", // a child was moved from one place to another
+ remove: ""
+ };
+
+
+ this.dragSources = {};
+
+ this.dropTargets = {};
+}
+
+dojo.inherits(dojo.widget.EditorTreeController, dojo.widget.HtmlWidget);
+
+
+dojo.lang.extend(dojo.widget.EditorTreeController, {
+ widgetType: "EditorTreeController",
+
+ RPCUrl: "local",
+
+ errorHandler: null, // function pointer on error handler
+
+ eventNaming: "default",
+
+ initialize: function(args, frag){
+
+ if (this.eventNaming == "default") { // IE || FF
+ for (eventName in this.eventNames) {
+ this.eventNames[eventName] = this.widgetId+"/"+eventName;
+ }
+ }
+
+ },
+
+
+ DNDMode: "off",
+
+
+ /**
+ * Common RPC error handler (dies)
+ */
+ RPCErrorHandler: function(type, obj) {
+ alert( "RPC Error: " + (obj.message||"no message"));
+ },
+
+
+ /**
+ * Binds controller to all tree events
+ */
+ subscribeTree: function(tree) {
+
+ if (!tree.eventNames.nodeCreate) dojo.raise("Can't subscribe controller to empty nodeCreate")
+ if (!tree.eventNames.treeClick) dojo.raise("Can't subscribe controller to empty treeClick")
+ if (!tree.eventNames.iconClick) dojo.raise("Can't subscribe controller to empty iconClick")
+ if (!tree.eventNames.titleClick) dojo.raise("Can't subscribe controller to empty titleClick")
+
+ dojo.event.topic.subscribe(tree.eventNames.nodeCreate, this, "onNodeCreate");
+ dojo.event.topic.subscribe(tree.eventNames.treeClick, this, "onTreeClick");
+ dojo.event.topic.subscribe(tree.eventNames.iconClick, this, "onIconClick");
+ dojo.event.topic.subscribe(tree.eventNames.titleClick, this, "onTitleClick");
+ },
+
+
+ /**
+ * Checks whether it is ok to change parent of child to newParent
+ * May incur type checks etc
+ *
+ * It should check only hierarchical possibility w/o index, etc
+ * because in onDragOver event for Between DND mode we can't calculate index at once on onDragOVer.
+ * index changes as client moves mouse up-down over the node
+ */
+ canChangeParent: function(child, newParent){
+
+ if (child.actionIsDisabled(child.actions.MOVE)) {
+ return false;
+ }
+
+ if (child.parent !== newParent && newParent.actionIsDisabled(newParent.actions.ADDCHILD)) {
+ return false;
+ }
+
+ // Can't move parent under child. check whether new parent is child of "child".
+ var node = newParent;
+ while(node.isTreeNode) {
+ //dojo.debugShallow(node.title)
+
+
+ if (node === child) {
+ // parent of newParent is child
+ return false;
+ }
+ node = node.parent;
+ }
+
+
+ // check for newParent being a folder (if node)
+ if (newParent.isTreeNode && !newParent.isFolder) {
+ return false;
+ }
+
+
+ return true;
+ },
+
+
+
+ saveExpandedIndices: function(node, field) {
+ var obj = {};
+
+ for(var i=0; i<node.children.length; i++) {
+ if (node.children[i].isExpanded) {
+ var key = dojo.lang.isUndefined(field) ? i : node.children[i][field];
+ obj[key] = this.saveExpandedIndices(node.children[i], field);
+ }
+ }
+
+ return obj;
+ },
+
+
+ restoreExpandedIndices: function(node, savedIndices, field) {
+ var _this = this;
+
+
+
+ var handler = function(node, savedIndices) {
+ this.node = node; //.children[i];
+ this.savedIndices = savedIndices; //[i];
+ // recursively read next savedIndices level and apply to opened node
+ this.process = function() {
+ //dojo.debug("Callback applied for "+this.node);
+ _this.restoreExpandedIndices(this.node, this.savedIndices, field);
+ };
+ }
+
+
+ for(var i=0; i<node.children.length; i++) {
+ var child = node.children[i];
+
+ var found = false;
+ var key = -1;
+
+ dojo.debug("Check "+child)
+ // process field set case
+ if (dojo.lang.isUndefined(field) && savedIndices[i]) {
+ found = true;
+ key = i;
+ }
+
+ // process case when field is not set
+ if (field) {
+ for(var key in savedIndices) {
+ dojo.debug("Compare "+key+" "+child[field])
+ if (key == child[field]) {
+ found = true;
+ break;
+ }
+ }
+ }
+
+ // if we found anything - expand it
+ if (found) {
+ dojo.debug("Found at "+key)
+ var h = new handler(child, savedIndices[key]);
+ this.expand(child, h, h.process);
+ } else if (child.isExpanded) { // not found, so collapse
+ dojo.debug("Collapsing all descendants "+node.children[i])
+ dojo.lang.forEach(child.getDescendants(), function(elem) { _this.collapse(elem); });
+ //this.collapse(node.children[i]);
+ }
+
+ }
+
+
+ },
+
+
+ getRPCUrl: function(action) {
+
+ if (this.RPCUrl == "local") { // for demo and tests. May lead to widgetId collisions
+ var dir = document.location.href.substr(0, document.location.href.lastIndexOf('/'));
+ var localUrl = dir+"/"+action;
+ //dojo.debug(localUrl);
+ return localUrl;
+ }
+
+
+ if (!this.RPCUrl) {
+ dojo.raise("Empty RPCUrl: can't load");
+ }
+
+ return this.RPCUrl + ( this.RPCUrl.indexOf("?") > -1 ? "&" : "?") + "action="+action;
+ },
+
+
+ /**
+ * Make request to server about moving children.
+ *
+ * Request returns "true" if move succeeded,
+ * object with error field if failed
+ *
+ * I can't leave DragObject floating until async request returns, need to return false/true
+ * so making it sync way...
+ *
+ * Also, "loading" icon is not shown until function finishes execution, so no indication for remote request.
+ */
+ changeParentRemote: function(child, newParent, index){
+
+
+
+ //if (newParent.isTreeNode) newParent.markLoading();
+
+ var params = {
+ // where from
+ child: child.getInfo(),
+ childTree: child.tree.getInfo(),
+ // where to
+ newParent: newParent.getInfo(),
+ newParentTree: newParent.tree.getInfo()
+ };
+
+ var success;
+
+ //dojo.debug("changeParentRemote request")
+
+ dojo.io.bind({
+ url: this.getRPCUrl('changeParent'),
+ /* I hitch to get this.loadOkHandler */
+ load: dojo.lang.hitch(this,
+ function(type, obj) {
+ success = this.changeParentProcessResponse(type, obj, child, newParent, index) ;
+ }
+ ),
+ error: this.RPCErrorHandler,
+ mimetype: "text/json",
+ preventCache: true,
+ sync: true,
+ content: { data: dojo.json.serialize(params) }
+ });
+
+ //dojo.debug("changeParentRemote request done")
+
+ return success;
+ },
+
+ changeParentProcessResponse: function(type, result, child, newParent, index) {
+
+
+ if (!dojo.lang.isUndefined(result.error)) {
+ this.RPCErrorHandler(result.error);
+ return false;
+ }
+
+ child.tree.changeParent(child, newParent, index);
+ this.updateDND(child);
+
+ return true;
+ },
+
+ /**
+ * return true on success, false on failure
+ */
+ changeParent: function(child, newParent, index) {
+
+ /* move sourceTreeNode to new parent */
+ if (!this.canChangeParent(child, newParent)) {
+ return false;
+ }
+
+ /* load nodes into newParent in sync mode, if needed, first */
+ if (newParent.isTreeNode && newParent.state == newParent.loadStates.UNCHECKED) {
+ this.loadRemote(newParent, true);
+ }
+
+ var oldParent = child.parent;
+ var oldParentIndex = child.getParentIndex();
+
+
+ var result = this.changeParentRemote(child, newParent, index);
+
+ if (!result) return result;
+
+
+
+ /* publish many events here about structural changes */
+ dojo.event.topic.publish(this.eventNames.move,
+ {
+ oldParent: oldParent, oldParentIndex: oldParentIndex,
+ newParent: child.parent, newParentIndex: index,
+ child: child
+ }
+ );
+
+ this.expand(newParent);
+
+ return result;
+ },
+
+
+
+
+
+ /**
+ * Add all loaded nodes from array obj as node children and expand it
+ */
+ loadProcessResponse: function(type, node, result, callback, callObj) {
+
+ if (!dojo.lang.isUndefined(result.error)) {
+ this.RPCErrorHandler(result.error);
+ return false;
+ }
+
+ var newChildren = result;
+
+ if (!dojo.lang.isArray(newChildren)) {
+ dojo.raise('Not array loaded: '+newChildren);
+ }
+
+ for(var i=0; i<newChildren.length; i++) {
+ // looks like dojo.widget.manager needs no special "add" command
+ newChildren[i] = dojo.widget.createWidget(node.widgetType, newChildren[i]);
+ node.addChild(newChildren[i])
+ }
+
+
+ //node.addAllChildren(newChildren);
+
+ node.state = node.loadStates.LOADED;
+
+ if (dojo.lang.isFunction(callback)) {
+ callback.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node, newChildren]);
+ }
+ //this.expand(node);
+ },
+
+
+ /**
+ * Load children of the node from server
+ * Synchroneous loading doesn't break control flow
+ * I need sync mode for DnD
+ */
+ loadRemote: function(node, sync, callback, callObj){
+ node.markLoading();
+
+
+ var params = {
+ node: node.getInfo(),
+ tree: node.tree.getInfo()
+ };
+
+ var requestUrl = this.getRPCUrl('getChildren');
+ //dojo.debug(requestUrl)
+
+ dojo.io.bind({
+ url: requestUrl,
+ /* I hitch to get this.loadOkHandler */
+ load: dojo.lang.hitch(this,
+ function(type, result) {
+ this.loadProcessResponse(type, node, result, callback, callObj) ;
+ }
+ ),
+ error: this.RPCErrorHandler,
+ mimetype: "text/json",
+ preventCache: true,
+ sync: sync,
+ content: { data: dojo.json.serialize(params) }
+ });
+
+
+ },
+
+ onTreeClick: function(message){
+
+ //dojo.debug("EXPAND")
+
+ var node = message.source;
+
+ if (node.isExpanded){
+ this.collapse(node);
+ } else {
+ this.expand(node);
+ }
+ },
+
+
+ onIconClick: function(message){
+ this.onTitleClick(message);
+ },
+
+ onTitleClick: function(message){
+ var node = message.source;
+ var e = message.event;
+
+ if (node.tree.selector.selectedNode === node){
+ dojo.event.topic.publish(this.eventNames.dblselect, { source: node });
+ return;
+ }
+
+
+ /* deselect old node */
+ if (node.tree.selector.selectedNode) {
+ this.deselect(node.tree.selector.selectedNode);
+ }
+
+ this.select(node);
+
+
+ },
+
+
+ /**
+ * Process drag'n'drop -> drop
+ * NOT event-driven, because its result is important (success/false)
+ * in event system subscriber can't return a result into _current function control-flow_
+ * @return true on success, false on failure
+ */
+ processDrop: function(sourceNode, parentNode, index){
+ if (dojo.lang.isUndefined(index)) {
+ var index = 0;
+ }
+
+ //dojo.debug('drop index '+index)
+ return this.changeParent(sourceNode, parentNode, index)
+
+ },
+
+
+ onNodeCreate: function(message) {
+ this.registerDNDNode(message.source);
+ },
+
+ select: function(node){
+
+ node.markSelected();
+
+ node.tree.selector.selectedNode = node;
+
+
+ dojo.event.topic.publish(this.eventNames.select, {source: node} );
+ },
+
+ deselect: function(node){
+ node.unMarkSelected();
+
+ node.tree.selector.selectedNode = null;
+ dojo.event.topic.publish(this.eventNames.deselect, {source: node} );
+ },
+
+ expand: function(node, callObj, callFunc, sync) {
+
+ if (node.isExpanded) {
+ // callback is anyway applied
+ if (callFunc) callFunc.apply(callObj, [node]);
+ return;
+ }
+
+ if (node.state == node.loadStates.UNCHECKED) {
+ this.loadRemote(node, sync,
+ function(node, newChildren) {
+ this.expand(node, callObj, callFunc, sync);
+ }
+ );
+ } else {
+ node.expand();
+
+ // callback after expansion
+ if (callFunc) callFunc.apply(callObj, [node])
+
+ dojo.event.topic.publish(this.eventNames.expand, {source: node} );
+ }
+ },
+
+ collapse: function(node) {
+ if (!node.isExpanded) return;
+
+ node.collapse();
+ dojo.event.topic.publish(this.eventNames.collapse, {source: node} );
+ },
+
+
+ /**
+ * Controller(node model) creates DNDNodes because it passes itself to node for synchroneous drops processing
+ * I can't process DnD with events cause an event can't return result success/false
+ */
+ registerDNDNode: function(node) {
+
+ if (this.DNDMode=="off") return;
+
+ /* I drag label, not domNode, because large domNodes are very slow to copy and large to drag */
+
+ var source = null;
+ var target = null;
+
+ if (!node.actionIsDisabled(node.actions.MOVE)) {
+ //dojo.debug("reg source")
+ var source = new dojo.dnd.TreeDragSource(node.labelNode, this, node.tree.widgetId, node);
+ this.dragSources[node.widgetId] = source;
+ }
+
+ if (this.DNDMode=="onto") {
+ var target = new dojo.dnd.TreeDropOntoTarget(node.labelNode, this, node.tree.acceptDropSources, node);
+ } else if (this.DNDMode=="between") {
+ var target = new dojo.dnd.TreeDropBetweenTarget(node.labelNode, this, node.tree.acceptDropSources, node);
+ }
+
+ this.dropTargets[node.widgetId] = target;
+
+ },
+
+
+ unregisterDNDNode: function(node) {
+
+ if (this.dragSources[node.widgetId]) {
+ dojo.dnd.dragManager.unregisterDragSource(this.dragSources[node.widgetId]);
+ delete this.dragSources[node.widgetId];
+ }
+
+ if (this.dropTargets[node.widgetId]) {
+ dojo.dnd.dragManager.unregisterDropTarget(this.dropTargets[node.widgetId]);
+ delete this.dropTargets[node.widgetId];
+ }
+ },
+
+ // update types for DND right accept
+ // E.g when move from one tree to another tree
+ updateDND: function(node) {
+
+ this.unregisterDNDNode(node);
+
+ this.registerDNDNode(node);
+
+ for(var i=0; i<node.children.length; i++) {
+ this.updateDND(node.children[i]);
+ }
+
+ },
+
+
+
+
+ // -----------------------------------------------------------------------------
+ // Remove nodes stuff
+ // -----------------------------------------------------------------------------
+
+
+
+ canRemoveNode: function(node) {
+ return true;
+ },
+
+ removeNode: function(node, callback, callObj) {
+ if (!this.canRemoveNode(node)) {
+ return false;
+ }
+
+ return this.removeNodeRemote(node, callback, callObj);
+
+ },
+
+
+ removeNodeRemote: function(node, callback, callObj) {
+
+ var params = {
+ node: node.getInfo(),
+ tree: node.tree.getInfo()
+ }
+
+ dojo.io.bind({
+ url: this.getRPCUrl('removeNode'),
+ /* I hitch to get this.loadOkHandler */
+ load: dojo.lang.hitch(this, function(type, obj) {
+ this.removeNodeProcessResponse(type, node, obj, callback, callObj) }
+ ),
+ error: this.RPCErrorHandler,
+ mimetype: "text/json",
+ preventCache: true,
+ content: {data: dojo.json.serialize(params) }
+ });
+
+ },
+
+ removeNodeProcessResponse: function(type, node, result, callback, callObj) {
+ if (!dojo.lang.isUndefined(result.error)) {
+ this.RPCErrorHandler(result.error);
+ return false;
+ }
+
+ if (!result) return false;
+
+ if (result == true) {
+ /* change parent succeeded */
+ this.doRemoveNode(node, node);
+ if (callback) {
+ // provide context manually e.g with dojo.lang.hitch.
+ callback.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [node]);
+ }
+
+ return true;
+ } else if (dojo.lang.isObject(result)) {
+ dojo.raise(result.error);
+ } else {
+ dojo.raise("Invalid response "+obj)
+ }
+
+
+ },
+
+
+ /* This function does the real job only w/o any checks */
+ doRemoveNode: function(node) {
+ /* publish many events here about structural changes */
+
+ if (node.tree.selector.selectedNode === node) {
+ this.deselect(node);
+ }
+
+ this.unregisterDNDNode(node);
+
+ removed_node = node.tree.removeChild(node);
+
+ // nodes AFTER
+ dojo.event.topic.publish(this.eventNames.remove,
+ { node: removed_node }
+ );
+
+ },
+
+
+ // -----------------------------------------------------------------------------
+ // Create node stuff
+ // -----------------------------------------------------------------------------
+
+
+
+
+ canCreateNode: function(parent, index, data) {
+ if (!parent.isFolder) return false;
+
+ return true;
+ },
+
+
+ /* send data to server and add child from server */
+ /* data may contain an almost ready child, or anything else, suggested to server */
+ /* server responds with child data to be inserted */
+ createNode: function(parent, index, data, callback, callObj) {
+ if (!this.canCreateNode(parent, index, data)) {
+ return false;
+ }
+
+
+ /* load nodes into newParent in sync mode, if needed, first */
+ if (parent.state == parent.loadStates.UNCHECKED) {
+ this.loadRemote(parent, true);
+ }
+
+
+ return this.createNodeRemote(parent, index, data, callback, callObj);
+
+ },
+
+
+ createNodeRemote: function(parent, index, data, callback, callObj) {
+
+ var params = {
+ treeId: parent.tree.widgetId,
+ parentId: parent.widgetId,
+ index: index,
+ data: dojo.json.serialize(data)
+ }
+
+ dojo.io.bind({
+ url: this.getRPCUrl('createNode'),
+ /* I hitch to get this.loadOkHandler */
+ load: dojo.lang.hitch(this, function(type, obj) {
+ this.createNodeProcessResponse(type, obj, parent, index, callback, callObj) }
+ ),
+ error: this.RPCErrorHandler,
+ mimetype: "text/json",
+ preventCache: true,
+ content: params
+ });
+
+ },
+
+ createNodeProcessResponse: function(type, result, parent, index, callback, callObj) {
+
+ if (!dojo.lang.isUndefined(result.error)) {
+ this.RPCErrorHandler(result.error);
+ return false;
+ }
+
+ if (!parent.isTreeNode) {
+ dojo.raise("Can only add children to EditorTreeNode")
+ }
+
+ if (!dojo.lang.isObject(result)) {
+ dojo.raise("Invalid result "+result)
+ }
+
+ this.doCreateNode(parent, index, result);
+
+ if (callback) {
+ // provide context manually e.g with dojo.lang.hitch.
+ callback.apply(dojo.lang.isUndefined(callObj) ? this : callObj, [parent, index, result]);
+ }
+
+ },
+
+
+ doCreateNode: function(parent, index, child) {
+
+ var newChild = dojo.widget.createWidget("EditorTreeNode", child);
+
+ parent.addChild(newChild, index);
+
+ this.expand(parent);
+ }
+
+
+});
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeNode.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeNode.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeNode.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeNode.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,469 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.EditorTreeNode");
+
+dojo.require("dojo.event.*");
+dojo.require("dojo.fx.html");
+dojo.require("dojo.io.*");
+
+
+dojo.deprecated("dojo.widget.EditorTreeNode", "refactored & moved to dojo.widget.TreeNode");
+
+// make it a tag
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTreeNode");
+
+
+// # //////////
+
+dojo.widget.EditorTreeNode = function() {
+ dojo.widget.HtmlWidget.call(this);
+
+ this.actionsDisabled = [];
+}
+
+dojo.inherits(dojo.widget.EditorTreeNode, dojo.widget.HtmlWidget);
+
+dojo.lang.extend(dojo.widget.EditorTreeNode, {
+ widgetType: "EditorTreeNode",
+
+ loadStates: {
+ UNCHECKED: "UNCHECKED",
+ LOADING: "LOADING",
+ LOADED: "LOADED"
+ },
+
+
+ actions: {
+ MOVE: "MOVE",
+ REMOVE: "REMOVE",
+ EDIT: "EDIT",
+ ADDCHILD: "ADDCHILD"
+ },
+
+ isContainer: true,
+
+
+ templateString: ('<div class="dojoTreeNode"> '
+ + '<span treeNode="${this.widgetId}" class="dojoTreeNodeLabel" dojoAttachPoint="labelNode"> '
+ + ' <span dojoAttachPoint="titleNode" dojoAttachEvent="onClick: onTitleClick" class="dojoTreeNodeLabelTitle">${this.title}</span> '
+ + '</span> '
+ + '<span class="dojoTreeNodeAfterLabel" dojoAttachPoint="afterLabelNode">${this.afterLabel}</span> '
+ + '<div dojoAttachPoint="containerNode"></div> '
+ + '</div>').replace(/(>|<)\s+/g, '$1'), // strip whitespaces between nodes
+
+
+ childIconSrc: null,
+ childIconFolderSrc: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/closed.gif"), // for under root parent item child icon,
+ childIconDocumentSrc: dojo.uri.dojoUri("src/widget/templates/images/EditorTree/document.gif"), // for under root parent item child icon,
+
+ childIcon: null,
+ isTreeNode: true,
+
+ objectId: "", // the widget represents an object
+
+ afterLabel: "",
+ afterLabelNode: null, // node to the left of labelNode
+
+ // an icon left from childIcon: imgs[-2].
+ // if +/- for folders, blank for leaves
+ expandIcon: null,
+
+ title: "",
+ href: "", // node may have href for navigation purposes
+ isFolder: false,
+
+ labelNode: null, // the item label
+ titleNode: null, // the item title
+ imgs: null, // an array of icons imgs
+
+
+ tree: null,
+
+ depth: 0,
+
+ isExpanded: false,
+
+ state: null, // after creation will change to loadStates: "loaded/loading/unchecked"
+ domNodeInitialized: false, // domnode is initialized with icons etc
+
+
+ isFirstNode: function() {
+ return this.getPreviousSibling() ? false : true;
+ },
+
+ isLastNode: function() {
+ return this.getNextSibling() ? false : true;
+ },
+
+ actionIsDisabled: function(action) {
+ var _this = this;
+
+ return (action == this.actions.ADDCHILD && !this.isFolder) || dojo.lang.inArray(_this.actionsDisabled, action);
+ },
+
+ getInfo: function() {
+ // No title here (title may be widget)
+ var info = {
+ widgetId: this.widgetId,
+ objectId: this.objectId,
+ index: this.getParentIndex(),
+ isFolder: this.isFolder
+ }
+
+ return info;
+ },
+
+ initialize: function(args, frag){
+ this.state = this.loadStates.UNCHECKED;
+
+ for(var i=0; i<this.actionsDisabled.length; i++) {
+ this.actionsDisabled[i] = this.actionsDisabled[i].toUpperCase();
+ }
+
+ },
+
+
+ /**
+ * Change visible node depth by appending/prepending with blankImgs
+ * @param depthDiff Integer positive => move right, negative => move left
+ */
+ adjustDepth: function(depthDiff) {
+
+ for(var i=0; i<this.children.length; i++) {
+ this.children[i].adjustDepth(depthDiff);
+ }
+
+ this.depth += depthDiff;
+
+ if (depthDiff>0) {
+ for(var i=0; i<depthDiff; i++) {
+ var img = this.tree.makeBlankImg();
+ this.imgs.unshift(img);
+ //dojo.debugShallow(this.domNode);
+ this.domNode.insertBefore(this.imgs[0], this.domNode.firstChild);
+
+ }
+ }
+ if (depthDiff<0) {
+ for(var i=0; i<-depthDiff;i++) {
+ this.imgs.shift();
+ this.domNode.removeChild(this.domNode.firstChild);
+ }
+ }
+
+ },
+
+
+ markLoading: function() {
+ this.expandIcon.src = this.tree.expandIconSrcLoading;
+
+
+ },
+
+
+ setFolder: function() {
+ dojo.event.connect(this.expandIcon, 'onclick', this, 'onTreeClick');
+ this.isFolder = true;
+ },
+
+
+ buildNode: function(tree, depth){
+
+ this.tree = tree;
+ this.depth = depth;
+
+
+ //
+ // add the tree icons
+ //
+
+ this.imgs = [];
+
+ for(var i=0; i<this.depth+1; i++){
+
+ var img = this.tree.makeBlankImg();
+
+ this.domNode.insertBefore(img, this.labelNode);
+
+ this.imgs.push(img);
+ }
+
+
+ this.expandIcon = this.imgs[this.imgs.length-1];
+
+
+ this.childIcon = this.tree.makeBlankImg();
+
+ // add to images before the title
+ this.imgs.push(this.childIcon);
+
+ dojo.dom.insertBefore(this.childIcon, this.titleNode);
+
+ // node with children(from source html) becomes folder on build stage.
+ if (this.children.length || this.isFolder) {
+ this.setFolder();
+ }
+
+ dojo.event.connect(this.childIcon, 'onclick', this, 'onIconClick');
+
+
+ //
+ // create the child rows
+ //
+
+
+ for(var i=0; i<this.children.length; i++){
+ this.children[i].parent = this;
+
+ var node = this.children[i].buildNode(this.tree, this.depth+1);
+
+ this.containerNode.appendChild(node);
+ }
+
+
+ if (this.children.length) {
+ this.state = this.loadStates.LOADED;
+ }
+
+ if (this.isExpanded) {
+ this.expand();
+ }else { // leads to double icon updates
+ this.updateIcons();
+ }
+
+ this.domNodeInitialized = true;
+
+ dojo.event.topic.publish(this.tree.eventNames.nodeCreate, { source: this } );
+
+ return this.domNode;
+ },
+
+ onTreeClick: function(e){
+ dojo.event.topic.publish(this.tree.eventNames.treeClick, { source: this, event: e });
+ },
+
+ onIconClick: function(e){
+ dojo.event.topic.publish(this.tree.eventNames.iconClick, { source: this, event: e });
+ },
+
+ onTitleClick: function(e){
+ dojo.event.topic.publish(this.tree.eventNames.titleClick, { source: this, event: e });
+ },
+
+ markSelected: function() {
+ dojo.html.addClass(this.titleNode, 'dojoTreeNodeLabelSelected');
+ },
+
+
+ unMarkSelected: function() {
+ //dojo.debug('unmark')
+ dojo.html.removeClass(this.titleNode, 'dojoTreeNodeLabelSelected');
+ },
+
+ /* et the grid under the expand icon */
+ updateExpandIcon: function() {
+
+
+ if (this.tree.showGrid){
+ if (this.depth){
+ this.setGridImage(-2, this.isLastNode() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+ }else{
+ if (this.isFirstNode()){
+ this.setGridImage(-2, this.isLastNode() ? this.tree.gridIconSrcX : this.tree.gridIconSrcY);
+ }else{
+ this.setGridImage(-2, this.isLastNode() ? this.tree.gridIconSrcL : this.tree.gridIconSrcT);
+ }
+ }
+ }else{
+ this.setGridImage(-2, this.tree.blankIconSrc);
+ }
+
+ },
+
+ /* set the grid under the child icon */
+ updateChildIcon: function() {
+
+ if ((this.depth || this.tree.showRootGrid) && this.tree.showGrid){
+ this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcP : this.tree.gridIconSrcC);
+ }else{
+ if (this.tree.showGrid && !this.tree.showRootGrid){
+ this.setGridImage(-1, (this.children.length && this.isExpanded) ? this.tree.gridIconSrcZ : this.tree.blankIconSrc);
+ }else{
+ this.setGridImage(-1, this.tree.blankIconSrc);
+ }
+ }
+
+
+ },
+
+ updateParentIcons: function() {
+ var parent = this.parent;
+
+ for(var i=0; i<this.depth; i++){
+
+ var idx = this.imgs.length-(3+i);
+
+ this.setGridImage(
+ idx,
+ (this.tree.showGrid && !parent.isLastNode()) ? this.tree.gridIconSrcV : this.tree.blankIconSrc
+ );
+
+ parent = parent.parent;
+ }
+ },
+
+ updateIcons: function(){
+
+
+ dojo.profile.start("updateIcons")
+
+ //dojo.debug("Update icons for "+this.widgetId)
+ //dojo.debug(this.isFolder)
+
+ this.imgs[0].style.display = this.tree.showRootGrid ? 'inline' : 'none';
+
+
+ //
+ // set the expand icon
+ //
+
+ if (this.isFolder){
+
+ this.expandIcon.src = this.isExpanded ? this.tree.expandIconSrcMinus : this.tree.expandIconSrcPlus;
+
+ } else {
+ this.expandIcon.src = this.tree.blankIconSrc;
+ }
+
+ //
+ // set the child icon
+ //
+ this.buildChildIcon();
+
+ this.updateExpandIcon();
+ this.updateChildIcon();
+ this.updateParentIcons();
+
+
+ //alert(dojo.profile.toSource());
+ dojo.profile.stop("updateIcons")
+
+ },
+
+ buildChildIcon: function() {
+ /* no child icon */
+ if (this.childIconSrc == "none") {
+ this.childIcon.style.display = 'none';
+ return;
+ }
+
+ /* assign default icon if not set */
+ this.childIcon.src = this.childIconSrc
+ || (this.childIconSrc = this.isFolder ? this.childIconFolderSrc : this.childIconDocumentSrc);
+
+
+ this.childIcon.style.display = 'inline';
+ },
+
+ setGridImage: function(idx, src){
+
+ if (idx < 0){
+ idx = this.imgs.length + idx;
+ }
+
+ //if (idx >= this.imgs.length-2) return;
+ this.imgs[idx].style.backgroundImage = 'url(' + src + ')';
+ },
+
+
+ updateIconTree: function(){
+ this.tree.updateIconTree.call(this);
+ },
+
+
+
+ expand: function(){
+
+ //if (this.title=="Item 1.1") dojo.debug("expand IsExpanded:"+this.isExpanded);
+
+
+ if (this.children.length) {
+ this.showChildren();
+ }
+
+ this.isExpanded = true;
+
+ this.updateIcons();
+ },
+
+ collapse: function(){
+ this.hideChildren();
+ this.isExpanded = false;
+ this.updateIcons();
+ },
+
+ hideChildren: function(){
+ dojo.style.hide(this.containerNode);
+
+ /* if dnd is in action, recalculate changed coordinates */
+ if(dojo.dnd.dragManager.dragObjects.length) {
+ dojo.dnd.dragManager.cacheTargetLocations();
+ }
+ },
+
+ showChildren: function(){
+ dojo.style.show(this.containerNode);
+
+ /* if dnd is in action, recalculate changed coordinates */
+ if(dojo.dnd.dragManager.dragObjects.length) {
+ dojo.dnd.dragManager.cacheTargetLocations();
+ }
+ },
+
+
+ addChild: function(){
+ return this.tree.addChild.apply(this, arguments);
+ },
+
+ removeChild: function(){
+ return this.tree.removeChild.apply(this, arguments);
+ },
+
+
+ /* Edit current node : change properties and update contents */
+ edit: function(props) {
+ dojo.lang.mixin(this, props);
+ if (props.title) {
+ this.titleNode.innerHTML = this.title;
+ }
+
+ if (props.afterLabel) {
+ this.afterLabelNode.innerHTML = this.afterLabel;
+ }
+
+ if (props.childIconSrc) {
+ this.buildChildIcon();
+ }
+
+
+ },
+
+ toString: function() {
+ return "["+this.widgetType+" Tree:"+this.tree+" ID:"+this.widgetId+"]";
+
+ }
+
+});
+
+
+
+
Added: jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeSelector.js
URL: http://svn.apache.org/viewcvs/jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeSelector.js?rev=385171&view=auto
==============================================================================
--- jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeSelector.js (added)
+++ jakarta/tapestry/trunk/framework/src/java/org/apache/tapestry/html/dojo/src/widget/EditorTreeSelector.js Sat Mar 11 13:18:41 2006
@@ -0,0 +1,36 @@
+/*
+ Copyright (c) 2004-2005, The Dojo Foundation
+ All Rights Reserved.
+
+ Licensed under the Academic Free License version 2.1 or above OR the
+ modified BSD license. For more information on Dojo licensing, see:
+
+ http://dojotoolkit.org/community/licensing.shtml
+*/
+
+
+dojo.provide("dojo.widget.EditorTreeSelector");
+
+dojo.require("dojo.widget.HtmlWidget");
+
+dojo.deprecated("dojo.widget.EditorTreeSelector", "refactored & moved to dojo.widget.TreeSelector");
+
+
+dojo.widget.tags.addParseTreeHandler("dojo:EditorTreeSelector");
+
+
+dojo.widget.EditorTreeSelector = function() {
+ dojo.widget.HtmlWidget.call(this);
+}
+
+dojo.inherits(dojo.widget.EditorTreeSelector, dojo.widget.HtmlWidget);
+
+
+dojo.lang.extend(dojo.widget.EditorTreeSelector, {
+ widgetType: "EditorTreeSelector",
+ selectedNode: null
+
+});
+
+
+
---------------------------------------------------------------------
To unsubscribe, e-mail: tapestry-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: tapestry-dev-help@jakarta.apache.org