//>>built // wrapped by build app define("dojox/widget/RollingList", ["dijit","dojo","dojox","dojo/i18n!dijit/nls/common","dojo/require!dojo/window,dijit/layout/ContentPane,dijit/_Templated,dijit/_Contained,dijit/layout/_LayoutWidget,dijit/Menu,dijit/form/Button,dijit/focus,dijit/_base/focus,dojox/html/metrics,dojo/i18n"], function(dijit,dojo,dojox){ dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dojo.window"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit._Templated"); dojo.require("dijit._Contained"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dijit.form.Button"); dojo.require("dijit.focus"); // dijit.focus() dojo.require("dijit._base.focus"); // dijit.getFocus() dojo.require("dojox.html.metrics"); dojo.require("dojo.i18n"); dojo.requireLocalization("dijit", "common"); dojo.declare("dojox.widget._RollingListPane", [dijit.layout.ContentPane, dijit._Templated, dijit._Contained], { // summary: a core pane that can be attached to a RollingList. All panes // should extend this one // templateString: string // our template templateString: '
', // parentWidget: dojox.widget.RollingList // Our rolling list widget parentWidget: null, // parentPane: dojox.widget._RollingListPane // The pane that immediately precedes ours parentPane: null, // store: store // the store we must use store: null, // items: item[] // an array of (possibly not-yet-loaded) items to display in this. // If this array is null, then the query and query options are used to // get the top-level items to use. This array is also used to watch and // see if the pane needs to be reloaded (store notifications are handled) // by the pane items: null, // query: object // a query to pass to the datastore. This is only used if items are null query: null, // queryOptions: object // query options to be passed to the datastore queryOptions: null, // focusByNode: boolean // set to false if the subclass will handle its own node focusing _focusByNode: true, // minWidth: integer // the width (in px) for this pane minWidth: 0, _setContentAndScroll: function(/*String|DomNode|Nodelist*/cont, /*Boolean?*/isFakeContent){ // summary: sets the value of the content and scrolls it into view this._setContent(cont, isFakeContent); this.parentWidget.scrollIntoView(this); }, _updateNodeWidth: function(n, min){ // summary: updates the min width of the pane to be minPaneWidth n.style.width = ""; var nWidth = dojo.marginBox(n).w; if(nWidth < min){ dojo.marginBox(n, {w: min}); } }, _onMinWidthChange: function(v){ // Called when the min width of a pane has changed this._updateNodeWidth(this.domNode, v); }, _setMinWidthAttr: function(v){ if(v !== this.minWidth){ this.minWidth = v; this._onMinWidthChange(v); } }, startup: function(){ if(this._started){ return; } if(this.store && this.store.getFeatures()["dojo.data.api.Notification"]){ window.setTimeout(dojo.hitch(this, function(){ // Set connections after a slight timeout to avoid getting in the // condition where we are setting them while events are still // being fired this.connect(this.store, "onSet", "_onSetItem"); this.connect(this.store, "onNew", "_onNewItem"); this.connect(this.store, "onDelete", "_onDeleteItem"); }), 1); } this.connect(this.focusNode||this.domNode, "onkeypress", "_focusKey"); this.parentWidget._updateClass(this.domNode, "Pane"); this.inherited(arguments); this._onMinWidthChange(this.minWidth); }, _focusKey: function(/*Event*/e){ // summary: called when a keypress happens on the widget if(e.charOrCode == dojo.keys.BACKSPACE){ dojo.stopEvent(e); return; }else if(e.charOrCode == dojo.keys.LEFT_ARROW && this.parentPane){ this.parentPane.focus(); this.parentWidget.scrollIntoView(this.parentPane); }else if(e.charOrCode == dojo.keys.ENTER){ this.parentWidget._onExecute(); } }, focus: function(/*boolean*/force){ // summary: sets the focus to this current widget if(this.parentWidget._focusedPane != this){ this.parentWidget._focusedPane = this; this.parentWidget.scrollIntoView(this); if(this._focusByNode && (!this.parentWidget._savedFocus || force)){ try{(this.focusNode||this.domNode).focus();}catch(e){} } } }, _onShow: function(){ // summary: checks that the store is loaded if((this.store || this.items) && ((this.refreshOnShow && this.domNode) || (!this.isLoaded && this.domNode))){ this.refresh(); } }, _load: function(){ // summary: sets the "loading" message and then kicks off a query asyncronously this.isLoaded = false; if(this.items){ this._setContentAndScroll(this.onLoadStart(), true); window.setTimeout(dojo.hitch(this, "_doQuery"), 1); }else{ this._doQuery(); } }, _doLoadItems: function(/*item[]*/items, /*function*/callback){ // summary: loads the given items, and then calls the callback when they // are finished. var _waitCount = 0, store = this.store; dojo.forEach(items, function(item){ if(!store.isItemLoaded(item)){ _waitCount++; } }); if(_waitCount === 0){ callback(); }else{ var onItem = function(item){ _waitCount--; if((_waitCount) === 0){ callback(); } }; dojo.forEach(items, function(item){ if(!store.isItemLoaded(item)){ store.loadItem({item: item, onItem: onItem}); } }); } }, _doQuery: function(){ // summary: either runs the query or loads potentially not-yet-loaded items. if(!this.domNode){return;} var preload = this.parentWidget.preloadItems; preload = (preload === true || (this.items && this.items.length <= Number(preload))); if(this.items && preload){ this._doLoadItems(this.items, dojo.hitch(this, "onItems")); }else if(this.items){ this.onItems(); }else{ this._setContentAndScroll(this.onFetchStart(), true); this.store.fetch({query: this.query, onComplete: function(items){ this.items = items; this.onItems(); }, onError: function(e){ this._onError("Fetch", e); }, scope: this}); } }, _hasItem: function(/* item */ item){ // summary: returns whether or not the given item is handled by this // pane var items = this.items || []; for(var i = 0, myItem; (myItem = items[i]); i++){ if(this.parentWidget._itemsMatch(myItem, item)){ return true; } } return false; }, _onSetItem: function(/* item */ item, /* attribute-name-string */ attribute, /* object | array */ oldValue, /* object | array */ newValue){ // Summary: called when an item in the store has changed if(this._hasItem(item)){ this.refresh(); } }, _onNewItem: function(/* item */ newItem, /*object?*/ parentInfo){ // Summary: called when an item is added to the store var sel; if((!parentInfo && !this.parentPane) || (parentInfo && this.parentPane && this.parentPane._hasItem(parentInfo.item) && (sel = this.parentPane._getSelected()) && this.parentWidget._itemsMatch(sel.item, parentInfo.item))){ this.items.push(newItem); this.refresh(); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this.refresh(); } }, _onDeleteItem: function(/* item */ deletedItem){ // Summary: called when an item is removed from the store if(this._hasItem(deletedItem)){ this.items = dojo.filter(this.items, function(i){ return (i != deletedItem); }); this.refresh(); } }, onFetchStart: function(){ // summary: // called before a fetch starts return this.loadingMessage; }, onFetchError: function(/*Error*/ error){ // summary: // called when a fetch error occurs. return this.errorMessage; }, onLoadStart: function(){ // summary: // called before a load starts return this.loadingMessage; }, onLoadError: function(/*Error*/ error){ // summary: // called when a load error occurs. return this.errorMessage; }, onItems: function(){ // summary: // called after a fetch or load - at this point, this.items should be // set and loaded. Override this function to "do your stuff" if(!this.onLoadDeferred){ this.cancel(); this.onLoadDeferred = new dojo.Deferred(dojo.hitch(this, "cancel")); } this._onLoadHandler(); } }); dojo.declare("dojox.widget._RollingListGroupPane", [dojox.widget._RollingListPane], { // summary: a pane that will handle groups (treats them as menu items) // templateString: string // our template templateString: '
' + '
' + '
' + '
', // _menu: dijit.Menu // The menu that we will call addChild() on for adding items _menu: null, _setContent: function(/*String|DomNode|Nodelist*/cont){ if(!this._menu){ // Only set the content if we don't already have a menu this.inherited(arguments); } }, _onMinWidthChange: function(v){ // override and resize the menu instead if(!this._menu){ return; } var dWidth = dojo.marginBox(this.domNode).w; var mWidth = dojo.marginBox(this._menu.domNode).w; this._updateNodeWidth(this._menu.domNode, v - (dWidth - mWidth)); }, onItems: function(){ // summary: // called after a fetch or load var selectItem, hadChildren = false; if(this._menu){ selectItem = this._getSelected(); this._menu.destroyRecursive(); } this._menu = this._getMenu(); var child, selectMenuItem; if(this.items.length){ dojo.forEach(this.items, function(item){ child = this.parentWidget._getMenuItemForItem(item, this); if(child){ if(selectItem && this.parentWidget._itemsMatch(child.item, selectItem.item)){ selectMenuItem = child; } this._menu.addChild(child); } }, this); }else{ child = this.parentWidget._getMenuItemForItem(null, this); if(child){ this._menu.addChild(child); } } if(selectMenuItem){ this._setSelected(selectMenuItem); if((selectItem && !selectItem.children && selectMenuItem.children) || (selectItem && selectItem.children && !selectMenuItem.children)){ var itemPane = this.parentWidget._getPaneForItem(selectMenuItem.item, this, selectMenuItem.children); if(itemPane){ this.parentWidget.addChild(itemPane, this.getIndexInParent() + 1); }else{ this.parentWidget._removeAfter(this); this.parentWidget._onItemClick(null, this, selectMenuItem.item, selectMenuItem.children); } } }else if(selectItem){ this.parentWidget._removeAfter(this); } this.containerNode.innerHTML = ""; this.containerNode.appendChild(this._menu.domNode); this.parentWidget.scrollIntoView(this); this._checkScrollConnection(true); this.inherited(arguments); this._onMinWidthChange(this.minWidth); }, _checkScrollConnection: function(doLoad){ // summary: checks whether or not we need to connect to our onscroll // function var store = this.store if(this._scrollConn){ this.disconnect(this._scrollConn); } delete this._scrollConn; if(!dojo.every(this.items, function(i){return store.isItemLoaded(i);})){ if(doLoad){ this._loadVisibleItems(); } this._scrollConn = this.connect(this.domNode, "onscroll", "_onScrollPane"); } }, startup: function(){ this.inherited(arguments); this.parentWidget._updateClass(this.domNode, "GroupPane"); }, focus: function(/*boolean*/force){ // summary: sets the focus to this current widget if(this._menu){ if(this._pendingFocus){ this.disconnect(this._pendingFocus); } delete this._pendingFocus; // We focus the right widget - either the focusedChild, the // selected node, the first menu item, or the menu itself var focusWidget = this._menu.focusedChild; if(!focusWidget){ var focusNode = dojo.query(".dojoxRollingListItemSelected", this.domNode)[0]; if(focusNode){ focusWidget = dijit.byNode(focusNode); } } if(!focusWidget){ focusWidget = this._menu.getChildren()[0] || this._menu; } this._focusByNode = false; if(focusWidget.focusNode){ if(!this.parentWidget._savedFocus || force){ try{focusWidget.focusNode.focus();}catch(e){} } window.setTimeout(function(){ try{ dojo.window.scrollIntoView(focusWidget.focusNode); }catch(e){} }, 1); }else if(focusWidget.focus){ if(!this.parentWidget._savedFocus || force){ focusWidget.focus(); } }else{ this._focusByNode = true; } this.inherited(arguments); }else if(!this._pendingFocus){ this._pendingFocus = this.connect(this, "onItems", "focus"); } }, _getMenu: function(){ // summary: returns a widget to be used for the container widget. var self = this; var menu = new dijit.Menu({ parentMenu: this.parentPane ? this.parentPane._menu : null, onCancel: function(/*Boolean*/ closeAll){ if(self.parentPane){ self.parentPane.focus(true); } }, _moveToPopup: function(/*Event*/ evt){ if(this.focusedChild && !this.focusedChild.disabled){ this.focusedChild._onClick(evt); } } }, this.menuNode); this.connect(menu, "onItemClick", function(/*dijit.MenuItem*/ item, /*Event*/ evt){ if(item.disabled){ return; } evt.alreadySelected = dojo.hasClass(item.domNode, "dojoxRollingListItemSelected"); if(evt.alreadySelected && ((evt.type == "keypress" && evt.charOrCode != dojo.keys.ENTER) || (evt.type == "internal"))){ var p = this.parentWidget.getChildren()[this.getIndexInParent() + 1]; if(p){ p.focus(true); this.parentWidget.scrollIntoView(p); } }else{ this._setSelected(item, menu); this.parentWidget._onItemClick(evt, this, item.item, item.children); if(evt.type == "keypress" && evt.charOrCode == dojo.keys.ENTER){ this.parentWidget._onExecute(); } } }); if(!menu._started){ menu.startup(); } return menu; }, _onScrollPane: function(){ // summary: called when the pane has been scrolled - it sets a timeout // so that we don't try and load our visible items too often during // a scroll if(this._visibleLoadPending){ window.clearTimeout(this._visibleLoadPending); } this._visibleLoadPending = window.setTimeout(dojo.hitch(this, "_loadVisibleItems"), 500); }, _loadVisibleItems: function(){ // summary: loads the items that are currently visible in the pane delete this._visibleLoadPending var menu = this._menu; if(!menu){ return; } var children = menu.getChildren(); if(!children || !children.length){ return; } var gpbme = function(n, m, pb){ var s = dojo.getComputedStyle(n); var r = 0; if(m){ r += dojo._getMarginExtents(n, s).t; } if(pb){ r += dojo._getPadBorderExtents(n, s).t; } return r; }; var topOffset = gpbme(this.domNode, false, true) + gpbme(this.containerNode, true, true) + gpbme(menu.domNode, true, true) + gpbme(children[0].domNode, true, false); var h = dojo.contentBox(this.domNode).h; var minOffset = this.domNode.scrollTop - topOffset - (h/2); var maxOffset = minOffset + (3*h/2); var menuItemsToLoad = dojo.filter(children, function(c){ var cnt = c.domNode.offsetTop; var s = c.store; var i = c.item; return (cnt >= minOffset && cnt <= maxOffset && !s.isItemLoaded(i)); }) var itemsToLoad = dojo.map(menuItemsToLoad, function(c){ return c.item; }); var onItems = dojo.hitch(this, function(){ var selectItem = this._getSelected(); var selectMenuItem; dojo.forEach(itemsToLoad, function(item, idx){ var newItem = this.parentWidget._getMenuItemForItem(item, this); var oItem = menuItemsToLoad[idx]; var oIdx = oItem.getIndexInParent(); menu.removeChild(oItem); if(newItem){ if(selectItem && this.parentWidget._itemsMatch(newItem.item, selectItem.item)){ selectMenuItem = newItem; } menu.addChild(newItem, oIdx); if(menu.focusedChild == oItem){ menu.focusChild(newItem); } } oItem.destroy(); }, this); this._checkScrollConnection(false); }); this._doLoadItems(itemsToLoad, onItems); }, _getSelected: function(/*dijit.Menu?*/ menu){ // summary: // returns the selected menu item - or null if none are selected if(!menu){ menu = this._menu; } if(menu){ var children = this._menu.getChildren(); for(var i = 0, item; (item = children[i]); i++){ if(dojo.hasClass(item.domNode, "dojoxRollingListItemSelected")){ return item; } } } return null; }, _setSelected: function(/*dijit.MenuItem?*/ item, /*dijit.Menu?*/ menu){ // summary: // selectes the given item in the given menu (defaults to pane's menu) if(!menu){ menu = this._menu;} if(menu){ dojo.forEach(menu.getChildren(), function(i){ this.parentWidget._updateClass(i.domNode, "Item", {"Selected": (item && (i == item && !i.disabled))}); }, this); } } }); dojo.declare("dojox.widget.RollingList", [dijit._Widget, dijit._Templated, dijit._Container], { // summary: a rolling list that can be tied to a data store with children // templateString: String // The template to be used to construct the widget. templateString: dojo.cache("dojox.widget", "RollingList/RollingList.html", "
\n"), widgetsInTemplate: true, // className: string // an additional class (or space-separated classes) to add for our widget className: "", // store: store // the store we must use store: null, // query: object // a query to pass to the datastore. This is only used if items are null query: null, // queryOptions: object // query options to be passed to the datastore queryOptions: null, // childrenAttrs: String[] // one ore more attributes that holds children of a node childrenAttrs: ["children"], // parentAttr: string // the attribute to read for finding our parent item (if any) parentAttr: "", // value: item // The value that has been selected value: null, // executeOnDblClick: boolean // Set to true if you want to call onExecute when an item is // double-clicked, false if you want to call onExecute yourself. (mainly // used for popups to control how they want to be handled) executeOnDblClick: true, // preloadItems: boolean or int // if set to true, then onItems will be called only *after* all items have // been loaded (ie store.isLoaded will return true for all of them). If // false, then no preloading will occur. If set to an integer, preloading // will occur if the number of items is less than or equal to the value // of the integer. The onItems function will need to be aware of handling // items that may not be loaded preloadItems: false, // showButtons: boolean // if set to true, then buttons for "OK" and "Cancel" will be provided showButtons: false, // okButtonLabel: string // The string to use for the OK button - will use dijit's common "OK" string // if not set okButtonLabel: "", // cancelButtonLabel: string // The string to use for the Cancel button - will use dijit's common // "Cancel" string if not set cancelButtonLabel: "", // minPaneWidth: integer // the minimum pane width (in px) for all child panes. If they are narrower, // the width will be increased to this value. minPaneWidth: 0, postMixInProperties: function(){ // summary: Mix in our labels, if they are not set this.inherited(arguments); var loc = dojo.i18n.getLocalization("dijit", "common"); this.okButtonLabel = this.okButtonLabel || loc.buttonOk; this.cancelButtonLabel = this.cancelButtonLabel || loc.buttonCancel; }, _setShowButtonsAttr: function(doShow){ // summary: Sets the visibility of the buttons for the widget var needsLayout = false; if((this.showButtons != doShow && this._started) || (this.showButtons == doShow && !this.started)){ needsLayout = true; } dojo.toggleClass(this.domNode, "dojoxRollingListButtonsHidden", !doShow); this.showButtons = doShow; if(needsLayout){ if(this._started){ this.layout(); }else{ window.setTimeout(dojo.hitch(this, "layout"), 0); } } }, _itemsMatch: function(/*item*/ item1, /*item*/ item2){ // Summary: returns whether or not the two items match - checks ID if // they aren't the exact same object if(!item1 && !item2){ return true; }else if(!item1 || !item2){ return false; } return (item1 == item2 || (this._isIdentity && this.store.getIdentity(item1) == this.store.getIdentity(item2))); }, _removeAfter: function(/*Widget or int*/ idx){ // summary: removes all widgets after the given widget (or index) if(typeof idx != "number"){ idx = this.getIndexOfChild(idx); } if(idx >= 0){ dojo.forEach(this.getChildren(), function(c, i){ if(i > idx){ this.removeChild(c); c.destroyRecursive(); } }, this); } var children = this.getChildren(), child = children[children.length - 1]; var selItem = null; while(child && !selItem){ var val = child._getSelected ? child._getSelected() : null; if(val){ selItem = val.item; } child = child.parentPane; } if(!this._setInProgress){ this._setValue(selItem); } }, addChild: function(/*dijit._Widget*/ widget, /*int?*/ insertIndex){ // summary: adds a child to this rolling list - if passed an insertIndex, // then all children from that index on will be removed and destroyed // before adding the child. if(insertIndex > 0){ this._removeAfter(insertIndex - 1); } this.inherited(arguments); if(!widget._started){ widget.startup(); } widget.attr("minWidth", this.minPaneWidth); this.layout(); if(!this._savedFocus){ widget.focus(); } }, _setMinPaneWidthAttr: function(value){ // summary: // Sets the min pane width of all children if(value !== this.minPaneWidth){ this.minPaneWidth = value; dojo.forEach(this.getChildren(), function(c){ c.attr("minWidth", value); }); } }, _updateClass: function(/* Node */ node, /* String */ type, /* Object? */ options){ // summary: // sets the state of the given node with the given type and options // options: // an object with key-value-pairs. The values are boolean, if true, // the key is added as a class, if false, it is removed. if(!this._declaredClasses){ this._declaredClasses = ("dojoxRollingList " + this.className).split(" "); } dojo.forEach(this._declaredClasses, function(c){ if(c){ dojo.addClass(node, c + type); for(var k in options||{}){ dojo.toggleClass(node, c + type + k, options[k]); } dojo.toggleClass(node, c + type + "FocusSelected", (dojo.hasClass(node, c + type + "Focus") && dojo.hasClass(node, c + type + "Selected"))); dojo.toggleClass(node, c + type + "HoverSelected", (dojo.hasClass(node, c + type + "Hover") && dojo.hasClass(node, c + type + "Selected"))); } }); }, scrollIntoView: function(/*dijit._Widget*/ childWidget){ // summary: scrolls the given widget into view if(this._scrollingTimeout){ window.clearTimeout(this._scrollingTimeout); } delete this._scrollingTimeout; this._scrollingTimeout = window.setTimeout(dojo.hitch(this, function(){ if(childWidget.domNode){ dojo.window.scrollIntoView(childWidget.domNode); } delete this._scrollingTimeout; return; }), 1); }, resize: function(args){ dijit.layout._LayoutWidget.prototype.resize.call(this, args); }, layout: function(){ var children = this.getChildren(); if(this._contentBox){ var bn = this.buttonsNode; var height = this._contentBox.h - dojo.marginBox(bn).h - dojox.html.metrics.getScrollbar().h; dojo.forEach(children, function(c){ dojo.marginBox(c.domNode, {h: height}); }); } if(this._focusedPane){ var foc = this._focusedPane; delete this._focusedPane; if(!this._savedFocus){ foc.focus(); } }else if(children && children.length){ if(!this._savedFocus){ children[0].focus(); } } }, _onChange: function(/*item*/ value){ this.onChange(value); }, _setValue: function(/* item */ value){ // summary: internally sets the value and fires onchange delete this._setInProgress; if(!this._itemsMatch(this.value, value)){ this.value = value; this._onChange(value); } }, _setValueAttr: function(/* item */ value){ // summary: sets the value of this widget to the given store item if(this._itemsMatch(this.value, value) && !value){ return; } if(this._setInProgress && this._setInProgress === value){ return; } this._setInProgress = value; if(!value || !this.store.isItem(value)){ var pane = this.getChildren()[0]; pane._setSelected(null); this._onItemClick(null, pane, null, null); return; } var fetchParentItems = dojo.hitch(this, function(/*item*/ item, /*function*/callback){ // Summary: Fetchs the parent items for the given item var store = this.store, id; if(this.parentAttr && store.getFeatures()["dojo.data.api.Identity"] && ((id = this.store.getValue(item, this.parentAttr)) || id === "")){ // Fetch by parent attribute var cb = function(i){ if(store.getIdentity(i) == store.getIdentity(item)){ callback(null); }else{ callback([i]); } }; if(id === ""){ callback(null); }else if(typeof id == "string"){ store.fetchItemByIdentity({identity: id, onItem: cb}); }else if(store.isItem(id)){ cb(id); } }else{ // Fetch by finding children var numCheck = this.childrenAttrs.length; var parents = []; dojo.forEach(this.childrenAttrs, function(attr){ var q = {}; q[attr] = item; store.fetch({query: q, scope: this, onComplete: function(items){ if(this._setInProgress !== value){ return; } parents = parents.concat(items); numCheck--; if(numCheck === 0){ callback(parents); } } }); }, this); } }); var setFromChain = dojo.hitch(this, function(/*item[]*/itemChain, /*integer*/idx){ // Summary: Sets the value of the widget at the given index in the chain - onchanges are not // fired here var set = itemChain[idx]; var child = this.getChildren()[idx]; var conn; if(set && child){ var fx = dojo.hitch(this, function(){ if(conn){ this.disconnect(conn); } delete conn; if(this._setInProgress !== value){ return; } var selOpt = dojo.filter(child._menu.getChildren(), function(i){ return this._itemsMatch(i.item, set); }, this)[0]; if(selOpt){ idx++; child._menu.onItemClick(selOpt, {type: "internal", stopPropagation: function(){}, preventDefault: function(){}}); if(itemChain[idx]){ setFromChain(itemChain, idx); }else{ this._setValue(set); this.onItemClick(set, child, this.getChildItems(set)); } } }); if(!child.isLoaded){ conn = this.connect(child, "onLoad", fx); }else{ fx(); } }else if(idx === 0){ this.set("value", null); } }); var parentChain = []; var onParents = dojo.hitch(this, function(/*item[]*/ parents){ // Summary: recursively grabs the parents - only the first one is followed if(parents && parents.length){ parentChain.push(parents[0]); fetchParentItems(parents[0], onParents); }else{ if(!parents){ parentChain.pop(); } parentChain.reverse(); setFromChain(parentChain, 0); } }); // Only set the value in display if we are shown - if we are in a dropdown, // and are hidden, don't actually do the scrolling in the display (it can // mess up layouts) var ns = this.domNode.style; if(ns.display == "none" || ns.visibility == "hidden"){ this._setValue(value); }else if(!this._itemsMatch(value, this._visibleItem)){ onParents([value]); } }, _onItemClick: function(/* Event */ evt, /* dijit._Contained */ pane, /* item */ item, /* item[]? */ children){ // summary: internally called when a widget should pop up its child if(evt){ var itemPane = this._getPaneForItem(item, pane, children); var alreadySelected = (evt.type == "click" && evt.alreadySelected); if(alreadySelected && itemPane){ this._removeAfter(pane.getIndexInParent() + 1); var next = pane.getNextSibling(); if(next && next._setSelected){ next._setSelected(null); } this.scrollIntoView(next); }else if(itemPane){ this.addChild(itemPane, pane.getIndexInParent() + 1); if(this._savedFocus){ itemPane.focus(true); } }else{ this._removeAfter(pane); this.scrollIntoView(pane); } }else if(pane){ this._removeAfter(pane); this.scrollIntoView(pane); } if(!evt || evt.type != "internal"){ this._setValue(item); this.onItemClick(item, pane, children); } this._visibleItem = item; }, _getPaneForItem: function(/* item? */ item, /* dijit._Contained? */ parentPane, /* item[]? */ children){ // summary: gets the pane for the given item, and mixes in our needed parts // Returns the pane for the given item (null if the root pane) - after mixing in // its stuff. var ret = this.getPaneForItem(item, parentPane, children); ret.store = this.store; ret.parentWidget = this; ret.parentPane = parentPane||null; if(!item){ ret.query = this.query; ret.queryOptions = this.queryOptions; }else if(children){ ret.items = children; }else{ ret.items = [item]; } return ret; }, _getMenuItemForItem: function(/*item*/ item, /* dijit._Contained */ parentPane){ // summary: returns a widget for the given store item. The returned // item will be added to this widget's container widget. null will // be passed in for an "empty" item. var store = this.store; if(!item || !store || !store.isItem(item)){ var i = new dijit.MenuItem({ label: "---", disabled: true, iconClass: "dojoxEmpty", focus: function(){ // Do nothing on focus of this guy... } }); this._updateClass(i.domNode, "Item"); return i; }else{ var itemLoaded = store.isItemLoaded(item); var childItems = itemLoaded ? this.getChildItems(item) : undefined; var widgetItem; if(childItems){ widgetItem = this.getMenuItemForItem(item, parentPane, childItems); widgetItem.children = childItems; this._updateClass(widgetItem.domNode, "Item", {"Expanding": true}); if(!widgetItem._started){ var c = widgetItem.connect(widgetItem, "startup", function(){ this.disconnect(c); dojo.style(this.arrowWrapper, "display", ""); }); }else{ dojo.style(widgetItem.arrowWrapper, "display", ""); } }else{ widgetItem = this.getMenuItemForItem(item, parentPane, null); if(itemLoaded){ this._updateClass(widgetItem.domNode, "Item", {"Single": true}); }else{ this._updateClass(widgetItem.domNode, "Item", {"Unloaded": true}); widgetItem.attr("disabled", true); } } widgetItem.store = this.store; widgetItem.item = item; if(!widgetItem.label){ widgetItem.attr("label", this.store.getLabel(item).replace(/