Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Manager.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Manager.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Manager.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Manager.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,279 @@ +/* + 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.Manager"); +dojo.require("dojo.lang"); +dojo.require("dojo.event.*"); + +// Manager class +dojo.widget.manager = new function(){ + this.widgets = []; + this.widgetIds = []; + + // map of widgetId-->widget for widgets without parents (top level widgets) + this.topWidgets = {}; + + var widgetTypeCtr = {}; + var renderPrefixCache = []; + + this.getUniqueId = function (widgetType) { + return widgetType + "_" + (widgetTypeCtr[widgetType] != undefined ? + ++widgetTypeCtr[widgetType] : widgetTypeCtr[widgetType] = 0); + } + + this.add = function(widget){ + dojo.profile.start("dojo.widget.manager.add"); + this.widgets.push(widget); + // FIXME: the rest of this method is very slow! + if(widget.widgetId == ""){ + if(widget["id"]){ + widget.widgetId = widget["id"]; + }else if(widget.extraArgs["id"]){ + widget.widgetId = widget.extraArgs["id"]; + }else{ + widget.widgetId = this.getUniqueId(widget.widgetType); + } + } + if(this.widgetIds[widget.widgetId]){ + dojo.debug("widget ID collision on ID: "+widget.widgetId); + } + this.widgetIds[widget.widgetId] = widget; + // Widget.destroy already calls removeById(), so we don't need to + // connect() it here + dojo.profile.end("dojo.widget.manager.add"); + } + + this.destroyAll = function(){ + for(var x=this.widgets.length-1; x>=0; x--){ + try{ + // this.widgets[x].destroyChildren(); + this.widgets[x].destroy(true); + delete this.widgets[x]; + }catch(e){ } + } + } + + // FIXME: we should never allow removal of the root widget until all others + // are removed! + this.remove = function(widgetIndex){ + var tw = this.widgets[widgetIndex].widgetId; + delete this.widgetIds[tw]; + this.widgets.splice(widgetIndex, 1); + } + + // FIXME: suboptimal performance + this.removeById = function(id) { + for (var i=0; i<this.widgets.length; i++){ + if(this.widgets[i].widgetId == id){ + this.remove(i); + break; + } + } + } + + this.getWidgetById = function(id){ + return this.widgetIds[id]; + } + + this.getWidgetsByType = function(type){ + var lt = type.toLowerCase(); + var ret = []; + dojo.lang.forEach(this.widgets, function(x){ + if(x.widgetType.toLowerCase() == lt){ + ret.push(x); + } + }); + return ret; + } + + this.getWidgetsOfType = function (id) { + dj_deprecated("getWidgetsOfType is depecrecated, use getWidgetsByType"); + return dojo.widget.manager.getWidgetsByType(id); + } + + this.getWidgetsByFilter = function(unaryFunc){ + var ret = []; + dojo.lang.forEach(this.widgets, function(x){ + if(unaryFunc(x)){ + ret.push(x); + } + }); + return ret; + } + + this.getAllWidgets = function() { + return this.widgets.concat(); + } + + // shortcuts, baby + this.byId = this.getWidgetById; + this.byType = this.getWidgetsByType; + this.byFilter = this.getWidgetsByFilter; + + // map of previousally discovered implementation names to constructors + var knownWidgetImplementations = {}; + + // support manually registered widget packages + var widgetPackages = ["dojo.widget", "dojo.webui.widgets"]; + for (var i=0; i<widgetPackages.length; i++) { + // convenience for checking if a package exists (reverse lookup) + widgetPackages[widgetPackages[i]] = true; + } + + this.registerWidgetPackage = function(pname) { + if(!widgetPackages[pname]){ + widgetPackages[pname] = true; + widgetPackages.push(pname); + } + } + + this.getWidgetPackageList = function() { + return dojo.lang.map(widgetPackages, function(elt) { return(elt!==true ? elt : undefined); }); + } + + this.getImplementation = function(widgetName, ctorObject, mixins){ + // try and find a name for the widget + var impl = this.getImplementationName(widgetName); + if(impl){ + // var tic = new Date(); + var ret = new impl(ctorObject); + // dojo.debug(new Date() - tic); + return ret; + } + } + + this.getImplementationName = function(widgetName){ + /* + * This is the overly-simplistic implemention of getImplementation (har + * har). In the future, we are going to want something that allows more + * freedom of expression WRT to specifying different specializations of + * a widget. + * + * Additionally, this implementation treats widget names as case + * insensitive, which does not necessarialy mesh with the markup which + * can construct a widget. + */ + + var lowerCaseWidgetName = widgetName.toLowerCase(); + + var impl = knownWidgetImplementations[lowerCaseWidgetName]; + if(impl){ + return impl; + } + + // first store a list of the render prefixes we are capable of rendering + if(!renderPrefixCache.length){ + for(var renderer in dojo.render){ + if(dojo.render[renderer]["capable"] === true){ + var prefixes = dojo.render[renderer].prefixes; + for(var i = 0; i < prefixes.length; i++){ + renderPrefixCache.push(prefixes[i].toLowerCase()); + } + } + } + // make sure we don't HAVE to prefix widget implementation names + // with anything to get them to render + renderPrefixCache.push(""); + } + + // look for a rendering-context specific version of our widget name + for(var i = 0; i < widgetPackages.length; i++){ + var widgetPackage = dojo.evalObjPath(widgetPackages[i]); + if(!widgetPackage) { continue; } + + for (var j = 0; j < renderPrefixCache.length; j++) { + if (!widgetPackage[renderPrefixCache[j]]) { continue; } + for (var widgetClass in widgetPackage[renderPrefixCache[j]]) { + if (widgetClass.toLowerCase() != lowerCaseWidgetName) { continue; } + knownWidgetImplementations[lowerCaseWidgetName] = + widgetPackage[renderPrefixCache[j]][widgetClass]; + return knownWidgetImplementations[lowerCaseWidgetName]; + } + } + + for (var j = 0; j < renderPrefixCache.length; j++) { + for (var widgetClass in widgetPackage) { + if (widgetClass.toLowerCase() != + (renderPrefixCache[j] + lowerCaseWidgetName)) { continue; } + + knownWidgetImplementations[lowerCaseWidgetName] = + widgetPackage[widgetClass]; + return knownWidgetImplementations[lowerCaseWidgetName]; + } + } + } + + throw new Error('Could not locate "' + widgetName + '" class'); + } + + // FIXME: does it even belong in this name space? + // NOTE: this method is implemented by DomWidget.js since not all + // hostenv's would have an implementation. + /*this.getWidgetFromPrimitive = function(baseRenderType){ + dj_unimplemented("dojo.widget.manager.getWidgetFromPrimitive"); + } + + this.getWidgetFromEvent = function(nativeEvt){ + dj_unimplemented("dojo.widget.manager.getWidgetFromEvent"); + }*/ + + // Catch window resize events and notify top level widgets + this.resizing=false; + this.onResized = function() { + if(this.resizing){ + return; // duplicate event + } + try { + this.resizing=true; + for(var id in this.topWidgets) { + var child = this.topWidgets[id]; + //dojo.debug("root resizing child " + child.widgetId); + if ( child.onResized ) { + child.onResized(); + } + } + } finally { + this.resizing=false; + } + } + if(typeof window != "undefined") { + dojo.addOnLoad(this, 'onResized'); // initial sizing + dojo.event.connect(window, 'onresize', this, 'onResized'); // window resize + } + + // FIXME: what else? +} + +// copy the methods from the default manager (this) to the widget namespace +dojo.widget.getUniqueId = function () { return dojo.widget.manager.getUniqueId.apply(dojo.widget.manager, arguments); } +dojo.widget.addWidget = function () { return dojo.widget.manager.add.apply(dojo.widget.manager, arguments); } +dojo.widget.destroyAllWidgets = function () { return dojo.widget.manager.destroyAll.apply(dojo.widget.manager, arguments); } +dojo.widget.removeWidget = function () { return dojo.widget.manager.remove.apply(dojo.widget.manager, arguments); } +dojo.widget.removeWidgetById = function () { return dojo.widget.manager.removeById.apply(dojo.widget.manager, arguments); } +dojo.widget.getWidgetById = function () { return dojo.widget.manager.getWidgetById.apply(dojo.widget.manager, arguments); } +dojo.widget.getWidgetsByType = function () { return dojo.widget.manager.getWidgetsByType.apply(dojo.widget.manager, arguments); } +dojo.widget.getWidgetsByFilter = function () { return dojo.widget.manager.getWidgetsByFilter.apply(dojo.widget.manager, arguments); } +dojo.widget.byId = function () { return dojo.widget.manager.getWidgetById.apply(dojo.widget.manager, arguments); } +dojo.widget.byType = function () { return dojo.widget.manager.getWidgetsByType.apply(dojo.widget.manager, arguments); } +dojo.widget.byFilter = function () { return dojo.widget.manager.getWidgetsByFilter.apply(dojo.widget.manager, arguments); } +dojo.widget.all = function (n) { + var widgets = dojo.widget.manager.getAllWidgets.apply(dojo.widget.manager, arguments); + if(arguments.length > 0) { + return widgets[n]; + } + return widgets; +} +dojo.widget.registerWidgetPackage = function () { return dojo.widget.manager.registerWidgetPackage.apply(dojo.widget.manager, arguments); } +dojo.widget.getWidgetImplementation = function () { return dojo.widget.manager.getImplementation.apply(dojo.widget.manager, arguments); } +dojo.widget.getWidgetImplementationName = function () { return dojo.widget.manager.getImplementationName.apply(dojo.widget.manager, arguments); } + +dojo.widget.widgets = dojo.widget.manager.widgets; +dojo.widget.widgetIds = dojo.widget.manager.widgetIds; +dojo.widget.root = dojo.widget.manager.root;
Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,59 @@ +/* + 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.Menu"); +dojo.provide("dojo.widget.DomMenu"); + +dojo.deprecated("dojo.widget.Menu, dojo.widget.DomMenu", "use dojo.widget.Menu2", "0.4"); + +dojo.require("dojo.widget.*"); + +dojo.widget.tags.addParseTreeHandler("dojo:menu"); + +/* Menu + *******/ + +dojo.widget.Menu = function () { + dojo.widget.Menu.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.Menu, dojo.widget.Widget); + +dojo.lang.extend(dojo.widget.Menu, { + widgetType: "Menu", + isContainer: true, + + items: [], + push: function(item){ + dojo.connect.event(item, "onSelect", this, "onSelect"); + this.items.push(item); + }, + onSelect: function(){} +}); + + +/* DomMenu + **********/ + +dojo.widget.DomMenu = function(){ + dojo.widget.DomMenu.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.DomMenu, dojo.widget.DomWidget); + +dojo.lang.extend(dojo.widget.DomMenu, { + widgetType: "Menu", + isContainer: true, + + push: function (item) { + dojo.widget.Menu.call(this, item); + this.domNode.appendChild(item.domNode); + } +}); + +dojo.requireAfterIf("html", "dojo.widget.html.Menu"); Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu2.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu2.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu2.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Menu2.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,703 @@ +/* + 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.Menu2"); +dojo.provide("dojo.widget.html.Menu2"); +dojo.provide("dojo.widget.PopupMenu2"); +dojo.provide("dojo.widget.MenuItem2"); + +dojo.require("dojo.html"); +dojo.require("dojo.style"); +dojo.require("dojo.event.*"); +dojo.require("dojo.widget.*"); +dojo.require("dojo.widget.HtmlWidget"); + + +dojo.widget.PopupMenu2 = function(){ + dojo.widget.HtmlWidget.call(this); + this.items = []; // unused??? + this.targetNodeIds = []; // fill this with nodeIds upon widget creation and it becomes context menu for those nodes + this.queueOnAnimationFinish = []; +} + +dojo.inherits(dojo.widget.PopupMenu2, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.PopupMenu2, { + widgetType: "PopupMenu2", + isContainer: true, + + snarfChildDomOutput: true, + + currentSubmenu: null, + currentSubmenuTrigger: null, + parentMenu: null, + isShowing: false, + menuX: 0, + menuY: 0, + menuWidth: 0, + menuHeight: 0, + menuIndex: 0, + + domNode: null, + containerNode: null, + + templateString: '<div><div dojoAttachPoint="containerNode"></div></div>', + templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlMenu2.css"), + + itemHeight: 18, + iconGap: 1, + accelGap: 10, + submenuGap: 2, + finalGap: 5, + submenuIconSize: 4, + separatorHeight: 9, + submenuDelay: 500, + submenuOverlap: 5, + contextMenuForWindow: false, + openEvent: null, + + submenuIconSrc: dojo.uri.dojoUri("src/widget/templates/images/submenu_off.gif").toString(), + submenuIconOnSrc: dojo.uri.dojoUri("src/widget/templates/images/submenu_on.gif").toString(), + + postCreate: function(){ + + dojo.html.addClass(this.domNode, 'dojoPopupMenu2'); + dojo.html.addClass(this.containerNode, 'dojoPopupMenu2Client'); + + this.domNode.style.left = '-9999px' + this.domNode.style.top = '-9999px' + + if (this.contextMenuForWindow){ + var doc = document.documentElement || dojo.html.body(); + dojo.event.connect(doc, "oncontextmenu", this, "onOpen"); + } else if ( this.targetNodeIds.length > 0 ){ + for(var i=0; i<this.targetNodeIds.length; i++){ + this.bindDomNode(this.targetNodeIds[i]); + } + } + + this.layoutMenuSoon(); + }, + + // get open event for current menu + getTopOpenEvent: function() { + var menu = this; + while (menu.parent){ menu = menu.parent; } + return menu.openEvent; + }, + + // attach menu to given node + bindDomNode: function(node){ + dojo.event.connect(dojo.byId(node), "oncontextmenu", this, "onOpen"); + }, + + // detach menu from given node + unBindDomNode: function(node){ + dojo.event.kwDisconnect({ + srcObj: dojo.byId(node), + srcFunc: "oncontextmenu", + targetObj: this, + targetFunc: "onOpen", + once: true + }); + }, + + layoutMenuSoon: function(){ + + dojo.lang.setTimeout(this, "layoutMenu", 0); + }, + + layoutMenu: function(){ + + // determine menu width + + var max_label_w = 0; + var max_accel_w = 0; + + for(var i=0; i<this.children.length; i++){ + + if (this.children[i].getLabelWidth){ + + max_label_w = Math.max(max_label_w, this.children[i].getLabelWidth()); + } + + if (dojo.lang.isFunction(this.children[i].getAccelWidth)){ + + max_accel_w = Math.max(max_accel_w, this.children[i].getAccelWidth()); + } + } + + if( isNaN(max_label_w) || isNaN(max_accel_w) ){ + // Browser needs some more time to calculate sizes + this.layoutMenuSoon(); + return; + } + + var clientLeft = dojo.style.getPixelValue(this.domNode, "padding-left", true) + dojo.style.getPixelValue(this.containerNode, "padding-left", true); + var clientTop = dojo.style.getPixelValue(this.domNode, "padding-top", true) + dojo.style.getPixelValue(this.containerNode, "padding-top", true); + + if( isNaN(clientLeft) || isNaN(clientTop) ){ + // Browser needs some more time to calculate sizes + this.layoutMenuSoon(); + return; + } + + var y = clientTop; + var max_item_width = 0; + + for(var i=0; i<this.children.length; i++){ + + var ch = this.children[i]; + + ch.layoutItem(max_label_w, max_accel_w); + + ch.topPosition = y; + + y += dojo.style.getOuterHeight(ch.domNode); + max_item_width = Math.max(max_item_width, dojo.style.getOuterWidth(ch.domNode)); + } + + dojo.style.setContentWidth(this.containerNode, max_item_width); + dojo.style.setContentHeight(this.containerNode, y-clientTop); + + dojo.style.setContentWidth(this.domNode, dojo.style.getOuterWidth(this.containerNode)); + dojo.style.setContentHeight(this.domNode, dojo.style.getOuterHeight(this.containerNode)); + + this.menuWidth = dojo.style.getOuterWidth(this.domNode); + this.menuHeight = dojo.style.getOuterHeight(this.domNode); + }, + + open: function(x, y, parentMenu, explodeSrc){ + + // NOTE: alex: + // this couldn't have possibly worked. this.open wound up calling + // this.close, which called open...etc.. + if (this.isShowing){ /* this.close(); */ return; } + + if ( !parentMenu ) { + // record whenever a top level menu is opened + dojo.widget.html.Menu2Manager.opened(this, explodeSrc); + } + + //dojo.debug("open called for animation "+this.animationInProgress) + + // if I click right button and menu is opened, then it gets 2 commands: close -> open + // so close enables animation and next "open" is put to queue to occur at new location + if(this.animationInProgress){ + this.queueOnAnimationFinish.push(this.open, arguments); + return; + } + + var viewport = dojo.html.getViewportSize(); + var scrolloffset = dojo.html.getScrollOffset(); + + var clientRect = { + 'left' : scrolloffset[0], + 'right' : scrolloffset[0] + viewport[0], + 'top' : scrolloffset[1], + 'bottom': scrolloffset[1] + viewport[1] + }; + + if (parentMenu){ + // submenu is opening + + if (x + this.menuWidth > clientRect.right){ x = x - (this.menuWidth + parentMenu.menuWidth - (2 * this.submenuOverlap)); } + + if (y + this.menuHeight > clientRect.bottom){ y = y - + (this.menuHeight - (this.itemHeight + 5)); } // TODO: why 5? + + }else{ + // top level menu is opening + x+=scrolloffset[0]; + y+=scrolloffset[1]; + explodeSrc[0] += scrolloffset[0]; + explodeSrc[1] += scrolloffset[1]; + + if (x < clientRect.left){ x = clientRect.left; } + if (x + this.menuWidth > clientRect.right){ x = x - this.menuWidth; } + + if (y < clientRect.top){ y = clientRect.top; } + if (y + this.menuHeight > clientRect.bottom){ y = y - this.menuHeight; } + } + + this.parentMenu = parentMenu; + this.explodeSrc = explodeSrc; + this.menuIndex = parentMenu ? parentMenu.menuIndex + 1 : 1; + + this.menuX = x; + this.menuY = y; + + // move the menu into position but make it invisible + // (because when menus are initially constructed they are visible but off-screen) + this.domNode.style.zIndex = 10 + this.menuIndex; + this.domNode.style.left = x + 'px'; + this.domNode.style.top = y + 'px'; + this.domNode.style.display='none'; + this.domNode.style.position='absolute'; + + // then use the user defined method to display it + this.show(); + + this.isShowing = true; + }, + + close: function(){ + // If we are in the process of opening the menu and we are asked to close it, + // we should really cancel the current animation, but for simplicity we will + // just ignore the request + if(this.animationInProgress){ + this.queueOnAnimationFinish.push(this.close, []); + return; + } + + this.closeSubmenu(); + this.hide(); + this.isShowing = false; + dojo.widget.html.Menu2Manager.closed(this); + }, + + onShow: function() { + dojo.widget.HtmlWidget.prototype.onShow.call(this); + this.processQueue(); + }, + + // do events from queue + processQueue: function() { + if (!this.queueOnAnimationFinish.length) return; + + var func = this.queueOnAnimationFinish.shift(); + var args = this.queueOnAnimationFinish.shift(); + + func.apply(this, args); + }, + + onHide: function() { + dojo.widget.HtmlWidget.prototype.onHide.call(this); + + this.processQueue(); + }, + + + closeAll: function(){ + + if (this.parentMenu){ + this.parentMenu.closeAll(); + }else{ + this.close(); + } + }, + + closeSubmenu: function(){ + if (this.currentSubmenu == null){ return; } + + this.currentSubmenu.close(); + this.currentSubmenu = null; + + this.currentSubmenuTrigger.is_open = false; + this.currentSubmenuTrigger.closedSubmenu(); + this.currentSubmenuTrigger = null; + }, + + openSubmenu: function(submenu, from_item){ + + var our_x = dojo.style.getPixelValue(this.domNode, 'left'); + var our_y = dojo.style.getPixelValue(this.domNode, 'top'); + var our_w = dojo.style.getOuterWidth(this.domNode); + var item_y = from_item.topPosition; + + var x = our_x + our_w - this.submenuOverlap; + var y = our_y + item_y; + + this.currentSubmenu = submenu; + this.currentSubmenu.open(x, y, this, from_item.domNode); + + this.currentSubmenuTrigger = from_item; + this.currentSubmenuTrigger.is_open = true; + }, + + onOpen: function(e){ + this.openEvent = e; + + //dojo.debugShallow(e); + this.open(e.clientX, e.clientY, null, [e.clientX, e.clientY]); + + if(e["preventDefault"]){ + e.preventDefault(); + } + }, + + isPointInMenu: function(x, y){ + + if (x < this.menuX){ return 0; } + if (x > this.menuX + this.menuWidth){ return 0; } + + if (y < this.menuY){ return 0; } + if (y > this.menuY + this.menuHeight){ return 0; } + + return 1; + } +}); + + +dojo.widget.MenuItem2 = function(){ + dojo.widget.HtmlWidget.call(this); +} + +dojo.inherits(dojo.widget.MenuItem2, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.MenuItem2, { + widgetType: "MenuItem2", + templateString: + '<div class="dojoMenuItem2">' + +'<div dojoAttachPoint="iconNode" class="dojoMenuItem2Icon"></div>' + +'<span dojoAttachPoint="labelNode" class="dojoMenuItem2Label"><span><span></span></span></span>' + +'<span dojoAttachPoint="accelNode" class="dojoMenuItem2Accel"><span><span></span></span></span>' + +'<div dojoAttachPoint="submenuNode" class="dojoMenuItem2Submenu"></div>' + +'<div dojoAttachPoint="targetNode" class="dojoMenuItem2Target" dojoAttachEvent="onMouseOver: onHover; onMouseOut: onUnhover; onClick;"> </div>' + +'</div>', + + // + // nodes + // + + domNode: null, + iconNode: null, + labelNode: null, + accelNode: null, + submenuNode: null, + targetNode: null, + + // + // internal settings + // + + is_hovering: false, + hover_timer: null, + is_open: false, + topPosition: 0, + is_disabled: false, + + // + // options + // + + caption: 'Untitled', + accelKey: '', + iconSrc: '', + submenuId: '', + isDisabled: false, + + + postCreate: function(){ + + dojo.html.disableSelection(this.domNode); + + if (this.isDisabled){ + this.setDisabled(true); + } + + this.labelNode.childNodes[0].appendChild(document.createTextNode(this.caption)); + this.accelNode.childNodes[0].appendChild(document.createTextNode(this.accelKey)); + + this.labelShadowNode = this.labelNode.childNodes[0].childNodes[0]; + this.accelShadowNode = this.accelNode.childNodes[0].childNodes[0]; + + this.labelShadowNode.appendChild(document.createTextNode(this.caption)); + this.accelShadowNode.appendChild(document.createTextNode(this.accelKey)); + }, + + layoutItem: function(label_w, accel_w){ + + var x_label = this.parent.itemHeight + this.parent.iconGap; + var x_accel = x_label + label_w + this.parent.accelGap; + var x_submu = x_accel + accel_w + this.parent.submenuGap; + var total_w = x_submu + this.parent.submenuIconSize + this.parent.finalGap; + + + this.iconNode.style.left = '0px'; + this.iconNode.style.top = '0px'; + + + if (this.iconSrc){ + + if ((this.iconSrc.toLowerCase().substring(this.iconSrc.length-4) == ".png") && (dojo.render.html.ie)){ + + this.iconNode.style.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+this.iconSrc+"', sizingMethod='image')"; + this.iconNode.style.backgroundImage = ''; + }else{ + this.iconNode.style.backgroundImage = 'url('+this.iconSrc+')'; + } + }else{ + this.iconNode.style.backgroundImage = ''; + } + + dojo.style.setOuterWidth(this.iconNode, this.parent.itemHeight); + dojo.style.setOuterHeight(this.iconNode, this.parent.itemHeight); + + dojo.style.setOuterHeight(this.labelNode, this.parent.itemHeight); + dojo.style.setOuterHeight(this.accelNode, this.parent.itemHeight); + + dojo.style.setContentWidth(this.domNode, total_w); + dojo.style.setContentHeight(this.domNode, this.parent.itemHeight); + + this.labelNode.style.left = x_label + 'px'; + this.accelNode.style.left = x_accel + 'px'; + this.submenuNode.style.left = x_submu + 'px'; + + dojo.style.setOuterWidth(this.submenuNode, this.parent.submenuIconSize); + dojo.style.setOuterHeight(this.submenuNode, this.parent.itemHeight); + + this.submenuNode.style.display = this.submenuId ? 'block' : 'none'; + this.submenuNode.style.backgroundImage = 'url('+this.parent.submenuIconSrc+')'; + + dojo.style.setOuterWidth(this.targetNode, total_w); + dojo.style.setOuterHeight(this.targetNode, this.parent.itemHeight); + }, + + onHover: function(){ + + if (this.is_hovering){ return; } + if (this.is_open){ return; } + + this.parent.closeSubmenu(); + this.highlightItem(); + + if (this.is_hovering){ this.stopSubmenuTimer(); } + this.is_hovering = 1; + this.startSubmenuTimer(); + }, + + onUnhover: function(){ + + if (!this.is_open){ this.unhighlightItem(); } + + this.is_hovering = 0; + this.stopSubmenuTimer(); + }, + + onClick: function(){ + + if (this.is_disabled){ return; } + + if (this.submenuId){ + + if (!this.is_open){ + this.stopSubmenuTimer(); + this.openSubmenu(); + } + + }else{ + + this.parent.closeAll(); + } + }, + + highlightItem: function(){ + + dojo.html.addClass(this.domNode, 'dojoMenuItem2Hover'); + this.submenuNode.style.backgroundImage = 'url('+this.parent.submenuIconOnSrc+')'; + }, + + unhighlightItem: function(){ + + dojo.html.removeClass(this.domNode, 'dojoMenuItem2Hover'); + this.submenuNode.style.backgroundImage = 'url('+this.parent.submenuIconSrc+')'; + }, + + startSubmenuTimer: function(){ + this.stopSubmenuTimer(); + + if (this.is_disabled){ return; } + + var self = this; + var closure = function(){ return function(){ self.openSubmenu(); } }(); + + this.hover_timer = window.setTimeout(closure, this.parent.submenuDelay); + }, + + stopSubmenuTimer: function(){ + if (this.hover_timer){ + window.clearTimeout(this.hover_timer); + this.hover_timer = null; + } + }, + + openSubmenu: function(){ + // first close any other open submenu + this.parent.closeSubmenu(); + + var submenu = dojo.widget.getWidgetById(this.submenuId); + if (submenu){ + + this.parent.openSubmenu(submenu, this); + } + + //dojo.debug('open submenu for item '+this.widgetId); + }, + + closedSubmenu: function(){ + + this.onUnhover(); + }, + + setDisabled: function(value){ + + if (value == this.is_disabled){ return; } + + this.is_disabled = value; + + if (this.is_disabled){ + dojo.html.addClass(this.domNode, 'dojoMenuItem2Disabled'); + }else{ + dojo.html.removeClass(this.domNode, 'dojoMenuItem2Disabled'); + } + }, + + getLabelWidth: function(){ + + var node = this.labelNode.childNodes[0]; + + return dojo.style.getOuterWidth(node); + }, + + getAccelWidth: function(){ + + var node = this.accelNode.childNodes[0]; + + return dojo.style.getOuterWidth(node); + } +}); + + +dojo.widget.MenuSeparator2 = function(){ + dojo.widget.HtmlWidget.call(this); +} + +dojo.inherits(dojo.widget.MenuSeparator2, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.MenuSeparator2, { + widgetType: "MenuSeparator2", + + domNode: null, + topNode: null, + bottomNode: null, + + templateString: '<div>' + +'<div dojoAttachPoint="topNode"></div>' + +'<div dojoAttachPoint="bottomNode"></div>' + +'</div>', + + postCreate: function(){ + + dojo.html.addClass(this.domNode, 'dojoMenuSeparator2'); + dojo.html.addClass(this.topNode, 'dojoMenuSeparator2Top'); + dojo.html.addClass(this.bottomNode, 'dojoMenuSeparator2Bottom'); + + dojo.html.disableSelection(this.domNode); + + this.layoutItem(); + }, + + layoutItem: function(label_w, accel_w){ + + var full_width = this.parent.itemHeight + + this.parent.iconGap + + label_w + + this.parent.accelGap + + accel_w + + this.parent.submenuGap + + this.parent.submenuIconSize + + this.parent.finalGap; + + if (isNaN(full_width)){ return; } + + dojo.style.setContentHeight(this.domNode, this.parent.separatorHeight); + dojo.style.setContentWidth(this.domNode, full_width); + } +}); + +// +// the menu manager makes sure we don't have several menus +// open at once. the root menu in an opening sequence calls +// opened(). when a root menu closes it calls closed(). then +// everything works. lovely. +// + +dojo.widget.html.Menu2Manager = new function(){ + + this.currentMenu = null; + this.currentButton = null; // button that opened current menu (if any) + this.focusNode = null; + + dojo.event.connect(document, 'onmousedown', this, 'onClick'); + dojo.event.connect(window, "onscroll", this, "onClick"); + + this.closed = function(menu){ + if (this.currentMenu == menu){ + this.currentMenu = null; + this.currentButton = null; + } + }; + + this.opened = function(menu, button){ + if (menu == this.currentMenu){ return; } + + if (this.currentMenu){ + this.currentMenu.close(); + } + + this.currentMenu = menu; + this.currentButton = button; + }; + + this.onClick = function(e){ + + if (!this.currentMenu){ return; } + + var scrolloffset = dojo.html.getScrollOffset(); + + var x = e.clientX + scrolloffset[0]; + var y = e.clientY + scrolloffset[1]; + + var m = this.currentMenu; + + // starting from the base menu, perform a hit test + // and exit when one succeeds + + while (m){ + + if (m.isPointInMenu(x, y)){ + + return; + } + + m = m.currentSubmenu; + } + + // Also, if user clicked the button that opened this menu, then + // that button will send the menu a close() command, so this code + // shouldn't try to close the menu. Closing twice messes up animation. + if (this.currentButton && dojo.html.overElement(this.currentButton, e)){ + return; + } + + // the click didn't fall within the open menu tree + // so close it + + this.currentMenu.close(); + }; +} + + +// make it a tag +dojo.widget.tags.addParseTreeHandler("dojo:PopupMenu2"); +dojo.widget.tags.addParseTreeHandler("dojo:MenuItem2"); +dojo.widget.tags.addParseTreeHandler("dojo:MenuSeparator2"); + Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/MenuItem.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/MenuItem.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/MenuItem.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/MenuItem.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,47 @@ +/* + 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.MenuItem"); +dojo.provide("dojo.widget.DomMenuItem"); + +dojo.deprecated("dojo.widget.MenuItem, dojo.widget.DomMenuItem", "use dojo.widget.Menu2", "0.4"); + +dojo.require("dojo.string"); +dojo.require("dojo.widget.*"); + +dojo.widget.tags.addParseTreeHandler("dojo:MenuItem"); + +/* MenuItem + ***********/ + +dojo.widget.MenuItem = function(){ + dojo.widget.MenuItem.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.MenuItem, dojo.widget.Widget); + +dojo.lang.extend(dojo.widget.MenuItem, { + widgetType: "MenuItem", + isContainer: true +}); + + +/* DomMenuItem + **************/ +dojo.widget.DomMenuItem = function(){ + dojo.widget.DomMenuItem.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.DomMenuItem, dojo.widget.DomWidget); + +dojo.lang.extend(dojo.widget.DomMenuItem, { + widgetType: "MenuItem" +}); + +dojo.requireAfterIf("html", "dojo.html"); +dojo.requireAfterIf("html", "dojo.widget.html.MenuItem"); Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Parse.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Parse.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Parse.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/Parse.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,320 @@ +/* + 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.Parse"); + +dojo.require("dojo.widget.Manager"); +dojo.require("dojo.string"); +dojo.require("dojo.dom"); + +dojo.widget.Parse = function(fragment) { + this.propertySetsList = []; + this.fragment = fragment; + + /* createComponents recurses over a raw JavaScript object structure, + and calls the corresponding handler for its normalized tagName if it exists + */ + this.createComponents = function(fragment, parentComp){ + var djTags = dojo.widget.tags; + var returnValue = []; + // this allows us to parse without having to include the parent + // it is commented out as it currently breaks the existing mechanism for + // adding widgets programmatically. Once that is fixed, this can be used + /*if( (fragment["tagName"])&& + (fragment != fragment["nodeRef"])){ + var tn = new String(fragment["tagName"]); + // we split so that you can declare multiple + // non-destructive widgets from the same ctor node + var tna = tn.split(";"); + for(var x=0; x<tna.length; x++){ + var ltn = dojo.text.trim(tna[x]).toLowerCase(); + if(djTags[ltn]){ + fragment.tagName = ltn; + returnValue.push(djTags[ltn](fragment, this, parentComp, count++)); + }else{ + if(ltn.substr(0, 5)=="dojo:"){ + dj_debug("no tag handler registed for type: ", ltn); + } + } + } + }*/ + for(var item in fragment){ + var built = false; + // if we have items to parse/create at this level, do it! + try{ + if( fragment[item] && (fragment[item]["tagName"])&& + (fragment[item] != fragment["nodeRef"])){ + var tn = new String(fragment[item]["tagName"]); + // we split so that you can declare multiple + // non-destructive widgets from the same ctor node + var tna = tn.split(";"); + for(var x=0; x<tna.length; x++){ + var ltn = dojo.string.trim(tna[x]).toLowerCase(); + if(djTags[ltn]){ + built = true; + // var tic = new Date(); + fragment[item].tagName = ltn; + var ret = djTags[ltn](fragment[item], this, parentComp, fragment[item]["index"]) + returnValue.push(ret); + }else{ + if((dojo.lang.isString(ltn))&&(ltn.substr(0, 5)=="dojo:")){ + dojo.debug("no tag handler registed for type: ", ltn); + } + } + } + } + }catch(e){ + dojo.debug("fragment creation error:", e); + // throw(e); + // IE is such a bitch sometimes + } + + // if there's a sub-frag, build widgets from that too + if( (!built) && (typeof fragment[item] == "object")&& + (fragment[item] != fragment.nodeRef)&& + (fragment[item] != fragment["tagName"])){ + returnValue.push(this.createComponents(fragment[item], parentComp)); + } + } + return returnValue; + } + + /* parsePropertySets checks the top level of a raw JavaScript object + structure for any propertySets. It stores an array of references to + propertySets that it finds. + */ + this.parsePropertySets = function(fragment) { + return []; + var propertySets = []; + for(var item in fragment){ + if( (fragment[item]["tagName"] == "dojo:propertyset") ) { + propertySets.push(fragment[item]); + } + } + // FIXME: should we store these propertySets somewhere for later retrieval + this.propertySetsList.push(propertySets); + return propertySets; + } + + /* parseProperties checks a raw JavaScript object structure for + properties, and returns an array of properties that it finds. + */ + this.parseProperties = function(fragment) { + var properties = {}; + for(var item in fragment){ + // FIXME: need to check for undefined? + // case: its a tagName or nodeRef + if((fragment[item] == fragment["tagName"])|| + (fragment[item] == fragment.nodeRef)){ + // do nothing + }else{ + if((fragment[item]["tagName"])&& + (dojo.widget.tags[fragment[item].tagName.toLowerCase()])){ + // TODO: it isn't a property or property set, it's a fragment, + // so do something else + // FIXME: needs to be a better/stricter check + // TODO: handle xlink:href for external property sets + }else if((fragment[item][0])&&(fragment[item][0].value!="")){ + try{ + // FIXME: need to allow more than one provider + if(item.toLowerCase() == "dataprovider") { + var _this = this; + this.getDataProvider(_this, fragment[item][0].value); + properties.dataProvider = this.dataProvider; + } + properties[item] = fragment[item][0].value; + var nestedProperties = this.parseProperties(fragment[item]); + // FIXME: this kind of copying is expensive and inefficient! + for(var property in nestedProperties){ + properties[property] = nestedProperties[property]; + } + }catch(e){ dojo.debug(e); } + } + } + } + return properties; + } + + /* getPropertySetById returns the propertySet that matches the provided id + */ + + this.getDataProvider = function(objRef, dataUrl) { + // FIXME: this is currently sync. To make this async, we made need to move + //this step into the widget ctor, so that it is loaded when it is needed + // to populate the widget + dojo.io.bind({ + url: dataUrl, + load: function(type, evaldObj){ + if(type=="load"){ + objRef.dataProvider = evaldObj; + } + }, + mimetype: "text/javascript", + sync: true + }); + } + + + this.getPropertySetById = function(propertySetId){ + for(var x = 0; x < this.propertySetsList.length; x++){ + if(propertySetId == this.propertySetsList[x]["id"][0].value){ + return this.propertySetsList[x]; + } + } + return ""; + } + + /* getPropertySetsByType returns the propertySet(s) that match(es) the + * provided componentClass + */ + this.getPropertySetsByType = function(componentType){ + var propertySets = []; + for(var x=0; x < this.propertySetsList.length; x++){ + var cpl = this.propertySetsList[x]; + var cpcc = cpl["componentClass"]||cpl["componentType"]||null; + if((cpcc)&&(propertySetId == cpcc[0].value)){ + propertySets.push(cpl); + } + } + return propertySets; + } + + /* getPropertySets returns the propertySet for a given component fragment + */ + this.getPropertySets = function(fragment){ + var ppl = "dojo:propertyproviderlist"; + var propertySets = []; + var tagname = fragment["tagName"]; + if(fragment[ppl]){ + var propertyProviderIds = fragment[ppl].value.split(" "); + // FIXME: should the propertyProviderList attribute contain # + // syntax for reference to ids or not? + // FIXME: need a better test to see if this is local or external + // FIXME: doesn't handle nested propertySets, or propertySets that + // just contain information about css documents, etc. + for(propertySetId in propertyProviderIds){ + if((propertySetId.indexOf("..")==-1)&&(propertySetId.indexOf("://")==-1)){ + // get a reference to a propertySet within the current parsed structure + var propertySet = this.getPropertySetById(propertySetId); + if(propertySet != ""){ + propertySets.push(propertySet); + } + }else{ + // FIXME: add code to parse and return a propertySet from + // another document + // alex: is this even necessaray? Do we care? If so, why? + } + } + } + // we put the typed ones first so that the parsed ones override when + // iteration happens. + return (this.getPropertySetsByType(tagname)).concat(propertySets); + } + + /* + nodeRef is the node to be replaced... in the future, we might want to add + an alternative way to specify an insertion point + + componentName is the expected dojo widget name, i.e. Button of ContextMenu + + properties is an object of name value pairs + */ + this.createComponentFromScript = function(nodeRef, componentName, properties){ + var ltn = "dojo:" + componentName.toLowerCase(); + if(dojo.widget.tags[ltn]){ + properties.fastMixIn = true; + return [dojo.widget.tags[ltn](properties, this, null, null, properties)]; + }else{ + if(ltn.substr(0, 5)=="dojo:"){ + dojo.debug("no tag handler registed for type: ", ltn); + } + } + } +} + + +dojo.widget._parser_collection = {"dojo": new dojo.widget.Parse() }; +dojo.widget.getParser = function(name){ + if(!name){ name = "dojo"; } + if(!this._parser_collection[name]){ + this._parser_collection[name] = new dojo.widget.Parse(); + } + return this._parser_collection[name]; +} + +/** + * Creates widget. + * + * @param name The name of the widget to create + * @param props Key-Value pairs of properties of the widget + * @param refNode If the last argument is specified this node is used as + * a reference for inserting this node into a DOM tree else + * it beomces the domNode + * @param position The position to insert this widget's node relative to the + * refNode argument + * @return The new Widget object + */ + +dojo.widget.createWidget = function (name, props, refNode, position) { + + function fromScript (placeKeeperNode, name, props) { + var lowerCaseName = name.toLowerCase(); + var namespacedName = "dojo:" + lowerCaseName; + props[namespacedName] = { + dojotype: [{value: lowerCaseName}], + nodeRef: placeKeeperNode, + fastMixIn: true + }; + return dojo.widget.getParser().createComponentFromScript( + placeKeeperNode, name, props, true); + } + + if (typeof name != "string" && typeof props == "string") { + dojo.deprecated("dojo.widget.createWidget", + "argument order is now of the form " + + "dojo.widget.createWidget(NAME, [PROPERTIES, [REFERENCENODE, [POSITION]]])"); + return fromScript(name, props, refNode); + } + + props = props||{}; + var notRef = false; + var tn = null; + var h = dojo.render.html.capable; + if(h){ + tn = document.createElement("span"); + } + if(!refNode){ + notRef = true; + refNode = tn; + if(h){ + dojo.html.body().appendChild(refNode); + } + }else if(position){ + dojo.dom.insertAtPosition(tn, refNode, position); + }else{ // otherwise don't replace, but build in-place + tn = refNode; + } + var widgetArray = fromScript(tn, name, props); + if (!widgetArray[0] || typeof widgetArray[0].widgetType == "undefined") { + throw new Error("createWidget: Creation of \"" + name + "\" widget failed."); + } + if (notRef) { + if (widgetArray[0].domNode.parentNode) { + widgetArray[0].domNode.parentNode.removeChild(widgetArray[0].domNode); + } + } + return widgetArray[0]; // just return the widget +} + +dojo.widget.fromScript = function(name, props, refNode, position){ + dojo.deprecated("dojo.widget.fromScript", " use " + + "dojo.widget.createWidget instead"); + return dojo.widget.createWidget(name, props, refNode, position); +} Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/PopUpButton.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/PopUpButton.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/PopUpButton.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/PopUpButton.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,192 @@ +/* + 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.PopUpButton"); +dojo.provide("dojo.widget.DomPopUpButton"); +dojo.provide("dojo.widget.HtmlPopUpButton"); + +dojo.deprecated("dojo.widget.PopUpButton, dojo.widget.DomPopUpButton, dojo.widget.HtmlPopUpButton", "use dojo.widget.DropDownButton2", "0.4"); + +//dojo.require("dojo.widget.Button"); +//dojo.require("dojo.widget.HtmlButton"); + +dojo.require("dojo.widget.Menu"); +dojo.require("dojo.widget.MenuItem"); + +dojo.require("dojo.html"); + +dojo.widget.tags.addParseTreeHandler("dojo:PopUpButton"); + +/* PopUpButton + **************/ + +dojo.widget.PopUpButton = function () { + dojo.widget.PopUpButton.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.PopUpButton, dojo.widget.Widget); + +dojo.lang.extend(dojo.widget.PopUpButton, { + widgetType: "PopUpButton", + + label: "" +}); + + +/* DomPopUpButton + *****************/ +dojo.widget.DomPopUpButton = function(){ + dojo.widget.DomPopUpButton.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.DomPopUpButton, dojo.widget.DomWidget); + +dojo.lang.extend(dojo.widget.DomPopUpButton, { + widgetType: dojo.widget.PopUpButton.prototype.widgetType +}); + + +/* HtmlPopUpButton + ******************/ + +dojo.widget.HtmlPopUpButton = function () { + dojo.widget.HtmlPopUpButton.superclass.constructor.call(this); +} +dojo.inherits(dojo.widget.HtmlPopUpButton, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.HtmlPopUpButton, { + widgetType: dojo.widget.PopUpButton.prototype.widgetType, + templateString: null, + templateCssPath: dojo.uri.dojoUri("src/widget/templates/PopUpButton.css"), + + buildRendering: function (args, frag) { + dojo.html.insertCssFile(this.templateCssPath, null, true); + + this.domNode = document.createElement("a"); + this.domNode.className = "PopUpButton"; + dojo.event.connect(this.domNode, "onmousedown", this, "onMouseDown"); + + // draw the arrow + var arrow = document.createElement("img"); + arrow.src = dojo.uri.dojoUri("src/widget/templates/images/dropdownButtonsArrow.gif"); + dojo.html.setClass(arrow, "downArrow"); + this.domNode.appendChild(arrow); + + this.menu = dojo.widget.fromScript("Menu"); + dojo.html.addClass(this.menu.domNode, "PopUpButtonMenu"); + dojo.event.connect(this.menu, "onSelect", this, "onSelect"); + + if (frag["dojo:" + this.widgetType.toLowerCase()].nodeRef) { + var node = frag["dojo:" + this.widgetType.toLowerCase()].nodeRef; + var options = node.getElementsByTagName("option"); + for (var i = 0; i < options.length; i++) { + var properties = { + title: dojo.dom.textContent(options[i]), + value: options[i].value + } + this.addItem(dojo.widget.fromScript("MenuItem", properties)); + } + } + }, + + addItem: function (item) { + // TODO: should be dojo.widget.MenuItem + if (item instanceof dojo.widget.html.MenuItem) { + this.menu.push(item); + } else { + // TODO: create one + var menuItem = dojo.widget.fromScript("MenuItem", {title: item}); + this.menu.push(menuItem); + } + }, + + +/* Enabled utility methods + **************************/ + + _enabled: true, + + isEnabled: function() { return this._enabled; }, + + setEnabled: function(enabled, force, preventEvent) { + enabled = Boolean(enabled); + if (force || this._enabled != enabled) { + this._enabled = enabled; + if (!preventEvent) { + this._fireEvent(this._enabled ? "onEnable" : "onDisable"); + this._fireEvent("onChangeEnabled"); + } + } + + dojo.html[(this._enabled ? "add" : "remove") + + "Class"](this.domNode, "disabled"); + + return this._enabled; + }, + + enable: function(force, preventEvent) { + return this.setEnabled(true, force, preventEvent); + }, + + disable: function(force, preventEvent) { + return this.setEnabled(false, force, preventEvent); + }, + + toggleEnabled: function(force, preventEvent) { + return this.setEnabled(!this._enabled, force, preventEvent); + }, + + +/* Select utility methods + **************************/ + + onSelect: function (item, e) { + this.domNode.firstChild.nodeValue = item.title; + }, + + onMouseDown: function (e) { + if (!this._menuVisible) { + this._showMenu(e); + dojo.lang.setTimeout(dojo.event.connect, 1, document, "onmousedown", this, "_hideMenu"); + } + }, + + + _fireEvent: function(evt) { + if(typeof this[evt] == "function") { + var args = [this]; + for(var i = 1; i < arguments.length; i++) { + args.push(arguments[i]); + } + this[evt].apply(this, args); + } + }, + + + _showMenu: function (e) { + if (!this._enabled) { return; } + this._menuVisible = true; + with (dojo.html) { + var y = getAbsoluteY(this.domNode) + getInnerHeight(this.domNode); + var x = getAbsoluteX(this.domNode); + } + + dojo.html.body().appendChild(this.menu.domNode); + with (this.menu.domNode.style) { + top = y + "px"; + left = x + "px"; + } + }, + + _hideMenu: function (e) { + this.menu.domNode.parentNode.removeChild(this.menu.domNode); + dojo.event.disconnect(document, "onmousedown", this, "_hideMenu"); + this._menuVisible = false; + } + +}); Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizableTextarea.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizableTextarea.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizableTextarea.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizableTextarea.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,110 @@ +/* + 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.ResizableTextarea"); +dojo.require("dojo.html"); +dojo.require("dojo.widget.*"); +dojo.require("dojo.widget.LayoutPane"); +dojo.require("dojo.widget.ResizeHandle"); + +dojo.widget.tags.addParseTreeHandler("dojo:resizabletextarea"); + +dojo.widget.ResizableTextarea = function(){ + dojo.widget.HtmlWidget.call(this); +} + +dojo.inherits(dojo.widget.ResizableTextarea, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.ResizableTextarea, { + templatePath: dojo.uri.dojoUri("src/widget/templates/HtmlResizableTextarea.html"), + templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlResizableTextarea.css"), + widgetType: "ResizableTextarea", + tagName: "dojo:resizabletextarea", + isContainer: false, + textAreaNode: null, + textAreaContainer: null, + textAreaContainerNode: null, + statusBar: null, + statusBarContainerNode: null, + statusLabelNode: null, + statusLabel: null, + rootLayoutNode: null, + resizeHandleNode: null, + resizeHandle: null, + + fillInTemplate: function(args, frag){ + this.textAreaNode = this.getFragNodeRef(frag).cloneNode(true); + + // FIXME: Safari apparently needs this! + document.body.appendChild(this.domNode); + + this.rootLayout = dojo.widget.createWidget( + "LayoutPane", + { + minHeight: 50, + minWidth: 100 + }, + this.rootLayoutNode + ); + + + this.textAreaContainer = dojo.widget.createWidget( + "LayoutPane", + { layoutAlign: "client" }, + this.textAreaContainerNode + ); + this.rootLayout.addChild(this.textAreaContainer); + + this.textAreaContainer.domNode.appendChild(this.textAreaNode); + with(this.textAreaNode.style){ + width="100%"; + height="100%"; + } + + this.statusBar = dojo.widget.createWidget( + "LayoutPane", + { + layoutAlign: "bottom", + minHeight: 28 + }, + this.statusBarContainerNode + ); + this.rootLayout.addChild(this.statusBar); + + this.statusLabel = dojo.widget.createWidget( + "LayoutPane", + { + layoutAlign: "client", + minWidth: 50 + }, + this.statusLabelNode + ); + this.statusBar.addChild(this.statusLabel); + + this.resizeHandle = dojo.widget.createWidget( + "ResizeHandle", + { targetElmId: this.rootLayout.widgetId }, + this.resizeHandleNode + ); + this.statusBar.addChild(this.resizeHandle); + // dojo.debug(this.rootLayout.widgetId); + + // dojo.event.connect(this.resizeHandle, "beginSizing", this, "hideContent"); + // dojo.event.connect(this.resizeHandle, "endSizing", this, "showContent"); + }, + + hideContent: function(){ + this.textAreaNode.style.display = "none"; + }, + + showContent: function(){ + this.textAreaNode.style.display = ""; + } +}); Added: incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizeHandle.js URL: http://svn.apache.org/viewcvs/incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizeHandle.js?rev=393978&view=auto ============================================================================== --- incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizeHandle.js (added) +++ incubator/webwork2/action/src/main/resources/org/apache/struts/action2/static/dojo/src/widget/ResizeHandle.js Thu Apr 13 16:46:55 2006 @@ -0,0 +1,101 @@ +/* + 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.ResizeHandle"); +dojo.provide("dojo.widget.html.ResizeHandle"); + +dojo.require("dojo.widget.*"); +dojo.require("dojo.html"); +dojo.require("dojo.style"); +dojo.require("dojo.dom"); +dojo.require("dojo.event"); + +dojo.widget.html.ResizeHandle = function(){ + dojo.widget.HtmlWidget.call(this); +} + +dojo.inherits(dojo.widget.html.ResizeHandle, dojo.widget.HtmlWidget); + +dojo.lang.extend(dojo.widget.html.ResizeHandle, { + widgetType: "ResizeHandle", + + isSizing: false, + startPoint: null, + startSize: null, + + grabImg: null, + + targetElmId: '', + imgSrc: dojo.uri.dojoUri("src/widget/templates/grabCorner.gif"), + + templateCssPath: dojo.uri.dojoUri("src/widget/templates/HtmlResizeHandle.css"), + templateString: '<div dojoAttachPoint="domNode"><img dojoAttachPoint="grabImg" /></div>', + + fillInTemplate: function(){ + + dojo.style.insertCssFile(this.templateCssPath); + + dojo.html.addClass(this.domNode, 'dojoHtmlResizeHandle'); + dojo.html.addClass(this.grabImg, 'dojoHtmlResizeHandleImage'); + + this.grabImg.src = this.imgSrc; + }, + + postCreate: function(){ + dojo.event.connect(this.domNode, "onmousedown", this, "beginSizing"); + }, + + beginSizing: function(e){ + if (this.isSizing){ return false; } + + this.targetElm = dojo.widget.byId(this.targetElmId); + if (!this.targetElm){ return; } + + var screenX = window.event ? window.event.clientX : e.pageX; + var screenY = window.event ? window.event.clientY : e.pageY; + + this.isSizing = true; + this.startPoint = {'x':e.clientX, 'y':e.clientY}; + this.startSize = {'w':dojo.style.getOuterWidth(this.targetElm.domNode), 'h':dojo.style.getOuterHeight(this.targetElm.domNode)}; + + dojo.event.kwConnect({ + srcObj: dojo.html.body(), + srcFunc: "onmousemove", + targetObj: this, + targetFunc: "changeSizing", + rate: 25 + }); + dojo.event.connect(dojo.html.body(), "onmouseup", this, "endSizing"); + + e.preventDefault(); + }, + + changeSizing: function(e){ + // On IE, if you move the mouse above/to the left of the object being resized, + // sometimes clientX/Y aren't set, apparently. Just ignore the event. + if(!e.clientX || !e.clientY){ return; } + var dx = this.startPoint.x - e.clientX; + var dy = this.startPoint.y - e.clientY; + this.targetElm.resizeTo(this.startSize.w - dx, this.startSize.h - dy); + + e.preventDefault(); + }, + + endSizing: function(e){ + dojo.event.disconnect(dojo.html.body(), "onmousemove", this, "changeSizing"); + dojo.event.disconnect(dojo.html.body(), "onmouseup", this, "endSizing"); + + this.isSizing = false; + } + + +}); + +dojo.widget.tags.addParseTreeHandler("dojo:ResizeHandle"); --------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]