Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js
URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,682 @@ +/* + Copyright (c) 2004-2006, 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.Editor2Toolbar"); + +dojo.require("dojo.lang.*"); +dojo.require("dojo.widget.*"); +dojo.require("dojo.event.*"); +dojo.require("dojo.html.layout"); +dojo.require("dojo.html.display"); +dojo.require("dojo.widget.RichText"); +dojo.require("dojo.widget.PopupContainer"); +dojo.require("dojo.widget.ColorPalette"); + +dojo.lang.declare("dojo.widget.HandlerManager", null, + function(){ + this._registeredHandlers=[]; + }, +{ + // summary: internal base class for handler function management + registerHandler: function(/*Object*/obj, /*String*/func){ + // summary: register a handler + // obj: object which has the function to call + // func: the function in the object + if(arguments.length == 2){ + this._registeredHandlers.push(function(){return obj[func].apply(obj, arguments);}); + }else{ + /* obj: Function + func: null + pId: f */ + this._registeredHandlers.push(obj); + } + }, + removeHandler: function(func){ + // summary: remove a registered handler + for(var i=0;i<this._registeredHandlers.length;i++){ + if(func === this._registeredHandlers[i]){ + delete this._registeredHandlers[i]; + return; + } + } + dojo.debug("HandlerManager handler "+func+" is not registered, can not remove."); + }, + destroy: function(){ + for(var i=0;i<this._registeredHandlers.length;i++){ + delete this._registeredHandlers[i]; + } + } +}); + +dojo.widget.Editor2ToolbarItemManager = new dojo.widget.HandlerManager; +dojo.lang.mixin(dojo.widget.Editor2ToolbarItemManager, +{ + getToolbarItem: function(/*String*/name){ + // summary: return a toobar item with the given name + var item; + name = name.toLowerCase(); + for(var i=0;i<this._registeredHandlers.length;i++){ + item = this._registeredHandlers[i](name); + if(item){ + return item; + } + } + + switch(name){ + //button for builtin functions + case 'bold': + case 'copy': + case 'cut': + case 'delete': + case 'indent': + case 'inserthorizontalrule': + case 'insertorderedlist': + case 'insertunorderedlist': + case 'italic': + case 'justifycenter': + case 'justifyfull': + case 'justifyleft': + case 'justifyright': + case 'outdent': + case 'paste': + case 'redo': + case 'removeformat': + case 'selectall': + case 'strikethrough': + case 'subscript': + case 'superscript': + case 'underline': + case 'undo': + case 'unlink': + case 'createlink': + case 'insertimage': + //extra simple buttons + case 'htmltoggle': + item = new dojo.widget.Editor2ToolbarButton(name); + break; + case 'forecolor': + case 'hilitecolor': + item = new dojo.widget.Editor2ToolbarColorPaletteButton(name); + break; + case 'plainformatblock': + item = new dojo.widget.Editor2ToolbarFormatBlockPlainSelect("formatblock"); + break; + case 'formatblock': + item = new dojo.widget.Editor2ToolbarFormatBlockSelect("formatblock"); + break; + case 'fontsize': + item = new dojo.widget.Editor2ToolbarFontSizeSelect("fontsize"); + break; + case 'fontname': + item = new dojo.widget.Editor2ToolbarFontNameSelect("fontname"); + break; + case 'inserttable': + case 'insertcell': + case 'insertcol': + case 'insertrow': + case 'deletecells': + case 'deletecols': + case 'deleterows': + case 'mergecells': + case 'splitcell': + dojo.debug(name + " is implemented in dojo.widget.Editor2Plugin.TableOperation, please require it first."); + break; + //TODO: + case 'inserthtml': + case 'blockdirltr': + case 'blockdirrtl': + case 'dirltr': + case 'dirrtl': + case 'inlinedirltr': + case 'inlinedirrtl': + dojo.debug("Not yet implemented toolbar item: "+name); + break; + default: + dojo.debug("dojo.widget.Editor2ToolbarItemManager.getToolbarItem: Unknown toolbar item: "+name); + } + return item; + } +}); + +dojo.addOnUnload(dojo.widget.Editor2ToolbarItemManager, "destroy"); + +dojo.declare("dojo.widget.Editor2ToolbarButton", null, + function(name){ + this._name = name; +// this._command = editor.getCommand(name); + }, +{ + // summary: + // dojo.widget.Editor2ToolbarButton is the base class for all toolbar item in Editor2Toolbar + create: function(/*DomNode*/node, /*dojo.widget.Editor2Toolbar*/toolbar, /*Boolean*/nohover){ + // summary: create the item + // node: the dom node which is the root of this toolbar item + // toolbar: the Editor2Toolbar widget this toolbar item belonging to + // nohover: whether this item in charge of highlight this item + this._domNode = node; + var cmd = toolbar.parent.getCommand(this._name); //FIXME: maybe an issue if different instance has different language + if(cmd){ + this._domNode.title = cmd.getText(); + } + //make this unselectable: different browsers + //use different properties for this, so use + //js do it automatically + this.disableSelection(this._domNode); + + this._parentToolbar = toolbar; + dojo.event.connect(this._domNode, 'onclick', this, 'onClick'); + if(!nohover){ + dojo.event.connect(this._domNode, 'onmouseover', this, 'onMouseOver'); + dojo.event.connect(this._domNode, 'onmouseout', this, 'onMouseOut'); + } + }, + disableSelection: function(/*DomNode*/rootnode){ + // summary: disable selection on the passed node and all its children + dojo.html.disableSelection(rootnode); + var nodes = rootnode.all || rootnode.getElementsByTagName("*"); + for(var x=0; x<nodes.length; x++){ + dojo.html.disableSelection(nodes[x]); + } + }, + onMouseOver: function(){ + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command && _command.getState() != dojo.widget.Editor2Manager.commandState.Disabled){ + this.highlightToolbarItem(); + } + } + }, + onMouseOut: function(){ + this.unhighlightToolbarItem(); + }, + destroy: function(){ + // summary: destructor + this._domNode = null; +// delete this._command; + this._parentToolbar = null; + }, + onClick: function(e){ + if(this._domNode && !this._domNode.disabled && this._parentToolbar.checkAvailability()){ + e.preventDefault(); + e.stopPropagation(); + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + _command.execute(); + } + } + } + }, + refreshState: function(){ + // summary: update the state of the toolbar item + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + var em = dojo.widget.Editor2Manager; + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + var state = _command.getState(); + if(state != this._lastState){ + switch(state){ + case em.commandState.Latched: + this.latchToolbarItem(); + break; + case em.commandState.Enabled: + this.enableToolbarItem(); + break; + case em.commandState.Disabled: + default: + this.disableToolbarItem(); + } + this._lastState = state; + } + } + } + return em.commandState.Enabled; + }, + + latchToolbarItem: function(){ + this._domNode.disabled = false; + this.removeToolbarItemStyle(this._domNode); + dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle); + }, + + enableToolbarItem: function(){ + this._domNode.disabled = false; + this.removeToolbarItemStyle(this._domNode); + dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle); + }, + + disableToolbarItem: function(){ + this._domNode.disabled = true; + this.removeToolbarItemStyle(this._domNode); + dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle); + }, + + highlightToolbarItem: function(){ + dojo.html.addClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle); + }, + + unhighlightToolbarItem: function(){ + dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarHighlightedItemStyle); + }, + + removeToolbarItemStyle: function(){ + dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarEnabledItemStyle); + dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarLatchedItemStyle); + dojo.html.removeClass(this._domNode, this._parentToolbar.ToolbarDisabledItemStyle); + this.unhighlightToolbarItem(); + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarDropDownButton", dojo.widget.Editor2ToolbarButton, { + // summary: dojo.widget.Editor2ToolbarDropDownButton extends the basic button with a dropdown list + + onClick: function(){ + if(this._domNode && !this._domNode.disabled && this._parentToolbar.checkAvailability()){ + if(!this._dropdown){ + this._dropdown = dojo.widget.createWidget("PopupContainer", {}); + this._domNode.appendChild(this._dropdown.domNode); + } + if(this._dropdown.isShowingNow){ + this._dropdown.close(); + }else{ + this.onDropDownShown(); + this._dropdown.open(this._domNode, null, this._domNode); + } + } + }, + destroy: function(){ + this.onDropDownDestroy(); + if(this._dropdown){ + this._dropdown.destroy(); + } + dojo.widget.Editor2ToolbarDropDownButton.superclass.destroy.call(this); + }, + onDropDownShown: function(){}, + onDropDownDestroy: function(){} +}); + +dojo.declare("dojo.widget.Editor2ToolbarColorPaletteButton", dojo.widget.Editor2ToolbarDropDownButton, { + // summary: dojo.widget.Editor2ToolbarColorPaletteButton provides a dropdown color palette picker + + onDropDownShown: function(){ + if(!this._colorpalette){ + this._colorpalette = dojo.widget.createWidget("ColorPalette", {}); + this._dropdown.addChild(this._colorpalette); + + this.disableSelection(this._dropdown.domNode); + this.disableSelection(this._colorpalette.domNode); + //do we need a destory to delete this._colorpalette manually? + //I assume as it is added to this._dropdown via addChild, it + //should be deleted when this._dropdown is destroyed + + dojo.event.connect(this._colorpalette, "onColorSelect", this, 'setColor'); + dojo.event.connect(this._dropdown, "open", this, 'latchToolbarItem'); + dojo.event.connect(this._dropdown, "close", this, 'enableToolbarItem'); + } + }, + setColor: function(color){ + this._dropdown.close(); + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + _command.execute(color); + } + } + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarFormatBlockPlainSelect", dojo.widget.Editor2ToolbarButton, { + // summary: dojo.widget.Editor2ToolbarFormatBlockPlainSelect provides a simple select for setting block format + + create: function(node, toolbar){ +// dojo.widget.Editor2ToolbarFormatBlockPlainSelect.superclass.create.apply(this, arguments); + this._domNode = node; + this._parentToolbar = toolbar; + //TODO: check node is a select + this._domNode = node; + this.disableSelection(this._domNode); + dojo.event.connect(this._domNode, 'onchange', this, 'onChange'); + }, + + destroy: function(){ + this._domNode = null; + }, + + onChange: function(){ + if(this._parentToolbar.checkAvailability()){ + var sv = this._domNode.value.toLowerCase(); + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + _command.execute(sv); + } + } + } + }, + + refreshState: function(){ + if(this._domNode){ + dojo.widget.Editor2ToolbarFormatBlockPlainSelect.superclass.refreshState.call(this); + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + var format = _command.getValue(); + if(!format){ format = ""; } + dojo.lang.forEach(this._domNode.options, function(item){ + if(item.value.toLowerCase() == format.toLowerCase()){ + item.selected = true; + } + }); + } + } + } + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarComboItem", dojo.widget.Editor2ToolbarDropDownButton,{ + // summary: dojo.widget.Editor2ToolbarComboItem provides an external loaded dropdown list + + href: null, + create: function(node, toolbar){ + dojo.widget.Editor2ToolbarComboItem.superclass.create.apply(this, arguments); + //do not use lazy initilization, as we need the local names in refreshState() + if(!this._contentPane){ + dojo.require("dojo.widget.ContentPane"); + this._contentPane = dojo.widget.createWidget("ContentPane", {preload: 'true'}); + this._contentPane.addOnLoad(this, "setup"); + this._contentPane.setUrl(this.href); + } + }, + + onMouseOver: function(e){ + if(this._lastState != dojo.widget.Editor2Manager.commandState.Disabled){ + dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle); + } + }, + onMouseOut:function(e){ + dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectStyle); + }, + + onDropDownShown: function(){ + if(!this._dropdown.__addedContentPage){ + this._dropdown.addChild(this._contentPane); + this._dropdown.__addedContentPage = true; + } + }, + + setup: function(){ + // summary: overload this to connect event + }, + + onChange: function(e){ + if(this._parentToolbar.checkAvailability()){ + var name = e.currentTarget.getAttribute("dropDownItemName"); + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + _command.execute(name); + } + } + } + this._dropdown.close(); + }, + + onMouseOverItem: function(e){ + dojo.html.addClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle); + }, + + onMouseOutItem: function(e){ + dojo.html.removeClass(e.currentTarget, this._parentToolbar.ToolbarHighlightedSelectItemStyle); + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarFormatBlockSelect", dojo.widget.Editor2ToolbarComboItem, { + // summary: dojo.widget.Editor2ToolbarFormatBlockSelect is an improved format block setting item + + href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FormatBlock.html"), + + setup: function(){ + dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this); + + var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*"); + this._blockNames = {}; + this._blockDisplayNames = {}; + for(var x=0; x<nodes.length; x++){ + var node = nodes[x]; + dojo.html.disableSelection(node); + var name=node.getAttribute("dropDownItemName") + if(name){ + this._blockNames[name] = node; + var childrennodes = node.getElementsByTagName(name); + this._blockDisplayNames[name] = childrennodes[childrennodes.length-1].innerHTML; + } + } + for(var name in this._blockNames){ + dojo.event.connect(this._blockNames[name], "onclick", this, "onChange"); + dojo.event.connect(this._blockNames[name], "onmouseover", this, "onMouseOverItem"); + dojo.event.connect(this._blockNames[name], "onmouseout", this, "onMouseOutItem"); + } + }, + + onDropDownDestroy: function(){ + if(this._blockNames){ + for(var name in this._blockNames){ + delete this._blockNames[name]; + delete this._blockDisplayNames[name]; + } + } + }, + + refreshState: function(){ + dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this); + if(this._lastState != dojo.widget.Editor2Manager.commandState.Disabled){ + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + var format = _command.getValue(); + if(format == this._lastSelectedFormat && this._blockDisplayNames){ + return this._lastState; + } + this._lastSelectedFormat = format; + var label = this._domNode.getElementsByTagName("label")[0]; + var isSet = false; + if(this._blockDisplayNames){ + for(var name in this._blockDisplayNames){ + if(name == format){ + label.innerHTML = this._blockDisplayNames[name]; + isSet = true; + break; + } + } + if(!isSet){ + label.innerHTML = " "; + } + } + } + } + } + + return this._lastState; + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarFontSizeSelect", dojo.widget.Editor2ToolbarComboItem,{ + // summary: dojo.widget.Editor2ToolbarFontSizeSelect provides a dropdown list for setting fontsize + + href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontSize.html"), + + setup: function(){ + dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.setup.call(this); + + var nodes = this._contentPane.domNode.all || this._contentPane.domNode.getElementsByTagName("*"); + this._fontsizes = {}; + this._fontSizeDisplayNames = {}; + for(var x=0; x<nodes.length; x++){ + var node = nodes[x]; + dojo.html.disableSelection(node); + var name=node.getAttribute("dropDownItemName") + if(name){ + this._fontsizes[name] = node; + this._fontSizeDisplayNames[name] = node.getElementsByTagName('font')[0].innerHTML; + } + } + for(var name in this._fontsizes){ + dojo.event.connect(this._fontsizes[name], "onclick", this, "onChange"); + dojo.event.connect(this._fontsizes[name], "onmouseover", this, "onMouseOverItem"); + dojo.event.connect(this._fontsizes[name], "onmouseout", this, "onMouseOutItem"); + } + }, + + onDropDownDestroy: function(){ + if(this._fontsizes){ + for(var name in this._fontsizes){ + delete this._fontsizes[name]; + delete this._fontSizeDisplayNames[name]; + } + } + }, + + refreshState: function(){ + dojo.widget.Editor2ToolbarFormatBlockSelect.superclass.refreshState.call(this); + if(this._lastState != dojo.widget.Editor2Manager.commandState.Disabled){ + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(curInst){ + var _command = curInst.getCommand(this._name); + if(_command){ + var size = _command.getValue(); + if(size == this._lastSelectedSize && this._fontSizeDisplayNames){ + return this._lastState; + } + this._lastSelectedSize = size; + var label = this._domNode.getElementsByTagName("label")[0]; + var isSet = false; + if(this._fontSizeDisplayNames){ + for(var name in this._fontSizeDisplayNames){ + if(name == size){ + label.innerHTML = this._fontSizeDisplayNames[name]; + isSet = true; + break; + } + } + if(!isSet){ + label.innerHTML = " "; + } + } + } + } + } + return this._lastState; + } +}); + +dojo.declare("dojo.widget.Editor2ToolbarFontNameSelect", dojo.widget.Editor2ToolbarFontSizeSelect, { + // summary: dojo.widget.Editor2ToolbarFontNameSelect provides a dropdown list for setting fontname + href: dojo.uri.dojoUri("src/widget/templates/Editor2/EditorToolbar_FontName.html") +}); + +dojo.widget.defineWidget( + "dojo.widget.Editor2Toolbar", + dojo.widget.HtmlWidget, + function(){ + dojo.event.connect(this, "fillInTemplate", dojo.lang.hitch(this, function(){ + if(dojo.render.html.ie){ + this.domNode.style.zoom = 1.0; + } + })); + }, + { + // summary: + // dojo.widget.Editor2Toolbar is the main widget for the toolbar associated with an Editor2 + + templatePath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.html"), + templateCssPath: dojo.uri.dojoUri("src/widget/templates/EditorToolbar.css"), + + // ToolbarLatchedItemStyle: String: class name for latched toolbar button items + ToolbarLatchedItemStyle: "ToolbarButtonLatched", + + // ToolbarEnabledItemStyle: String: class name for enabled toolbar button items + ToolbarEnabledItemStyle: "ToolbarButtonEnabled", + + // ToolbarDisabledItemStyle: String: class name for disabled toolbar button items + ToolbarDisabledItemStyle: "ToolbarButtonDisabled", + + // ToolbarHighlightedItemStyle: String: class name for highlighted toolbar button items + ToolbarHighlightedItemStyle: "ToolbarButtonHighlighted", + + // ToolbarHighlightedSelectStyle: String: class name for highlighted toolbar select items + ToolbarHighlightedSelectStyle: "ToolbarSelectHighlighted", + + // ToolbarHighlightedSelectItemStyle: String: class name for highlighted toolbar select dropdown items + ToolbarHighlightedSelectItemStyle: "ToolbarSelectHighlightedItem", + +// itemNodeType: 'span', //all the items (with attribute dojoETItemName set) defined in the toolbar should be a of this type + + postCreate: function(){ + var nodes = dojo.html.getElementsByClass("dojoEditorToolbarItem", this.domNode/*, this.itemNodeType*/); + + this.items = {}; + for(var x=0; x<nodes.length; x++){ + var node = nodes[x]; + var itemname = node.getAttribute("dojoETItemName"); + if(itemname){ + var item = dojo.widget.Editor2ToolbarItemManager.getToolbarItem(itemname); + if(item){ + item.create(node, this); + this.items[itemname.toLowerCase()] = item; + }else{ + //hide unsupported toolbar items + node.style.display = "none"; + } + } + } + }, + + update: function(){ + // summary: update all the toolbar items + for(var cmd in this.items){ + this.items[cmd].refreshState(); + } + }, + + shareGroup: '', + checkAvailability: function(){ + // summary: returns whether items in this toolbar can be executed + // description: + // For unshared toolbar, when clicking on a toolbar, the corresponding + // editor will be focused, and this function always return true. For shared + // toolbar, if the current focued editor is not one of the instances sharing + // this toolbar, this function return false, otherwise true. + if(!this.shareGroup){ + this.parent.focus(); + return true; + } + var curInst = dojo.widget.Editor2Manager.getCurrentInstance(); + if(this.shareGroup == curInst.toolbarGroup){ + return true; + } + return false; + }, + destroy: function(){ + for(var it in this.items){ + this.items[it].destroy(); + delete this.items[it]; + } + dojo.widget.Editor2Toolbar.superclass.destroy.call(this); + } + } +); Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/Editor2Toolbar.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,1003 @@ +/* + Copyright (c) 2004-2006, 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.FilteringTable"); + +dojo.require("dojo.date.format"); +dojo.require("dojo.collections.Store"); +dojo.require("dojo.html.*"); +dojo.require("dojo.html.util"); +dojo.require("dojo.html.style"); +dojo.require("dojo.html.selection"); +dojo.require("dojo.event.*"); +dojo.require("dojo.widget.*"); +dojo.require("dojo.widget.HtmlWidget"); + +dojo.widget.defineWidget( + "dojo.widget.FilteringTable", + dojo.widget.HtmlWidget, + function(){ + // summary: A basic tabular data widget that supports sorting and filtering mechanisms. + // description: + // FilteringTable is a 2D data view that supports multiple column sorting and filtering + // functionality. It can get its data in one of two ways: via HTML (i.e. degradable + // data), or from an external JSON source through widget.store.setData. Records in + // a FilteringTable can be selected as if it were a select list. + // store: dojo.collections.Store + // The underlying Store for all data represented by the widget. + // valueField: String + // The name of the field used as a unique key for each row, defaults to "Id". + // multiple: boolean + // Allow multiple selections. + // maxSelect: Integer + // Maximum number of rows that can be selected at once. 0 == no limit. + // maxSortable: Integer + // Maximum number of columns allowed for sorting at one time. + // minRows: Integer + // The minimum number of rows to show. Default is 0. + // defaultDateFormat: String + // The default format for a date column, as used by dojo.date.format. + // alternateRows: Boolean + // Use alternate row CSS classes to show zebra striping. + // headClass: String + // CSS Class name for the head of the table. + // tbodyClass: String + // CSS Class name for the body of the table. + // headerClass: String + // CSS Class name for headers that are not sorted. + // headerUpClass: String + // CSS Class name for headers that are for ascending sorted columns. Default is "selectedUp". + // headerDownClass: String + // CSS Class name for headers that are for descending sorted columns. Default is "selectedDown". + // rowClass: String + // CSS Class name for body rows. + // rowAlternateClass: String + // CSS Class name for alternate rows. Default is "alt". + // rowSelectedClass: String + // CSS Class name for selected rows. Default is "selected". + // columnSelectedClass: String + // CSS Class name for any columns being sorted on. Unimplemented. + this.store=new dojo.collections.Store(); + + //declare per instance changeable widget properties + this.valueField="Id"; + this.multiple=false; + this.maxSelect=0; + this.maxSortable=1; // how many columns can be sorted at once. + this.minRows=0; + this.defaultDateFormat = "%D"; + this.isInitialized=false; + this.alternateRows=false; + + this.columns=[]; + this.sortInformation=[{ + index:0, + direction:0 + }]; + + // CSS definitions + this.headClass=""; + this.tbodyClass=""; + this.headerClass=""; + this.headerUpClass="selectedUp"; + this.headerDownClass="selectedDown"; + this.rowClass=""; + this.rowAlternateClass="alt"; + this.rowSelectedClass="selected"; + this.columnSelected="sorted-column"; + }, +{ + // dojo widget properties + isContainer: false, + templatePath: null, + templateCssPath: null, + + // methods. + getTypeFromString: function(/* string */s){ + // summary + // Gets a function based on the passed string. + var parts = s.split("."), i = 0, obj = dj_global; + do{ + obj = obj[parts[i++]]; + } while (i < parts.length && obj); + return (obj != dj_global) ? obj : null; // function + }, + + // custom data access. + getByRow: function(/*HTMLTableRow*/row){ + // summary + // Returns the data object based on the passed row. + return this.store.getByKey(dojo.html.getAttribute(row, "value")); // object + }, + getDataByRow: function(/*HTMLTableRow*/row){ + // summary + // Returns the source data object based on the passed row. + return this.store.getDataByKey(dojo.html.getAttribute(row, "value")); // object + }, + + getRow: function(/* Object */ obj){ + // summary + // Finds the row in the table based on the passed data object. + var rows = this.domNode.tBodies[0].rows; + for(var i=0; i<rows.length; i++){ + if(this.store.getDataByKey(dojo.html.getAttribute(rows[i], "value")) == obj){ + return rows[i]; // HTMLTableRow + } + } + return null; // HTMLTableRow + }, + getColumnIndex: function(/* string */fieldPath){ + // summary + // Returns index of the column that represents the passed field path. + for(var i=0; i<this.columns.length; i++){ + if(this.columns[i].getField() == fieldPath){ + return i; // integer + } + } + return -1; // integer + }, + + getSelectedData: function(){ + // summary + // returns all objects that are selected. + var data=this.store.get(); + var a=[]; + for(var i=0; i<data.length; i++){ + if(data[i].isSelected){ + a.push(data[i].src); + } + } + if(this.multiple){ + return a; // array + } else { + return a[0]; // object + } + }, + + isSelected: function(/* object */obj){ + // summary + // Returns whether the passed object is currently selected. + var data = this.store.get(); + for(var i=0; i<data.length; i++){ + if(data[i].src == obj){ + return true; // boolean + } + } + return false; // boolean + }, + isValueSelected: function(/* string */val){ + // summary + // Returns the object represented by key "val" is selected. + var v = this.store.getByKey(val); + if(v){ + return v.isSelected; // boolean + } + return false; // boolean + }, + isIndexSelected: function(/* number */idx){ + // summary + // Returns the object represented by integer "idx" is selected. + var v = this.store.getByIndex(idx); + if(v){ + return v.isSelected; // boolean + } + return false; // boolean + }, + isRowSelected: function(/* HTMLTableRow */row){ + // summary + // Returns if the passed row is selected. + var v = this.getByRow(row); + if(v){ + return v.isSelected; // boolean + } + return false; // boolean + }, + + reset: function(){ + // summary + // Resets the widget to its initial internal state. + this.store.clearData(); + this.columns = []; + this.sortInformation = [ {index:0, direction:0} ]; + this.resetSelections(); + this.isInitialized = false; + this.onReset(); + }, + resetSelections: function(){ + // summary + // Unselects all data objects. + this.store.forEach(function(element){ + element.isSelected = false; + }); + }, + onReset:function(){ + // summary + // Stub for onReset event. + }, + + // selection and toggle functions + select: function(/*object*/ obj){ + // summary + // selects the passed object. + var data = this.store.get(); + for(var i=0; i<data.length; i++){ + if(data[i].src == obj){ + data[i].isSelected = true; + break; + } + } + this.onDataSelect(obj); + }, + selectByValue: function(/*string*/ val){ + // summary + // selects the object represented by key "val". + this.select(this.store.getDataByKey(val)); + }, + selectByIndex: function(/*number*/ idx){ + // summary + // selects the object represented at index "idx". + this.select(this.store.getDataByIndex(idx)); + }, + selectByRow: function(/*HTMLTableRow*/ row){ + // summary + // selects the object represented by HTMLTableRow row. + this.select(this.getDataByRow(row)); + }, + selectAll: function(){ + // summary + // selects all objects. + this.store.forEach(function(element){ + element.isSelected = true; + }); + }, + onDataSelect: function(/* object */obj){ + // summary + // Stub for onDataSelect event. + }, + + toggleSelection: function(/*object*/obj){ + // summary + // Flips the selection state of passed obj. + var data = this.store.get(); + for(var i=0; i<data.length; i++){ + if(data[i].src == obj){ + data[i].isSelected = !data[i].isSelected; + break; + } + } + this.onDataToggle(obj); + }, + toggleSelectionByValue: function(/*string*/val){ + // summary + // Flips the selection state of object represented by val. + this.toggleSelection(this.store.getDataByKey(val)); + }, + toggleSelectionByIndex: function(/*number*/idx){ + // summary + // Flips the selection state of object at index idx. + this.toggleSelection(this.store.getDataByIndex(idx)); + }, + toggleSelectionByRow: function(/*HTMLTableRow*/row){ + // summary + // Flips the selection state of object represented by row. + this.toggleSelection(this.getDataByRow(row)); + }, + toggleAll: function(){ + // summary + // Flips the selection state of all objects. + this.store.forEach(function(element){ + element.isSelected = !element.isSelected; + }); + }, + onDataToggle: function(/* object */obj){ + // summary + // Stub for onDataToggle event. + }, + + // parsing functions, from HTML to metadata/SimpleStore + _meta:{ + field:null, + format:null, + filterer:null, + noSort:false, + sortType:"String", + dataType:String, + sortFunction:null, + filterFunction:null, + label:null, + align:"left", + valign:"middle", + getField:function(){ + return this.field || this.label; + }, + getType:function(){ + return this.dataType; + } + }, + createMetaData: function(/* object */obj){ + // summary + // Take a JSON-type structure and make it into a ducktyped metadata object. + for(var p in this._meta){ + // rudimentary mixin + if(!obj[p]){ + obj[p] = this._meta[p]; + } + } + if(!obj.label){ + obj.label=obj.field; + } + if(!obj.filterFunction){ + obj.filterFunction=this._defaultFilter; + } + return obj; // object + }, + parseMetadata: function(/* HTMLTableHead */head){ + // summary + // Parses the passed HTMLTableHead element to create meta data. + this.columns=[]; + this.sortInformation=[]; + var row = head.getElementsByTagName("tr")[0]; + var cells = row.getElementsByTagName("td"); + if (cells.length == 0){ + cells = row.getElementsByTagName("th"); + } + for(var i=0; i<cells.length; i++){ + var o = this.createMetaData({ }); + + // presentation attributes + if(dojo.html.hasAttribute(cells[i], "align")){ + o.align = dojo.html.getAttribute(cells[i],"align"); + } + if(dojo.html.hasAttribute(cells[i], "valign")){ + o.valign = dojo.html.getAttribute(cells[i],"valign"); + } + if(dojo.html.hasAttribute(cells[i], "nosort")){ + o.noSort = (dojo.html.getAttribute(cells[i],"nosort")=="true"); + } + if(dojo.html.hasAttribute(cells[i], "sortusing")){ + var trans = dojo.html.getAttribute(cells[i],"sortusing"); + var f = this.getTypeFromString(trans); + if (f != null && f != window && typeof(f)=="function"){ + o.sortFunction=f; + } + } + o.label = dojo.html.renderedTextContent(cells[i]); + if(dojo.html.hasAttribute(cells[i], "field")){ + o.field=dojo.html.getAttribute(cells[i],"field"); + } else if(o.label.length > 0){ + o.field=o.label; + } else { + o.field = "field" + i; + } + if(dojo.html.hasAttribute(cells[i], "format")){ + o.format=dojo.html.getAttribute(cells[i],"format"); + } + if(dojo.html.hasAttribute(cells[i], "dataType")){ + var sortType = dojo.html.getAttribute(cells[i],"dataType"); + if(sortType.toLowerCase()=="html" || sortType.toLowerCase()=="markup"){ + o.sortType = "__markup__"; // always convert to "__markup__" + }else{ + var type = this.getTypeFromString(sortType); + if(type){ + o.sortType = sortType; + o.dataType = type; + } + } + } + + // TODO: set up filtering mechanisms here. + if(dojo.html.hasAttribute(cells[i], "filterusing")){ + var trans = dojo.html.getAttribute(cells[i],"filterusing"); + var f = this.getTypeFromString(trans); + if (f != null && f != window && typeof(f)=="function"){ + o.filterFunction=f; + } + } + + this.columns.push(o); + + // check to see if there's a default sort, and set the properties necessary + if(dojo.html.hasAttribute(cells[i], "sort")){ + var info = { + index:i, + direction:0 + }; + var dir = dojo.html.getAttribute(cells[i], "sort"); + if(!isNaN(parseInt(dir))){ + dir = parseInt(dir); + info.direction = (dir != 0) ? 1 : 0; + }else{ + info.direction = (dir.toLowerCase() == "desc") ? 1 : 0; + } + this.sortInformation.push(info); + } + } + if(this.sortInformation.length == 0){ + this.sortInformation.push({ + index:0, + direction:0 + }); + } else if (this.sortInformation.length > this.maxSortable){ + this.sortInformation.length = this.maxSortable; + } + }, + parseData: function(/* HTMLTableBody */body){ + // summary + // Parse HTML data into native JSON structure for the store. + if(body.rows.length == 0 && this.columns.length == 0){ + return; // there's no data, ignore me. + } + + // create a data constructor based on what we've got for the fields. + var self=this; + this["__selected__"] = []; + var arr = this.store.getFromHtml(this.columns, body, function(obj, row){ + if(typeof(obj[self.valueField])=="undefined" || obj[self.valueField]==null){ + obj[self.valueField] = dojo.html.getAttribute(row, "value"); + } + if(dojo.html.getAttribute(row, "selected")=="true"){ + self["__selected__"].push(obj); + } + }); + + this.store.setData(arr, true); + this.render(); + + for(var i=0; i<this["__selected__"].length; i++){ + this.select(this["__selected__"][i]); + } + this.renderSelections(); + + delete this["__selected__"]; + + // say that we are already initialized so that we don't kill anything + this.isInitialized=true; + }, + + // standard events + onSelect: function(/* HTMLEvent */e){ + // summary + // Handles the onclick event of any element. + var row = dojo.html.getParentByType(e.target,"tr"); + if(dojo.html.hasAttribute(row,"emptyRow")){ + return; + } + var body = dojo.html.getParentByType(row,"tbody"); + if(this.multiple){ + if(e.shiftKey){ + var startRow; + var rows=body.rows; + for(var i=0;i<rows.length;i++){ + if(rows[i]==row){ + break; + } + if(this.isRowSelected(rows[i])){ + startRow=rows[i]; + } + } + if(!startRow){ + startRow = row; + for(; i<rows.length; i++){ + if(this.isRowSelected(rows[i])){ + row = rows[i]; + break; + } + } + } + this.resetSelections(); + if(startRow == row){ + this.toggleSelectionByRow(row); + } else { + var doSelect = false; + for(var i=0; i<rows.length; i++){ + if(rows[i] == startRow){ + doSelect=true; + } + if(doSelect){ + this.selectByRow(rows[i]); + } + if(rows[i] == row){ + doSelect = false; + } + } + } + } else { + this.toggleSelectionByRow(row); + } + } else { + this.resetSelections(); + this.toggleSelectionByRow(row); + } + this.renderSelections(); + }, + onSort: function(/* HTMLEvent */e){ + // summary + // Sort the table based on the column selected. + var oldIndex=this.sortIndex; + var oldDirection=this.sortDirection; + + var source=e.target; + var row=dojo.html.getParentByType(source,"tr"); + var cellTag="td"; + if(row.getElementsByTagName(cellTag).length==0){ + cellTag="th"; + } + + var headers=row.getElementsByTagName(cellTag); + var header=dojo.html.getParentByType(source,cellTag); + + for(var i=0; i<headers.length; i++){ + dojo.html.setClass(headers[i], this.headerClass); + if(headers[i]==header){ + if(this.sortInformation[0].index != i){ + this.sortInformation.unshift({ + index:i, + direction:0 + }); + } else { + this.sortInformation[0] = { + index:i, + direction:(~this.sortInformation[0].direction)&1 + }; + } + } + } + + this.sortInformation.length = Math.min(this.sortInformation.length, this.maxSortable); + for(var i=0; i<this.sortInformation.length; i++){ + var idx=this.sortInformation[i].index; + var dir=(~this.sortInformation[i].direction)&1; + dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass); + } + this.render(); + }, + onFilter: function(){ + // summary + // show or hide rows based on the parameters of the passed filter. + }, + + // Filtering methods + _defaultFilter: function(/* Object */obj){ + // summary + // Always return true as the result of the default filter. + return true; + }, + setFilter: function(/* string */field, /* function */fn){ + // summary + // set a filtering function on the passed field. + for(var i=0; i<this.columns.length; i++){ + if(this.columns[i].getField() == field){ + this.columns[i].filterFunction=fn; + break; + } + } + this.applyFilters(); + }, + setFilterByIndex: function(/* number */idx, /* function */fn){ + // summary + // set a filtering function on the passed column index. + this.columns[idx].filterFunction=fn; + this.applyFilters(); + }, + clearFilter: function(/* string */field){ + // summary + // clear a filtering function on the passed field. + for(var i=0; i<this.columns.length; i++){ + if(this.columns[i].getField() == field){ + this.columns[i].filterFunction=this._defaultFilter; + break; + } + } + this.applyFilters(); + }, + clearFilterByIndex: function(/* number */idx){ + // summary + // clear a filtering function on the passed column index. + this.columns[idx].filterFunction=this._defaultFilter; + this.applyFilters(); + }, + clearFilters: function(){ + // summary + // clears all filters. + for(var i=0; i<this.columns.length; i++){ + this.columns[i].filterFunction=this._defaultFilter; + } + // we'll do the clear manually, it will be faster. + var rows=this.domNode.tBodies[0].rows; + for(var i=0; i<rows.length; i++){ + rows[i].style.display=""; + if(this.alternateRows){ + dojo.html[((i % 2 == 1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass); + } + } + this.onFilter(); + }, + applyFilters: function(){ + // summary + // apply all filters to the table. + var alt=0; + var rows=this.domNode.tBodies[0].rows; + for(var i=0; i<rows.length; i++){ + var b=true; + var row=rows[i]; + for(var j=0; j<this.columns.length; j++){ + var value = this.store.getField(this.getDataByRow(row), this.columns[j].getField()); + if(this.columns[j].getType() == Date && value != null && !value.getYear){ + value = new Date(value); + } + if(!this.columns[j].filterFunction(value)){ + b=false; + break; + } + } + row.style.display=(b?"":"none"); + if(b && this.alternateRows){ + dojo.html[((alt++ % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass); + } + } + this.onFilter(); + }, + + // sorting functionality + createSorter: function(/* array */info){ + // summary + // creates a custom function to be used for sorting. + var self=this; + var sortFunctions=[]; // our function stack. + + function createSortFunction(fieldIndex, dir){ + var meta=self.columns[fieldIndex]; + var field=meta.getField(); + return function(rowA, rowB){ + if(dojo.html.hasAttribute(rowA,"emptyRow")){ return 1; } + if(dojo.html.hasAttribute(rowB,"emptyRow")){ return -1; } + + // TODO: check for markup and compare by rendered text. + var a = self.store.getField(self.getDataByRow(rowA), field); + var b = self.store.getField(self.getDataByRow(rowB), field); + var ret = 0; + if(a > b) ret = 1; + if(a < b) ret = -1; + return dir * ret; + } + } + + var current=0; + var max = Math.min(info.length, this.maxSortable, this.columns.length); + while(current < max){ + var direction = (info[current].direction == 0) ? 1 : -1; + sortFunctions.push( + createSortFunction(info[current].index, direction) + ); + current++; + } + + return function(rowA, rowB){ + var idx=0; + while(idx < sortFunctions.length){ + var ret = sortFunctions[idx++](rowA, rowB); + if(ret != 0) return ret; + } + // if we got here then we must be equal. + return 0; + }; // function + }, + + // rendering + createRow: function(/* object */obj){ + // summary + // Create an HTML row based on the passed object + var row=document.createElement("tr"); + dojo.html.disableSelection(row); + if(obj.key != null){ + row.setAttribute("value", obj.key); + } + for(var j=0; j<this.columns.length; j++){ + var cell=document.createElement("td"); + cell.setAttribute("align", this.columns[j].align); + cell.setAttribute("valign", this.columns[j].valign); + dojo.html.disableSelection(cell); + var val = this.store.getField(obj.src, this.columns[j].getField()); + if(typeof(val)=="undefined"){ + val=""; + } + this.fillCell(cell, this.columns[j], val); + row.appendChild(cell); + } + return row; // HTMLTableRow + }, + fillCell: function(/* HTMLTableCell */cell, /* object */meta, /* object */val){ + // summary + // Fill the passed cell with value, based on the passed meta object. + if(meta.sortType=="__markup__"){ + cell.innerHTML=val; + } else { + if(meta.getType()==Date) { + val=new Date(val); + if(!isNaN(val)){ + var format = this.defaultDateFormat; + if(meta.format){ + format = meta.format; + } + cell.innerHTML = dojo.date.strftime(val, format); + } else { + cell.innerHTML = val; + } + } else if ("Number number int Integer float Float".indexOf(meta.getType())>-1){ + // TODO: number formatting + if(val.length == 0){ + val="0"; + } + var n = parseFloat(val, 10) + ""; + // TODO: numeric formatting + rounding :) + if(n.indexOf(".")>-1){ + n = dojo.math.round(parseFloat(val,10),2); + } + cell.innerHTML = n; + }else{ + cell.innerHTML = val; + } + } + }, + prefill: function(){ + // summary + // if there's no data in the table, then prefill it with this.minRows. + this.isInitialized = false; + var body = this.domNode.tBodies[0]; + while (body.childNodes.length > 0){ + body.removeChild(body.childNodes[0]); + } + + if(this.minRows>0){ + for(var i=0; i < this.minRows; i++){ + var row = document.createElement("tr"); + if(this.alternateRows){ + dojo.html[((i % 2 == 1)?"addClass":"removeClass")](row, this.rowAlternateClass); + } + row.setAttribute("emptyRow","true"); + for(var j=0; j<this.columns.length; j++){ + var cell = document.createElement("td"); + cell.innerHTML = " "; + row.appendChild(cell); + } + body.appendChild(row); + } + } + }, + init: function(){ + // summary + // initializes the table of data + this.isInitialized=false; + + // if there is no thead, create it now. + var head=this.domNode.getElementsByTagName("thead")[0]; + if(head.getElementsByTagName("tr").length == 0){ + // render the column code. + var row=document.createElement("tr"); + for(var i=0; i<this.columns.length; i++){ + var cell=document.createElement("td"); + cell.setAttribute("align", this.columns[i].align); + cell.setAttribute("valign", this.columns[i].valign); + dojo.html.disableSelection(cell); + cell.innerHTML=this.columns[i].label; + row.appendChild(cell); + + // attach the events. + if(!this.columns[i].noSort){ + dojo.event.connect(cell, "onclick", this, "onSort"); + } + } + dojo.html.prependChild(row, head); + } + + if(this.store.get().length == 0){ + return false; + } + + var idx=this.domNode.tBodies[0].rows.length; + if(!idx || idx==0 || this.domNode.tBodies[0].rows[0].getAttribute("emptyRow")=="true"){ + idx = 0; + var body = this.domNode.tBodies[0]; + while(body.childNodes.length>0){ + body.removeChild(body.childNodes[0]); + } + + var data = this.store.get(); + for(var i=0; i<data.length; i++){ + var row = this.createRow(data[i]); + body.appendChild(row); + idx++; + } + } + + // add empty rows + if(this.minRows > 0 && idx < this.minRows){ + idx = this.minRows - idx; + for(var i=0; i<idx; i++){ + row=document.createElement("tr"); + row.setAttribute("emptyRow","true"); + for(var j=0; j<this.columns.length; j++){ + cell=document.createElement("td"); + cell.innerHTML=" "; + row.appendChild(cell); + } + body.appendChild(row); + } + } + + // last but not least, show any columns that have sorting already on them. + var row=this.domNode.getElementsByTagName("thead")[0].rows[0]; + var cellTag="td"; + if(row.getElementsByTagName(cellTag).length==0) cellTag="th"; + var headers=row.getElementsByTagName(cellTag); + for(var i=0; i<headers.length; i++){ + dojo.html.setClass(headers[i], this.headerClass); + } + for(var i=0; i<this.sortInformation.length; i++){ + var idx=this.sortInformation[i].index; + var dir=(~this.sortInformation[i].direction)&1; + dojo.html.setClass(headers[idx], dir==0?this.headerDownClass:this.headerUpClass); + } + + this.isInitialized=true; + return this.isInitialized; + }, + render: function(){ + // summary + // Renders the actual table data. + + /* The method that should be called once underlying changes + * are made, including sorting, filtering, data changes. + * Rendering the selections themselves are a different method, + * which render() will call as the last step. + ****************************************************************/ + if(!this.isInitialized){ + var b = this.init(); + if(!b){ + this.prefill(); + return; + } + } + + // do the sort + var rows=[]; + var body=this.domNode.tBodies[0]; + var emptyRowIdx=-1; + for(var i=0; i<body.rows.length; i++){ + rows.push(body.rows[i]); + } + + // build the sorting function, and do the sorting. + var sortFunction = this.createSorter(this.sortInformation); + if(sortFunction){ + rows.sort(sortFunction); + } + + // append the rows without killing them, this should help with the HTML problems. + for(var i=0; i<rows.length; i++){ + if(this.alternateRows){ + dojo.html[((i%2==1)?"addClass":"removeClass")](rows[i], this.rowAlternateClass); + } + dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass); + body.appendChild(rows[i]); + } + }, + renderSelections: function(){ + // summary + // Render all selected objects using CSS. + var body=this.domNode.tBodies[0]; + for(var i=0; i<body.rows.length; i++){ + dojo.html[(this.isRowSelected(body.rows[i])?"addClass":"removeClass")](body.rows[i], this.rowSelectedClass); + } + }, + + // widget lifetime handlers + initialize: function(){ + // summary + // Initializes the widget. + var self=this; + // connect up binding listeners here. + dojo.event.connect(this.store, "onSetData", function(){ + self.store.forEach(function(element){ + element.isSelected = false; + }); + self.isInitialized=false; + var body = self.domNode.tBodies[0]; + if(body){ + while(body.childNodes.length>0){ + body.removeChild(body.childNodes[0]); + } + } + self.render(); + }); + dojo.event.connect(this.store, "onClearData", function(){ + self.isInitialized = false; + self.render(); + }); + dojo.event.connect(this.store, "onAddData", function(addedObject){ + var row=self.createRow(addedObject); + self.domNode.tBodies[0].appendChild(row); + self.render(); + }); + dojo.event.connect(this.store, "onAddDataRange", function(arr){ + for(var i=0; i<arr.length; i++){ + arr[i].isSelected=false; + var row=self.createRow(arr[i]); + self.domNode.tBodies[0].appendChild(row); + }; + self.render(); + }); + dojo.event.connect(this.store, "onRemoveData", function(removedObject){ + var rows = self.domNode.tBodies[0].rows; + for(var i=0; i<rows.length; i++){ + if(self.getDataByRow(rows[i]) == removedObject.src){ + rows[i].parentNode.removeChild(rows[i]); + break; + } + } + self.render(); + }); + dojo.event.connect(this.store, "onUpdateField", function(obj, fieldPath, val){ + var row = self.getRow(obj); + var idx = self.getColumnIndex(fieldPath); + if(row && row.cells[idx] && self.columns[idx]){ + self.fillCell(row.cells[idx], self.columns[idx], val); + } + }); + }, + postCreate: function(){ + // summary + // finish widget initialization. + this.store.keyField = this.valueField; + + if(this.domNode){ + // start by making sure domNode is a table element; + if(this.domNode.nodeName.toLowerCase() != "table"){ + } + + // see if there is columns set up already + if(this.domNode.getElementsByTagName("thead")[0]){ + var head=this.domNode.getElementsByTagName("thead")[0]; + if(this.headClass.length > 0){ + head.className = this.headClass; + } + dojo.html.disableSelection(this.domNode); + this.parseMetadata(head); + + var header="td"; + if(head.getElementsByTagName(header).length==0){ + header="th"; + } + var headers = head.getElementsByTagName(header); + for(var i=0; i<headers.length; i++){ + if(!this.columns[i].noSort){ + dojo.event.connect(headers[i], "onclick", this, "onSort"); + } + } + } else { + this.domNode.appendChild(document.createElement("thead")); + } + + // if the table doesn't have a tbody already, add one and grab a reference to it + if (this.domNode.tBodies.length < 1) { + var body = document.createElement("tbody"); + this.domNode.appendChild(body); + } else { + var body = this.domNode.tBodies[0]; + } + + if (this.tbodyClass.length > 0){ + body.className = this.tbodyClass; + } + dojo.event.connect(body, "onclick", this, "onSelect"); + this.parseData(body); + } + } +}); Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js ------------------------------------------------------------------------------ svn:eol-style = native Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js ------------------------------------------------------------------------------ svn:keywords = "Date Rev Author URL Id" Propchange: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FilteringTable.js ------------------------------------------------------------------------------ svn:mime-type = text/plain Added: ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FisheyeList.js URL: http://svn.apache.org/viewvc/ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FisheyeList.js?view=auto&rev=509273 ============================================================================== --- ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FisheyeList.js (added) +++ ofbiz/trunk/framework/images/webapp/images/dojo/src/widget/FisheyeList.js Mon Feb 19 09:56:06 2007 @@ -0,0 +1,745 @@ +/* + Copyright (c) 2004-2006, 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.FisheyeList"); + +// +// TODO +// fix SVG support, and turn it on only if the browser supports it +// fix really long labels in vertical mode +// + +dojo.require("dojo.widget.*"); +dojo.require("dojo.widget.HtmlWidget"); +dojo.require("dojo.html.style"); +dojo.require("dojo.html.selection"); +dojo.require("dojo.html.util"); +dojo.require("dojo.event.*"); + + +dojo.widget.defineWidget( + "dojo.widget.FisheyeList", + dojo.widget.HtmlWidget, +function(){ + /* + * summary + * Menu similar to the fish eye menu on the Mac OS + * usage + * <div dojoType="FisheyeList" + * itemWidth="40" itemHeight="40" + * itemMaxWidth="150" itemMaxHeight="150" + * orientation="horizontal" + * effectUnits="2" + * itemPadding="10" + * attachEdge="center" + * labelEdge="bottom"> + * + * <div dojoType="FisheyeListItem" + * id="item1" + * onclick="alert('click on' + this.caption + '(from widget id ' + this.widgetId + ')!');" + * caption="Item 1" + * iconsrc="images/fisheye_1.png"> + * </div> + * ... + * </div> + */ + + this.pos = {x: -1, y: -1}; // current cursor position, relative to the grid + + this.EDGE = { + CENTER: 0, + LEFT: 1, + RIGHT: 2, + TOP: 3, + BOTTOM: 4 + }; + + // for conservative trigger mode, when triggered, timerScale is gradually increased from 0 to 1 + this.timerScale = 1.0; + +}, +{ + templateString: '<div class="dojoHtmlFisheyeListBar"></div>', + templateCssPath: dojo.uri.dojoUri("src/widget/templates/FisheyeList.css"), + + isContainer: true, + snarfChildDomOutput: true, + + // itemWidth: Integer + // width of menu item (in pixels) in it's dormant state (when the mouse is far away) + itemWidth: 40, + + // itemHeight: Integer + // height of menu item (in pixels) in it's dormant state (when the mouse is far away) + itemHeight: 40, + + // itemMaxWidth: Integer + // width of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it) + itemMaxWidth: 150, + + // itemMaxHeight: Integer + // height of menu item (in pixels) in it's fully enlarged state (when the mouse is directly over it) + itemMaxHeight: 150, + + + // orientation: String + // orientation of the menu, either "horizontal" or "vertical" + orientation: 'horizontal', + + // conservativeTrigger: Boolean + // if true, don't start enlarging menu items until mouse is over an image; + // if false, start enlarging menu items as the mouse moves near them. + conservativeTrigger: false, + + // effectUnits: Number + // controls how much reaction the menu makes, relative to the distance of the mouse from the menu + effectUnits: 2, + + // itemPadding: Integer + // padding (in pixels) betweeen each menu item + itemPadding: 10, + + // attachEdge: String + // controls the border that the menu items don't expand past; + // for example, if set to "top", then the menu items will drop downwards as they expand. + // values + // "center", "left", "right", "top", "bottom". + attachEdge: 'center', + + // labelEdge: String + // controls were the labels show up in relation to the menu item icons + // values + // "center", "left", "right", "top", "bottom". + labelEdge: 'bottom', + + // enableCrappySvgSupportBoolean + // for browsers that support svg, use the svg image (specified in FisheyeListIem.svgSrc) + // rather than the iconSrc image attribute + enableCrappySvgSupport: false, + + fillInTemplate: function() { + dojo.html.disableSelection(this.domNode); + + this.isHorizontal = (this.orientation == 'horizontal'); + this.selectedNode = -1; + + this.isOver = false; + this.hitX1 = -1; + this.hitY1 = -1; + this.hitX2 = -1; + this.hitY2 = -1; + + // + // only some edges make sense... + // + this.anchorEdge = this._toEdge(this.attachEdge, this.EDGE.CENTER); + this.labelEdge = this._toEdge(this.labelEdge, this.EDGE.TOP); + + if ( this.isHorizontal && (this.anchorEdge == this.EDGE.LEFT )){ this.anchorEdge = this.EDGE.CENTER; } + if ( this.isHorizontal && (this.anchorEdge == this.EDGE.RIGHT )){ this.anchorEdge = this.EDGE.CENTER; } + if (!this.isHorizontal && (this.anchorEdge == this.EDGE.TOP )){ this.anchorEdge = this.EDGE.CENTER; } + if (!this.isHorizontal && (this.anchorEdge == this.EDGE.BOTTOM)){ this.anchorEdge = this.EDGE.CENTER; } + + if (this.labelEdge == this.EDGE.CENTER){ this.labelEdge = this.EDGE.TOP; } + if ( this.isHorizontal && (this.labelEdge == this.EDGE.LEFT )){ this.labelEdge = this.EDGE.TOP; } + if ( this.isHorizontal && (this.labelEdge == this.EDGE.RIGHT )){ this.labelEdge = this.EDGE.TOP; } + if (!this.isHorizontal && (this.labelEdge == this.EDGE.TOP )){ this.labelEdge = this.EDGE.LEFT; } + if (!this.isHorizontal && (this.labelEdge == this.EDGE.BOTTOM)){ this.labelEdge = this.EDGE.LEFT; } + + // + // figure out the proximity size + // + this.proximityLeft = this.itemWidth * (this.effectUnits - 0.5); + this.proximityRight = this.itemWidth * (this.effectUnits - 0.5); + this.proximityTop = this.itemHeight * (this.effectUnits - 0.5); + this.proximityBottom = this.itemHeight * (this.effectUnits - 0.5); + + if (this.anchorEdge == this.EDGE.LEFT){ + this.proximityLeft = 0; + } + if (this.anchorEdge == this.EDGE.RIGHT){ + this.proximityRight = 0; + } + if (this.anchorEdge == this.EDGE.TOP){ + this.proximityTop = 0; + } + if (this.anchorEdge == this.EDGE.BOTTOM){ + this.proximityBottom = 0; + } + if (this.anchorEdge == this.EDGE.CENTER){ + this.proximityLeft /= 2; + this.proximityRight /= 2; + this.proximityTop /= 2; + this.proximityBottom /= 2; + } + }, + + postCreate: function() { + this._initializePositioning(); + + // + // in liberal trigger mode, activate menu whenever mouse is close + // + if( !this.conservativeTrigger ){ + dojo.event.connect(document.documentElement, "onmousemove", this, "_onMouseMove"); + } + + // Deactivate the menu if mouse is moved off screen (doesn't work for FF?) + dojo.event.connect(document.documentElement, "onmouseout", this, "_onBodyOut"); + dojo.event.connect(this, "addChild", this, "_initializePositioning"); + }, + + _initializePositioning: function(){ + this.itemCount = this.children.length; + + this.barWidth = (this.isHorizontal ? this.itemCount : 1) * this.itemWidth; + this.barHeight = (this.isHorizontal ? 1 : this.itemCount) * this.itemHeight; + + this.totalWidth = this.proximityLeft + this.proximityRight + this.barWidth; + this.totalHeight = this.proximityTop + this.proximityBottom + this.barHeight; + + // + // calculate effect ranges for each item + // + for (var i=0; i<this.children.length; i++){ + + this.childr |
Free forum by Nabble | Edit this page |