a:115:{s:9:"#provides";s:24:"dojox.widget.RollingList";s:9:"#resource";s:21:"widget/RollingList.js";s:9:"#requires";a:7:{i:0;a:3:{i:0;s:6:"common";i:1;s:16:"dijit._Templated";i:2;s:5:"dijit";}i:1;a:3:{i:0;s:6:"common";i:1;s:24:"dijit.layout.ContentPane";i:2;s:5:"dijit";}i:2;a:3:{i:0;s:6:"common";i:1;s:26:"dijit.layout._LayoutWidget";i:2;s:5:"dijit";}i:3;a:3:{i:0;s:6:"common";i:1;s:10:"dijit.Menu";i:2;s:5:"dijit";}i:4;a:2:{i:0;s:6:"common";i:1;s:18:"dojox.html.metrics";}i:5;a:3:{i:0;s:6:"common";i:1;s:17:"dijit.form.Button";i:2;s:5:"dijit";}i:6;a:3:{i:0;s:6:"common";i:1;s:9:"dojo.i18n";i:2;s:4:"dojo";}}s:29:"dojox.widget._RollingListPane";a:5:{s:4:"type";s:8:"Function";s:6:"chains";a:2:{s:9:"prototype";a:1:{i:0;s:24:"dijit.layout.ContentPane";}s:4:"call";a:3:{i:0;s:24:"dijit.layout.ContentPane";i:1;s:16:"dijit._Templated";i:2;s:16:"dijit._Contained";}}s:6:"mixins";a:1:{s:9:"prototype";a:2:{i:0;s:26:"dijit._Templated.prototype";i:1;s:26:"dijit._Contained.prototype";}}s:7:"summary";s:84:"a core pane that can be attached to a RollingList. All panes should extend this one";s:9:"classlike";b:1;}s:44:"dojox.widget._RollingListPane.templateString";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:6:"string";s:7:"summary";s:12:"our template";}s:42:"dojox.widget._RollingListPane.parentWidget";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:24:"dojox.widget.RollingList";s:7:"summary";s:23:"Our rolling list widget";}s:40:"dojox.widget._RollingListPane.parentPane";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:29:"dojox.widget._RollingListPane";s:7:"summary";s:39:"The pane that immediately precedes ours";}s:35:"dojox.widget._RollingListPane.store";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:5:"store";s:7:"summary";s:21:"the store we must use";}s:35:"dojox.widget._RollingListPane.items";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:8:"instance";s:29:"dojox.widget._RollingListPane";s:4:"type";s:5:"item[";s:7:"summary";s:284:"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";}s:35:"dojox.widget._RollingListPane.query";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:6:"object";s:7:"summary";s:70:"a query to pass to the datastore. This is only used if items are null";}s:42:"dojox.widget._RollingListPane.queryOptions";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:6:"object";s:7:"summary";s:129:"query options to be passed to the datastore focusByNode: boolean set to false if the subclass will handle its own node focusing";}s:42:"dojox.widget._RollingListPane._focusByNode";a:3:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:38:"dojox.widget._RollingListPane.minWidth";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:8:"instance";s:29:"dojox.widget._RollingListPane";s:4:"type";s:7:"integer";s:7:"summary";s:31:"the width (in px) for this pane";}s:50:"dojox.widget._RollingListPane._setContentAndScroll";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"cont";a:1:{s:4:"type";s:23:"String|DomNode|Nodelist";}s:13:"isFakeContent";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:82:" this._setContent(cont, isFakeContent); this.parentWidget.scrollIntoView(this);";s:7:"summary";s:54:"sets the value of the content and scrolls it into view";s:7:"private";b:1;}s:46:"dojox.widget._RollingListPane._updateNodeWidth";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:1:"n";a:1:{s:4:"type";s:0:"";}s:3:"min";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:113:" n.style.width = ""; var nWidth = dojo.marginBox(n).w; if(nWidth < min){ dojo.marginBox(n, {w: min}); }";s:7:"summary";s:52:"updates the min width of the pane to be minPaneWidth";s:7:"private";b:1;}s:47:"dojox.widget._RollingListPane._onMinWidthChange";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:1:"v";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:2450:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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);";s:7:"private";b:1;s:7:"summary";s:0:"";}s:46:"dojox.widget._RollingListPane._setMinWidthAttr";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:1:"v";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:82:" if(v !== this.minWidth){ this.minWidth = v; this._onMinWidthChange(v); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:37:"dojox.widget._RollingListPane.startup";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:691:" 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);";s:7:"summary";s:0:"";}s:39:"dojox.widget._RollingListPane._focusKey";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:1:"e";a:1:{s:4:"type";s:5:"Event";}}s:6:"source";s:310:" 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(); }";s:7:"summary";s:44:"called when a keypress happens on the widget";s:7:"private";b:1;}s:35:"dojox.widget._RollingListPane.focus";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"force";a:1:{s:4:"type";s:7:"boolean";}}s:6:"source";s:269:" 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){} } }";s:7:"summary";s:37:"sets the focus to this current widget";}s:40:"dojox.widget._RollingListPane._loadCheck";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:324:" if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); }";s:7:"summary";s:31:"checks that the store is loaded";s:7:"private";b:1;}s:40:"dojox.widget._RollingListPane._loadQuery";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:186:" this.isLoaded = false; if(this.items){ this._setContentAndScroll(this.onLoadStart(), true); window.setTimeout(dojo.hitch(this, "_doQuery"), 1); }else{ this._doQuery(); }";s:7:"summary";s:77:"sets the "loading" message and then kicks off a query asyncronously";s:7:"private";b:1;}s:42:"dojox.widget._RollingListPane._doLoadItems";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:5:"items";a:1:{s:4:"type";s:6:"item[]";}s:8:"callback";a:1:{s:4:"type";s:8:"function";}}s:6:"source";s:434:" 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}); } }); } ";s:7:"summary";s:74:"loads the given items, and then calls the callback when they are finished.";s:7:"private";b:1;}s:38:"dojox.widget._RollingListPane._doQuery";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:552:" 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}); }";s:7:"summary";s:64:"either runs the query or loads potentially not-yet-loaded items.";s:7:"private";b:1;}s:38:"dojox.widget._RollingListPane._hasItem";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"item";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:177:" var items = this.items || []; for(var i = 0, myItem; (myItem = items[i]); i++){ if(this.parentWidget._itemsMatch(myItem, item)){ return true; } } return false;";s:7:"summary";s:61:"returns whether or not the given item is handled by this pane";s:7:"private";b:1;}s:40:"dojox.widget._RollingListPane._onSetItem";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:4:{s:4:"item";a:1:{s:4:"type";s:4:"item";}s:9:"attribute";a:1:{s:4:"type";s:21:"attribute-name-string";}s:8:"oldValue";a:1:{s:4:"type";s:14:"object | array";}s:8:"newValue";a:1:{s:4:"type";s:14:"object | array";}}s:6:"source";s:6622:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:40:"dojox.widget._RollingListPane._onNewItem";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:7:"newItem";a:1:{s:4:"type";s:4:"item";}s:10:"parentInfo";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"object";}}s:6:"source";s:7154:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:43:"dojox.widget._RollingListPane._onDeleteItem";a:6:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:11:"deletedItem";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:7426:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:42:"dojox.widget._RollingListPane.onFetchStart";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:29:" return this.loadingMessage;";s:7:"summary";s:28:"called before a fetch starts";}s:42:"dojox.widget._RollingListPane.onFetchError";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"error";a:1:{s:4:"type";s:5:"Error";}}s:6:"source";s:27:" return this.errorMessage;";s:7:"summary";s:33:"called when a fetch error occurs.";}s:41:"dojox.widget._RollingListPane.onLoadStart";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:29:" return this.loadingMessage;";s:7:"summary";s:27:"called before a load starts";}s:41:"dojox.widget._RollingListPane.onLoadError";a:5:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"error";a:1:{s:4:"type";s:5:"Error";}}s:6:"source";s:27:" return this.errorMessage;";s:7:"summary";s:32:"called when a load error occurs.";}s:37:"dojox.widget._RollingListPane.onItems";a:4:{s:9:"prototype";s:29:"dojox.widget._RollingListPane";s:4:"type";s:8:"Function";s:6:"source";s:26:" this._onLoadHandler(); ";s:7:"summary";s:135:"called after a fetch or load - at this point, this.items should be set and loaded. Override this function to "do your stuff"";}s:55:"dojox.widget._RollingListPane.parentWidget._focusedPane";a:3:{s:8:"instance";s:29:"dojox.widget._RollingListPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:38:"dojox.widget._RollingListPane.isLoaded";a:2:{s:8:"instance";s:29:"dojox.widget._RollingListPane";s:7:"summary";s:0:"";}s:34:"dojox.widget._RollingListGroupPane";a:4:{s:4:"type";s:8:"Function";s:6:"chains";a:2:{s:9:"prototype";a:1:{i:0;s:29:"dojox.widget._RollingListPane";}s:4:"call";a:1:{i:0;s:29:"dojox.widget._RollingListPane";}}s:7:"summary";s:58:"a pane that will handle groups (treats them as menu items)";s:9:"classlike";b:1;}s:49:"dojox.widget._RollingListGroupPane.templateString";a:3:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:6:"string";s:7:"summary";s:12:"our template";}s:40:"dojox.widget._RollingListGroupPane._menu";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:10:"dijit.Menu";s:7:"summary";s:57:"The menu that we will call addChild() on for adding items";s:7:"private";b:1;}s:45:"dojox.widget._RollingListGroupPane._loadCheck";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:175:" var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); }";s:7:"summary";s:31:"checks that the store is loaded";s:7:"private";b:1;}s:46:"dojox.widget._RollingListGroupPane._setContent";a:6:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"cont";a:1:{s:4:"type";s:23:"String|DomNode|Nodelist";}}s:6:"source";s:111:" if(!this._menu){ // Only set the content if we don't already have a menu this.inherited(arguments); }";s:7:"private";b:1;s:7:"summary";s:0:"";}s:52:"dojox.widget._RollingListGroupPane._onMinWidthChange";a:6:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:1:"v";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:9326:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); } }, 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" 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, _loadCheck: function(){ // summary: checks that the store is loaded var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _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));";s:7:"private";b:1;s:7:"summary";s:0:"";}s:42:"dojox.widget._RollingListGroupPane.onItems";a:4:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:1505:" 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);";s:7:"summary";s:28:"called after a fetch or load";}s:57:"dojox.widget._RollingListGroupPane._checkScrollConnection";a:6:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:6:"doLoad";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:326:" 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"); } ";s:7:"summary";s:65:"checks whether or not we need to connect to our onscroll function";s:7:"private";b:1;}s:42:"dojox.widget._RollingListGroupPane.startup";a:4:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:89:" this.inherited(arguments); this.parentWidget._updateClass(this.domNode, "GroupPane");";s:7:"summary";s:0:"";}s:40:"dojox.widget._RollingListGroupPane.focus";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"force";a:1:{s:4:"type";s:7:"boolean";}}s:6:"source";s:1139:" 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{ dijit.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"); }";s:7:"summary";s:37:"sets the focus to this current widget";}s:43:"dojox.widget._RollingListGroupPane._getMenu";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:1188:" 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;";s:7:"summary";s:53:"returns a widget to be used for the container widget.";s:7:"private";b:1;}s:48:"dojox.widget._RollingListGroupPane._onScrollPane";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:177:" if(this._visibleLoadPending){ window.clearTimeout(this._visibleLoadPending); } this._visibleLoadPending = window.setTimeout(dojo.hitch(this, "_loadVisibleItems"), 500);";s:7:"summary";s:132:"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";s:7:"private";b:1;}s:46:"dojox.widget._RollingListGroupPane._layoutHack";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:288:" if(dojo.isFF == 2 && !this._layoutHackHandle){ var node=this.domNode; var old = node.style.opacity; node.style.opacity = "0.999"; this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ this._layoutHackHandle = null; node.style.opacity = old; }), 0); }";s:7:"summary";s:112:"work around table sizing bugs on FF2 by forcing redraw note - this function is taken from dijit.form._FormWidget";s:7:"private";b:1;}s:52:"dojox.widget._RollingListGroupPane._loadVisibleItems";a:5:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:1733:" 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._layoutHack(); }); this._doLoadItems(itemsToLoad, onItems);";s:7:"summary";s:54:"loads the items that are currently visible in the pane";s:7:"private";b:1;}s:47:"dojox.widget._RollingListGroupPane._getSelected";a:6:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"menu";a:2:{s:8:"optional";b:1;s:4:"type";s:10:"dijit.Menu";}}s:6:"source";s:258:" 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;";s:7:"summary";s:61:"returns the selected menu item - or null if none are selected";s:7:"private";b:1;}s:47:"dojox.widget._RollingListGroupPane._setSelected";a:6:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"item";a:2:{s:8:"optional";b:1;s:4:"type";s:14:"dijit.MenuItem";}s:4:"menu";a:2:{s:8:"optional";b:1;s:4:"type";s:10:"dijit.Menu";}}s:6:"source";s:217:" 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); }";s:7:"summary";s:67:"selectes the given item in the given menu (defaults to pane's menu)";s:7:"private";b:1;}s:42:"dojox.widget._RollingListGroupPane.destroy";a:4:{s:9:"prototype";s:34:"dojox.widget._RollingListGroupPane";s:4:"type";s:8:"Function";s:6:"source";s:103:" if(this._layoutHackHandle){ clearTimeout(this._layoutHackHandle); } this.inherited(arguments);";s:7:"summary";s:0:"";}s:58:"dojox.widget._RollingListGroupPane.containerNode.innerHTML";a:2:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"summary";s:0:"";}s:46:"dojox.widget._RollingListGroupPane._scrollConn";a:3:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:47:"dojox.widget._RollingListGroupPane._focusByNode";a:3:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:48:"dojox.widget._RollingListGroupPane._pendingFocus";a:3:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:54:"dojox.widget._RollingListGroupPane._visibleLoadPending";a:3:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:52:"dojox.widget._RollingListGroupPane._layoutHackHandle";a:3:{s:8:"instance";s:34:"dojox.widget._RollingListGroupPane";s:7:"private";b:1;s:7:"summary";s:0:"";}s:24:"dojox.widget.RollingList";a:5:{s:4:"type";s:8:"Function";s:6:"chains";a:2:{s:9:"prototype";a:1:{i:0;s:13:"dijit._Widget";}s:4:"call";a:3:{i:0;s:13:"dijit._Widget";i:1;s:16:"dijit._Templated";i:2;s:16:"dijit._Container";}}s:6:"mixins";a:1:{s:9:"prototype";a:2:{i:0;s:26:"dijit._Templated.prototype";i:1;s:26:"dijit._Container.prototype";}}s:7:"summary";s:61:"a rolling list that can be tied to a data store with children";s:9:"classlike";b:1;}s:37:"dojox.widget.RollingList.templatePath";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"string";s:7:"summary";s:19:"our template to use";}s:42:"dojox.widget.RollingList.widgetsInTemplate";a:2:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:7:"summary";s:0:"";}s:34:"dojox.widget.RollingList.className";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"string";s:7:"summary";s:70:"an additional class (or space-separated classes) to add for our widget";}s:30:"dojox.widget.RollingList.store";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:5:"store";s:7:"summary";s:21:"the store we must use";}s:30:"dojox.widget.RollingList.query";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"object";s:7:"summary";s:70:"a query to pass to the datastore. This is only used if items are null";}s:37:"dojox.widget.RollingList.queryOptions";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"object";s:7:"summary";s:43:"query options to be passed to the datastore";}s:38:"dojox.widget.RollingList.childrenAttrs";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:7:"String[";s:7:"summary";s:53:"one ore more attributes that holds children of a node";}s:35:"dojox.widget.RollingList.parentAttr";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"string";s:7:"summary";s:58:"the attribute to read for finding our parent item (if any)";}s:30:"dojox.widget.RollingList.value";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:4:"item";s:7:"summary";s:32:"The value that has been selected";}s:42:"dojox.widget.RollingList.executeOnDblClick";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:7:"boolean";s:7:"summary";s:183:"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)";}s:37:"dojox.widget.RollingList.preloadItems";a:3:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:7:"boolean";s:7:"summary";s:390:"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";}s:36:"dojox.widget.RollingList.showButtons";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:7:"boolean";s:7:"summary";s:87:"if set to true, then buttons for "OK" and "Cancel" will be provided";}s:38:"dojox.widget.RollingList.okButtonLabel";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"string";s:7:"summary";s:94:"The string to use for the OK button - will use dijit's common "OK" string if not set";}s:42:"dojox.widget.RollingList.cancelButtonLabel";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:6:"string";s:7:"summary";s:102:"The string to use for the Cancel button - will use dijit's common "Cancel" string if not set";}s:37:"dojox.widget.RollingList.minPaneWidth";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:8:"instance";s:24:"dojox.widget.RollingList";s:4:"type";s:7:"integer";s:7:"summary";s:117:"the minimum pane width (in px) for all child panes. If they are narrower, the width will be increased to this value.";}s:44:"dojox.widget.RollingList.postMixInProperties";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:6:"source";s:216:" this.inherited(arguments); var loc = dojo.i18n.getLocalization("dijit", "common"); this.okButtonLabel = this.okButtonLabel || loc.buttonOk; this.cancelButtonLabel = this.cancelButtonLabel || loc.buttonCancel;";s:7:"summary";s:38:"Mix in our labels, if they are not set";}s:44:"dojox.widget.RollingList._setShowButtonsAttr";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:6:"doShow";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:396:" 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); } }";s:7:"summary";s:49:"Sets the visibility of the buttons for the widget";s:7:"private";b:1;}s:36:"dojox.widget.RollingList._itemsMatch";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:5:"item1";a:1:{s:4:"type";s:4:"item";}s:5:"item2";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:21149:"dojo.provide("dojox.widget.RollingList"); dojo.experimental("dojox.widget.RollingList"); dojo.require("dijit._Templated"); dojo.require("dijit.layout.ContentPane"); dojo.require("dijit.layout._LayoutWidget"); dojo.require("dijit.Menu"); dojo.require("dojox.html.metrics"); dojo.require("dijit.form.Button"); dojo.require("dojo.i18n"); dojo.requireLocalization("dojox.widget", "RollingList"); 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); } }, 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" 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, _loadCheck: function(){ // summary: checks that the store is loaded var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _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{ dijit.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); }, _layoutHack: function(){ // summary: work around table sizing bugs on FF2 by forcing redraw // note - this function is taken from dijit.form._FormWidget if(dojo.isFF == 2 && !this._layoutHackHandle){ var node=this.domNode; var old = node.style.opacity; node.style.opacity = "0.999"; this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ this._layoutHackHandle = null; node.style.opacity = old; }), 0); } }, _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._layoutHack(); }); 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); } }, destroy: function(){ if(this._layoutHackHandle){ clearTimeout(this._layoutHackHandle); } this.inherited(arguments); } }); 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 // templatePath: string // our template to use templatePath: dojo.moduleUrl("dojox.widget", "RollingList/RollingList.html"), 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)));";s:7:"private";b:1;s:7:"summary";s:0:"";}s:37:"dojox.widget.RollingList._removeAfter";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:3:"idx";a:1:{s:4:"type";s:13:"Widget or int";}}s:6:"source";s:553:" 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); }";s:7:"summary";s:53:"removes all widgets after the given widget (or index)";s:7:"private";b:1;}s:33:"dojox.widget.RollingList.addChild";a:5:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:6:"widget";a:1:{s:4:"type";s:6:"Widget";}s:11:"insertIndex";a:2:{s:8:"optional";b:1;s:4:"type";s:3:"int";}}s:6:"source";s:254:" 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(); }";s:7:"summary";s:153:"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.";}s:45:"dojox.widget.RollingList._setMinPaneWidthAttr";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"value";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:155:" if(value !== this.minPaneWidth){ this.minPaneWidth = value; dojo.forEach(this.getChildren(), function(c){ c.attr("minWidth", value); }); }";s:7:"summary";s:39:"Sets the min pane width of all children";s:7:"private";b:1;}s:37:"dojox.widget.RollingList._updateClass";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:4:"node";a:1:{s:4:"type";s:4:"Node";}s:4:"type";a:1:{s:4:"type";s:6:"String";}s:7:"options";a:3:{s:8:"optional";b:1;s:4:"type";s:6:"Object";s:7:"summary";s:119:"an object with key-value-pairs. The values are boolean, if true, the key is added as a class, if false, it is removed.";}}s:6:"source";s:612:" 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"))); } });";s:7:"summary";s:64:"sets the state of the given node with the given type and options";s:7:"private";b:1;}s:39:"dojox.widget.RollingList.scrollIntoView";a:5:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:11:"childWidget";a:1:{s:4:"type";s:6:"Widget";}}s:6:"source";s:324:" if(this._scrollingTimeout){ window.clearTimeout(this._scrollingTimeout); } delete this._scrollingTimeout; this._scrollingTimeout = window.setTimeout(dojo.hitch(this, function(){ if(childWidget.domNode){ dijit.scrollIntoView(childWidget.domNode); } delete this._scrollingTimeout; return; }), 1);";s:7:"summary";s:34:"scrolls the given widget into view";}s:31:"dojox.widget.RollingList.resize";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:4:"args";a:1:{s:4:"type";s:0:"";}}s:6:"source";s:63:" dijit.layout._LayoutWidget.prototype.resize.call(this, args);";s:6:"chains";a:1:{s:4:"call";a:1:{i:0;s:43:"dijit.layout._LayoutWidget.prototype.resize";}}s:7:"summary";s:0:"";}s:31:"dojox.widget.RollingList.layout";a:4:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:6:"source";s:524:" 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(); } }";s:7:"summary";s:0:"";}s:34:"dojox.widget.RollingList._onChange";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"value";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:23:" this.onChange(value);";s:7:"private";b:1;s:7:"summary";s:0:"";}s:34:"dojox.widget.RollingList._setValue";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"value";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:126:" delete this._setInProgress; if(!this._itemsMatch(this.value, value)){ this.value = value; this._onChange(value); }";s:7:"summary";s:44:"internally sets the value and fires onchange";s:7:"private";b:1;}s:38:"dojox.widget.RollingList._setValueAttr";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:1:{s:5:"value";a:1:{s:4:"type";s:4:"item";}}s:6:"source";s:3476:" 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.attr("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]); }";s:7:"summary";s:53:"sets the value of this widget to the given store item";s:7:"private";b:1;}s:37:"dojox.widget.RollingList._onItemClick";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:4:{s:3:"evt";a:1:{s:4:"type";s:5:"Event";}s:4:"pane";a:1:{s:4:"type";s:16:"dijit._Contained";}s:4:"item";a:1:{s:4:"type";s:4:"item";}s:8:"children";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"item[]";}}s:6:"source";s:806:" 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;";s:7:"summary";s:55:"internally called when a widget should pop up its child";s:7:"private";b:1;}s:40:"dojox.widget.RollingList._getPaneForItem";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:3:{s:4:"item";a:2:{s:8:"optional";b:1;s:4:"type";s:4:"item";}s:10:"parentPane";a:2:{s:8:"optional";b:1;s:4:"type";s:16:"dijit._Contained";}s:8:"children";a:2:{s:8:"optional";b:1;s:4:"type";s:6:"item[]";}}s:6:"source";s:328:" 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;";s:7:"summary";s:152:"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.";s:7:"private";b:1;}s:44:"dojox.widget.RollingList._getMenuItemForItem";a:6:{s:9:"prototype";s:24:"dojox.widget.RollingList";s:4:"type";s:8:"Function";s:10:"parameters";a:2:{s:4:"item";a:1:{s:4:"type";s:4:"item";}s:10:"parentPane";a:1:{s:4:"type";s:16:"dijit._Contained";}}s:6:"source";s:2494:" var store = this.store; if(!item || !store || !store.isItem(item)){ var i = new dijit.MenuItem({ label: dojo.i18n.getLocalization("dojox.widget", "RollingList", this.lang).empty, 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(/
', // 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); } }, 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" 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, _loadCheck: function(){ // summary: checks that the store is loaded var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _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{ dijit.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); }, _layoutHack: function(){ // summary: work around table sizing bugs on FF2 by forcing redraw // note - this function is taken from dijit.form._FormWidget if(dojo.isFF == 2 && !this._layoutHackHandle){ var node=this.domNode; var old = node.style.opacity; node.style.opacity = "0.999"; this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ this._layoutHackHandle = null; node.style.opacity = old; }), 0); } }, _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._layoutHack(); }); 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); } }, destroy: function(){ if(this._layoutHackHandle){ clearTimeout(this._layoutHackHandle); } this.inherited(arguments); } }); 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 // templatePath: string // our template to use templatePath: dojo.moduleUrl("dojox.widget", "RollingList/RollingList.html"), 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(/*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(/* 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){ dijit.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.attr("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: dojo.i18n.getLocalization("dojox.widget", "RollingList", this.lang).empty, 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(/
', // 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); } }, 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" 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, _loadCheck: function(){ // summary: checks that the store is loaded var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _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{ dijit.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); }, _layoutHack: function(){ // summary: work around table sizing bugs on FF2 by forcing redraw // note - this function is taken from dijit.form._FormWidget if(dojo.isFF == 2 && !this._layoutHackHandle){ var node=this.domNode; var old = node.style.opacity; node.style.opacity = "0.999"; this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ this._layoutHackHandle = null; node.style.opacity = old; }), 0); } }, _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._layoutHack(); }); 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); } }, destroy: function(){ if(this._layoutHackHandle){ clearTimeout(this._layoutHackHandle); } this.inherited(arguments); } }); 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 // templatePath: string // our template to use templatePath: dojo.moduleUrl("dojox.widget", "RollingList/RollingList.html"), 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(/*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(/* 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){ dijit.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.attr("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: dojo.i18n.getLocalization("dojox.widget", "RollingList", this.lang).empty, 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(/
', // 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, 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){} } } }, _loadCheck: function(){ // summary: checks that the store is loaded if(!this._started){ var c = this.connect(this, "startup", function(){ this.disconnect(c); this._loadCheck(); }); } var displayState = this.domNode && this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _loadQuery: 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. 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._loadCheck(true); } }, _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._loadCheck(true); }else if(parentInfo && this.parentPane && this._hasItem(parentInfo.item)){ this._loadCheck(true); } }, _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._loadCheck(true); } }, 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" 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, _loadCheck: function(){ // summary: checks that the store is loaded var displayState = this._isShown(); if((this.store || this.items) && ((this.refreshOnShow && displayState) || (!this.isLoaded && displayState))){ this._loadQuery(); } }, _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{ dijit.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); }, _layoutHack: function(){ // summary: work around table sizing bugs on FF2 by forcing redraw // note - this function is taken from dijit.form._FormWidget if(dojo.isFF == 2 && !this._layoutHackHandle){ var node=this.domNode; var old = node.style.opacity; node.style.opacity = "0.999"; this._layoutHackHandle = setTimeout(dojo.hitch(this, function(){ this._layoutHackHandle = null; node.style.opacity = old; }), 0); } }, _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._layoutHack(); }); 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); } }, destroy: function(){ if(this._layoutHackHandle){ clearTimeout(this._layoutHackHandle); } this.inherited(arguments); } }); 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 // templatePath: string // our template to use templatePath: dojo.moduleUrl("dojox.widget", "RollingList/RollingList.html"), 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(/*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(/* 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){ dijit.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.attr("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: dojo.i18n.getLocalization("dojox.widget", "RollingList", this.lang).empty, 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(/