diff options
Diffstat (limited to '')
| -rw-r--r-- | js/dojo-1.6/dojox/grid/TreeGrid.xd.js | 970 |
1 files changed, 970 insertions, 0 deletions
diff --git a/js/dojo-1.6/dojox/grid/TreeGrid.xd.js b/js/dojo-1.6/dojox/grid/TreeGrid.xd.js new file mode 100644 index 0000000..c6169a5 --- /dev/null +++ b/js/dojo-1.6/dojox/grid/TreeGrid.xd.js @@ -0,0 +1,970 @@ +/*
+ Copyright (c) 2004-2011, The Dojo Foundation All Rights Reserved.
+ Available via Academic Free License >= 2.1 OR the modified BSD license.
+ see: http://dojotoolkit.org/license for details
+*/
+
+
+dojo._xdResourceLoaded(function(dojo, dijit, dojox){
+return {depends: [["provide", "dojox.grid.TreeGrid"],
+["require", "dojox.grid.DataGrid"],
+["require", "dojox.grid._TreeView"],
+["require", "dojox.grid.cells.tree"],
+["require", "dojox.grid.TreeSelection"]],
+defineResource: function(dojo, dijit, dojox){if(!dojo._hasResource["dojox.grid.TreeGrid"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
+dojo._hasResource["dojox.grid.TreeGrid"] = true;
+dojo.experimental("dojox.grid.TreeGrid");
+
+dojo.provide("dojox.grid.TreeGrid");
+
+dojo.require("dojox.grid.DataGrid");
+dojo.require("dojox.grid._TreeView");
+dojo.require("dojox.grid.cells.tree");
+dojo.require("dojox.grid.TreeSelection");
+
+dojo.declare("dojox.grid._TreeAggregator", null, {
+ cells: [],
+ grid: null,
+ childFields: [],
+
+ constructor: function(kwArgs){
+ this.cells = kwArgs.cells || [];
+ this.childFields = kwArgs.childFields || [];
+ this.grid = kwArgs.grid;
+ this.store = this.grid.store;
+ },
+ _cacheValue: function(cache, id, value){
+ cache[id] = value;
+ return value;
+ },
+ clearSubtotalCache: function(){
+ // summary:
+ // Clears the subtotal cache so that we are forced to recalc it
+ // (or reread it) again. This is needed, for example, when
+ // column order is changed.
+ if(this.store){
+ delete this.store._cachedAggregates;
+ }
+ },
+
+ cnt: function(cell, level, item){
+ // summary:
+ // calculates the count of the children of item at the given level
+ var total = 0;
+ var store = this.store;
+ var childFields = this.childFields;
+ if(childFields[level]){
+ var children = store.getValues(item, childFields[level]);
+ if (cell.index <= level + 1){
+ total = children.length;
+ }else{
+ dojo.forEach(children, function(c){
+ total += this.getForCell(cell, level + 1, c, "cnt");
+ }, this);
+ }
+ }else{
+ total = 1;
+ }
+ return total;
+ },
+ sum: function(cell, level, item){
+ // summary:
+ // calculates the sum of the children of item at the given level
+ var total = 0;
+ var store = this.store;
+ var childFields = this.childFields;
+ if(childFields[level]){
+ dojo.forEach(store.getValues(item, childFields[level]), function(c){
+ total += this.getForCell(cell, level + 1, c, "sum");
+ }, this);
+ }else{
+ total += store.getValue(item, cell.field);
+ }
+ return total;
+ },
+ value: function(cell, level, item){
+ // summary:
+ // Empty function so that we can set "aggregate='value'" to
+ // force loading from the data - and bypass calculating
+ },
+ getForCell: function(cell, level, item, type){
+ // summary:
+ // Gets the value of the given cell at the given level and type.
+ // type can be one of "sum", "cnt", or "value". If itemAggregates
+ // is set and can be used, it is used instead. Values are also
+ // cached to prevent calculating them too often.
+ var store = this.store;
+ if(!store || !item || !store.isItem(item)){ return ""; }
+ var storeCache = store._cachedAggregates = store._cachedAggregates || {};
+ var id = store.getIdentity(item);
+ var itemCache = storeCache[id] = storeCache[id] || [];
+ if(!cell.getOpenState){
+ cell = this.grid.getCell(cell.layoutIndex + level + 1);
+ }
+ var idx = cell.index;
+ var idxCache = itemCache[idx] = itemCache[idx] || {};
+ type = (type || (cell.parentCell ? cell.parentCell.aggregate : "sum"))||"sum";
+ var attr = cell.field;
+ if(attr == store.getLabelAttributes()[0]){
+ // If our attribute is one of the label attributes, we should
+ // use cnt instead (since it makes no sense to do a sum of labels)
+ type = "cnt";
+ }
+ var typeCache = idxCache[type] = idxCache[type] || [];
+
+ // See if we have it in our cache immediately for easy returning
+ if(typeCache[level] != undefined){
+ return typeCache[level];
+ }
+
+ // See if they have specified a valid field
+ var field = ((cell.parentCell && cell.parentCell.itemAggregates) ?
+ cell.parentCell.itemAggregates[cell.idxInParent] : "")||"";
+ if(field && store.hasAttribute(item, field)){
+ return this._cacheValue(typeCache, level, store.getValue(item, field));
+ }else if(field){
+ return this._cacheValue(typeCache, level, 0);
+ }
+
+ // Calculate it
+ return this._cacheValue(typeCache, level, this[type](cell, level, item));
+ }
+});
+
+dojo.declare("dojox.grid._TreeLayout", dojox.grid._Layout, {
+ // Whether or not we are collapsable - this is calculated when we
+ // set our structure.
+ _isCollapsable: false,
+
+ _getInternalStructure: function(inStructure){
+ // Create a "Tree View" with 1 row containing references for
+ // each column (recursively)
+ var g = this.grid;
+
+ var s = inStructure;
+ var cells = s[0].cells[0];
+ var tree = {
+ type: "dojox.grid._TreeView",
+ cells: [[]]
+ };
+ var cFields = [];
+ var maxLevels = 0;
+ var getTreeCells = function(parentCell, level){
+ var children = parentCell.children;
+ var cloneTreeCell = function(originalCell, idx){
+ var k, n = {};
+ for(k in originalCell){
+ n[k] = originalCell[k];
+ }
+ n = dojo.mixin(n, {
+ level: level,
+ idxInParent: level > 0 ? idx : -1,
+ parentCell: level > 0 ? parentCell : null
+ });
+ return n;
+ };
+ var ret = [];
+ dojo.forEach(children, function(c, idx){
+ if("children" in c){
+ cFields.push(c.field);
+ var last = ret[ret.length - 1];
+ last.isCollapsable = true;
+ c.level = level;
+ ret = ret.concat(getTreeCells(c, level + 1));
+ }else{
+ ret.push(cloneTreeCell(c, idx));
+ }
+ });
+ maxLevels = Math.max(maxLevels, level);
+ return ret;
+ };
+ var tCell = {children: cells, itemAggregates: []};
+ tree.cells[0] = getTreeCells(tCell, 0);
+ g.aggregator = new dojox.grid._TreeAggregator({cells: tree.cells[0],
+ grid: g,
+ childFields: cFields});
+ if(g.scroller && g.defaultOpen){
+ g.scroller.defaultRowHeight = g.scroller._origDefaultRowHeight * (2 * maxLevels + 1);
+ }
+ return [ tree ];
+ },
+
+ setStructure: function(inStructure){
+ // Mangle the structure a bit and make it work as desired
+ var s = inStructure;
+ var g = this.grid;
+ // Only supporting single-view, single row or else we
+ // are not collapsable
+ if(g && g.treeModel && !dojo.every(s, function(i){
+ return ("cells" in i);
+ })){
+ s = arguments[0] = [{cells:[s]}];
+ }
+ if(s.length == 1 && s[0].cells.length == 1){
+ if(g && g.treeModel){
+ s[0].type = "dojox.grid._TreeView";
+ this._isCollapsable = true;
+ s[0].cells[0][(this.grid.treeModel?this.grid.expandoCell:0)].isCollapsable = true;
+ }else{
+ var childCells = dojo.filter(s[0].cells[0], function(c){
+ return ("children" in c);
+ });
+ if(childCells.length === 1){
+ this._isCollapsable = true;
+ }
+ }
+ }
+ if(this._isCollapsable && (!g || !g.treeModel)){
+ arguments[0] = this._getInternalStructure(s);
+ }
+ this.inherited(arguments);
+ },
+
+ addCellDef: function(inRowIndex, inCellIndex, inDef){
+ var obj = this.inherited(arguments);
+ return dojo.mixin(obj, dojox.grid.cells.TreeCell);
+ }
+});
+
+dojo.declare("dojox.grid.TreePath", null, {
+ level: 0,
+ _str: "",
+ _arr: null,
+ grid: null,
+ store: null,
+ cell: null,
+ item: null,
+
+ constructor: function(/*String|Integer[]|Integer|dojox.grid.TreePath*/ path, /*dojox.grid.TreeGrid*/ grid){
+ if(dojo.isString(path)){
+ this._str = path;
+ this._arr = dojo.map(path.split('/'), function(item){ return parseInt(item, 10); });
+ }else if(dojo.isArray(path)){
+ this._str = path.join('/');
+ this._arr = path.slice(0);
+ }else if(typeof path == "number"){
+ this._str = String(path);
+ this._arr = [path];
+ }else{
+ this._str = path._str;
+ this._arr = path._arr.slice(0);
+ }
+ this.level = this._arr.length-1;
+ this.grid = grid;
+ this.store = this.grid.store;
+ if(grid.treeModel){
+ this.cell = grid.layout.cells[grid.expandoCell];
+ }else{
+ this.cell = grid.layout.cells[this.level];
+ }
+ },
+ item: function(){
+ // summary:
+ // gets the dojo.data item associated with this path
+ if(!this._item){
+ this._item = this.grid.getItem(this._arr);
+ }
+ return this._item;
+ },
+ compare: function(path /*dojox.grid.TreePath|String|Array*/){
+ // summary:
+ // compares two paths
+ if(dojo.isString(path) || dojo.isArray(path)){
+ if(this._str == path){ return 0; }
+ if(path.join && this._str == path.join('/')){ return 0; }
+ path = new dojox.grid.TreePath(path, this.grid);
+ }else if(path instanceof dojox.grid.TreePath){
+ if(this._str == path._str){ return 0; }
+ }
+ for(var i=0, l=(this._arr.length < path._arr.length ? this._arr.length : path._arr.length); i<l; i++){
+ if(this._arr[i]<path._arr[i]){ return -1; }
+ if(this._arr[i]>path._arr[i]){ return 1; }
+ }
+ if(this._arr.length<path._arr.length){ return -1; }
+ if(this._arr.length>path._arr.length){ return 1; }
+ return 0;
+ },
+ isOpen: function(){
+ // summary:
+ // Returns the open state of this cell.
+ return this.cell.openStates && this.cell.getOpenState(this.item());
+ },
+ previous: function(){
+ // summary:
+ // Returns the path that is before this path in the
+ // grid. If no path is found, returns null.
+ var new_path = this._arr.slice(0);
+
+ if(this._str == "0"){
+ return null;
+ }
+
+ var last = new_path.length-1;
+
+ if(new_path[last] === 0){
+ new_path.pop();
+ return new dojox.grid.TreePath(new_path, this.grid);
+ }
+
+ new_path[last]--;
+ var path = new dojox.grid.TreePath(new_path, this.grid);
+ return path.lastChild(true);
+ },
+ next: function(){
+ // summary:
+ // Returns the next path in the grid. If no path
+ // is found, returns null.
+ var new_path = this._arr.slice(0);
+
+ if(this.isOpen()){
+ new_path.push(0);
+ }else{
+ new_path[new_path.length-1]++;
+ for(var i=this.level; i>=0; i--){
+ var item = this.grid.getItem(new_path.slice(0, i+1));
+ if(i>0){
+ if(!item){
+ new_path.pop();
+ new_path[i-1]++;
+ }
+ }else{
+ if(!item){
+ return null;
+ }
+ }
+ }
+ }
+
+ return new dojox.grid.TreePath(new_path, this.grid);
+ },
+ children: function(alwaysReturn){
+ // summary:
+ // Returns the child data items of this row. If this
+ // row isn't open and alwaysReturn is falsey, returns null.
+ if(!this.isOpen()&&!alwaysReturn){
+ return null;
+ }
+ var items = [];
+ var model = this.grid.treeModel;
+ if(model){
+ var item = this.item();
+ var store = model.store;
+ if(!model.mayHaveChildren(item)){
+ return null;
+ }
+ dojo.forEach(model.childrenAttrs, function(attr){
+ items = items.concat(store.getValues(item, attr));
+ });
+ }else{
+ items = this.store.getValues(this.item(), this.grid.layout.cells[this.cell.level+1].parentCell.field);
+ if(items.length>1&&this.grid.sortChildItems){
+ var sortProps = this.grid.getSortProps();
+ if(sortProps&&sortProps.length){
+ var attr = sortProps[0].attribute,
+ grid = this.grid;
+ if(attr&&items[0][attr]){
+ var desc = !!sortProps[0].descending;
+ items = items.slice(0); // don't touch the array in the store, make a copy
+ items.sort(function(a, b){
+ return grid._childItemSorter(a, b, attr, desc);
+ });
+ }
+ }
+ }
+ }
+ return items;
+ },
+ childPaths: function(){
+ var childItems = this.children();
+ if(!childItems){
+ return [];
+ }
+ return dojo.map(childItems, function(item, index){
+ return new dojox.grid.TreePath(this._str + '/' + index, this.grid);
+ }, this);
+ },
+ parent: function(){
+ // summary:
+ // Returns the parent path of this path. If this is a
+ // top-level row, returns null.
+ if(this.level === 0){
+ return null;
+ }
+ return new dojox.grid.TreePath(this._arr.slice(0, this.level), this.grid);
+ },
+ lastChild: function(/*Boolean?*/ traverse){
+ // summary:
+ // Returns the last child row below this path. If traverse
+ // is true, will traverse down to find the last child row
+ // of this branch. If there are no children, returns itself.
+ var children = this.children();
+ if(!children || !children.length){
+ return this;
+ }
+ var path = new dojox.grid.TreePath(this._str + "/" + String(children.length-1), this.grid);
+ if(!traverse){
+ return path;
+ }
+ return path.lastChild(true);
+ },
+ toString: function(){
+ return this._str;
+ }
+});
+
+dojo.declare("dojox.grid._TreeFocusManager", dojox.grid._FocusManager, {
+ setFocusCell: function(inCell, inRowIndex){
+ if(inCell && inCell.getNode(inRowIndex)){
+ this.inherited(arguments);
+ }
+ },
+ isLastFocusCell: function(){
+ if(this.cell && this.cell.index == this.grid.layout.cellCount-1){
+ var path = new dojox.grid.TreePath(this.grid.rowCount-1, this.grid);
+ path = path.lastChild(true);
+ return this.rowIndex == path._str;
+ }
+ return false;
+ },
+ next: function(){
+ // summary:
+ // focus next grid cell
+ if(this.cell){
+ var row=this.rowIndex, col=this.cell.index+1, cc=this.grid.layout.cellCount-1;
+ var path = new dojox.grid.TreePath(this.rowIndex, this.grid);
+ if(col > cc){
+ var new_path = path.next();
+ if(!new_path){
+ col--;
+ }else{
+ col = 0;
+ path = new_path;
+ }
+ }
+ if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
+ var nextCell = this.grid.getCell(col);
+ if (!this.isLastFocusCell() && !nextCell.editable){
+ this._focusifyCellNode(false);
+ this.cell=nextCell;
+ this.rowIndex=path._str;
+ this.next();
+ return;
+ }
+ }
+ this.setFocusIndex(path._str, col);
+ }
+ },
+ previous: function(){
+ // summary:
+ // focus previous grid cell
+ if(this.cell){
+ var row=(this.rowIndex || 0), col=(this.cell.index || 0) - 1;
+ var path = new dojox.grid.TreePath(row, this.grid);
+ if(col < 0){
+ var new_path = path.previous();
+ if(!new_path){
+ col = 0;
+ }else{
+ col = this.grid.layout.cellCount-1;
+ path = new_path;
+ }
+ }
+ if(this.grid.edit.isEditing()){ //when editing, only navigate to editable cells
+ var prevCell = this.grid.getCell(col);
+ if (!this.isFirstFocusCell() && !prevCell.editable){
+ this._focusifyCellNode(false);
+ this.cell=prevCell;
+ this.rowIndex=path._str;
+ this.previous();
+ return;
+ }
+ }
+ this.setFocusIndex(path._str, col);
+ }
+ },
+ move: function(inRowDelta, inColDelta){
+ if(this.isNavHeader()){
+ this.inherited(arguments);
+ return;
+ }
+ if(!this.cell){ return; }
+ // Handle grid proper.
+ var sc = this.grid.scroller,
+ r = this.rowIndex,
+ rc = this.grid.rowCount-1,
+ path = new dojox.grid.TreePath(this.rowIndex, this.grid);
+ if(inRowDelta){
+ var row;
+ if(inRowDelta>0){
+ path = path.next();
+ row = path._arr[0];
+ if(row > sc.getLastPageRow(sc.page)){
+ //need to load additional data, let scroller do that
+ this.grid.setScrollTop(this.grid.scrollTop+sc.findScrollTop(row)-sc.findScrollTop(r));
+ }
+ }else if(inRowDelta<0){
+ path = path.previous();
+ row = path._arr[0];
+ if(row <= sc.getPageRow(sc.page)){
+ //need to load additional data, let scroller do that
+ this.grid.setScrollTop(this.grid.scrollTop-sc.findScrollTop(r)-sc.findScrollTop(row));
+ }
+ }
+ }
+ var cc = this.grid.layout.cellCount-1,
+ i = this.cell.index,
+ col = Math.min(cc, Math.max(0, i+inColDelta));
+ var cell = this.grid.getCell(col);
+ var colDir = inColDelta < 0 ? -1 : 1;
+ while(col>=0 && col < cc && cell && cell.hidden === true){
+ // skip hidden cells
+ col += colDir;
+ cell = this.grid.getCell(col);
+ }
+ if (!cell || cell.hidden === true){
+ // don't change col if would move to hidden
+ col = i;
+ }
+ if(inRowDelta){
+ this.grid.updateRow(r);
+ }
+ this.setFocusIndex(path._str, col);
+ }
+});
+
+dojo.declare("dojox.grid.TreeGrid", dojox.grid.DataGrid, {
+ // summary:
+ // A grid that supports nesting rows - it provides an expando function
+ // similar to dijit.Tree. It also provides mechanisms for aggregating
+ // the values of subrows
+ //
+ // description:
+ // TreeGrid currently only works on "simple" structures. That is,
+ // single-view structures with a single row in them.
+ //
+ // The TreeGrid works using the concept of "levels" - level 0 are the
+ // top-level items.
+
+ // defaultOpen: Boolean
+ // Whether or not we default to open (all levels). This defaults to
+ // false for grids with a treeModel.
+ defaultOpen: true,
+
+ // sortChildItems: Boolean
+ // If true, child items will be returned sorted according to the sorting
+ // properties of the grid.
+ sortChildItems: false,
+
+ // openAtLevels: Array
+ // Which levels we are open at (overrides defaultOpen for the values
+ // that exist here). Its values can be a boolean (true/false) or an
+ // integer (for the # of children to be closed if there are more than
+ // that)
+ openAtLevels: [],
+
+ // treeModel: dijit.tree.ForestStoreModel
+ // A dijit.Tree model that will be used instead of using aggregates.
+ // Setting this value will make the TreeGrid behave like a columnar
+ // tree. When setting this value, defaultOpen will default to false,
+ // and openAtLevels will be ignored.
+ treeModel: null,
+
+ // expandoCell: Integer
+ // When used in conjunction with a treeModel (see above), this is a 0-based
+ // index of the cell in which to place the actual expando
+ expandoCell: 0,
+
+ // private values
+ // aggregator: Object
+ // The aggregator class - it will be populated automatically if we
+ // are a collapsable grid
+ aggregator: null,
+
+
+ // Override this to get our "magic" layout
+ _layoutClass: dojox.grid._TreeLayout,
+
+ createSelection: function(){
+ this.selection = new dojox.grid.TreeSelection(this);
+ },
+
+ _childItemSorter: function(a, b, attribute, descending){
+ var av = this.store.getValue(a, attribute);
+ var bv = this.store.getValue(b, attribute);
+ if(av != bv){
+ return av < bv == descending ? 1 : -1;
+ }
+ return 0;
+ },
+
+ _onNew: function(item, parentInfo){
+ if(!parentInfo || !parentInfo.item){
+ this.inherited(arguments);
+ }else{
+ var idx = this.getItemIndex(parentInfo.item);
+ if(typeof idx == "string"){
+ this.updateRow(idx.split('/')[0]);
+ }else if(idx > -1){
+ this.updateRow(idx);
+ }
+ }
+ },
+
+ _onSet: function(item, attribute, oldValue, newValue){
+ this._checkUpdateStatus();
+ if(this.aggregator){
+ this.aggregator.clearSubtotalCache();
+ }
+ var idx = this.getItemIndex(item);
+ if(typeof idx == "string"){
+ this.updateRow(idx.split('/')[0]);
+ }else if(idx > -1){
+ this.updateRow(idx);
+ }
+ },
+
+ _onDelete: function(item){
+ this._cleanupExpandoCache(this._getItemIndex(item, true), this.store.getIdentity(item), item);
+ this.inherited(arguments);
+ },
+
+ _cleanupExpandoCache: function(index, identity, item){},
+
+ _addItem: function(item, index, noUpdate, dontUpdateRoot){
+ // add our root items to the root of the model's children
+ // list since we don't query the model
+ if(!dontUpdateRoot && this.model && dojo.indexOf(this.model.root.children, item) == -1){
+ this.model.root.children[index] = item;
+ }
+ this.inherited(arguments);
+ },
+
+ getItem: function(/*integer|Array|String*/ idx){
+ // summary:
+ // overridden so that you can pass in a '/' delimited string of indexes to get the
+ // item based off its path...that is, passing in "1/3/2" will get the
+ // 3rd (0-based) child from the 4th child of the 2nd top-level item.
+ var isArray = dojo.isArray(idx);
+ if(dojo.isString(idx) && idx.indexOf('/')){
+ idx = idx.split('/');
+ isArray = true;
+ }
+ if(isArray && idx.length == 1){
+ idx = idx[0];
+ isArray = false;
+ }
+ if(!isArray){
+ return dojox.grid.DataGrid.prototype.getItem.call(this, idx);
+ }
+ var s = this.store;
+ var itm = dojox.grid.DataGrid.prototype.getItem.call(this, idx[0]);
+ var cf, i, j;
+ if(this.aggregator){
+ cf = this.aggregator.childFields||[];
+ if(cf){
+ for(i = 0; i < idx.length - 1 && itm; i++){
+ if(cf[i]){
+ itm = (s.getValues(itm, cf[i])||[])[idx[i + 1]];
+ }else{
+ itm = null;
+ }
+ }
+ }
+ }else if(this.treeModel){
+ cf = this.treeModel.childrenAttrs||[];
+ if(cf&&itm){
+ for(i=1, il=idx.length; (i<il) && itm; i++) {
+ for(j=0, jl=cf.length; j<jl; j++) {
+ if(cf[j]){
+ itm = (s.getValues(itm, cf[j])||[])[idx[i]];
+ }else{
+ itm = null;
+ }
+ if(itm){ break; }
+ }
+ }
+ }
+ }
+ return itm || null;
+ },
+
+ _getItemIndex: function(item, isDeleted){
+ if(!isDeleted && !this.store.isItem(item)){
+ return -1;
+ }
+ var idx = this.inherited(arguments);
+ if(idx == -1){
+ var idty = this.store.getIdentity(item);
+ return this._by_idty_paths[idty] || -1;
+ }
+ return idx;
+ },
+
+ postMixInProperties: function(){
+ if(this.treeModel && !("defaultOpen" in this.params)){
+ // Default open to false for tree models, true for other tree
+ // grids.
+ this.defaultOpen = false;
+ }
+ var def = this.defaultOpen;
+ this.openAtLevels = dojo.map(this.openAtLevels, function(l){
+ if(typeof l == "string"){
+ switch(l.toLowerCase()){
+ case "true":
+ return true;
+ break;
+ case "false":
+ return false;
+ break;
+ default:
+ var r = parseInt(l, 10);
+ if(isNaN(r)){
+ return def;
+ }
+ return r;
+ break;
+ }
+ }
+ return l;
+ });
+ this._by_idty_paths = {};
+ this.inherited(arguments);
+ },
+
+ postCreate: function(){
+ this.inherited(arguments);
+ if(this.treeModel){
+ this._setModel(this.treeModel);
+ }
+ },
+
+ setModel: function(treeModel){
+ this._setModel(treeModel);
+ this._refresh(true);
+ },
+
+ _setModel: function(treeModel){
+ if(treeModel && (!dijit.tree.ForestStoreModel || !(treeModel instanceof dijit.tree.ForestStoreModel))){
+ throw new Error("dojox.grid.TreeGrid: treeModel must be an instance of dijit.tree.ForestStoreModel");
+ }
+ this.treeModel = treeModel;
+ dojo.toggleClass(this.domNode, "dojoxGridTreeModel", this.treeModel ? true : false);
+ this._setQuery(treeModel ? treeModel.query : null);
+ this._setStore(treeModel ? treeModel.store : null);
+ },
+
+ createScroller: function(){
+ this.inherited(arguments);
+ this.scroller._origDefaultRowHeight = this.scroller.defaultRowHeight;
+ },
+
+ createManagers: function(){
+ // summary:
+ // create grid managers for various tasks including rows, focus, selection, editing
+
+ // row manager
+ this.rows = new dojox.grid._RowManager(this);
+ // focus manager
+ this.focus = new dojox.grid._TreeFocusManager(this);
+ // edit manager
+ this.edit = new dojox.grid._EditManager(this);
+ },
+
+ _setStore: function(store){
+ this.inherited(arguments);
+ if(this.treeModel&&!this.treeModel.root.children){
+ this.treeModel.root.children = [];
+ }
+ if(this.aggregator){
+ this.aggregator.store = store;
+ }
+ },
+
+ getDefaultOpenState: function(cellDef, item){
+ // summary:
+ // Returns the default open state for the given definition and item
+ // It reads from the openAtLevels and defaultOpen values of the
+ // grid to calculate if the given item should default to open or
+ // not.
+ var cf;
+ var store = this.store;
+ if(this.treeModel){ return this.defaultOpen; }
+ if(!cellDef || !store || !store.isItem(item) ||
+ !(cf = this.aggregator.childFields[cellDef.level])){
+ return this.defaultOpen;
+ }
+ if(this.openAtLevels.length > cellDef.level){
+ var dVal = this.openAtLevels[cellDef.level];
+ if(typeof dVal == "boolean"){
+ return dVal;
+ }else if(typeof dVal == "number"){
+ return (store.getValues(item, cf).length <= dVal);
+ }
+ }
+ return this.defaultOpen;
+ },
+ onStyleRow: function(row){
+ if(!this.layout._isCollapsable){
+ this.inherited(arguments);
+ return;
+ }
+ var base = dojo.attr(row.node, 'dojoxTreeGridBaseClasses');
+ if(base){
+ row.customClasses = base;
+ }
+ var i = row;
+ var tagName = i.node.tagName.toLowerCase();
+ i.customClasses += (i.odd?" dojoxGridRowOdd":"") +
+ (i.selected&&tagName=='tr'?" dojoxGridRowSelected":"") +
+ (i.over&&tagName=='tr'?" dojoxGridRowOver":"");
+ this.focus.styleRow(i);
+ this.edit.styleRow(i);
+ },
+ styleRowNode: function(inRowIndex, inRowNode){
+ if(inRowNode){
+ if(inRowNode.tagName.toLowerCase() == 'div' && this.aggregator){
+ dojo.query("tr[dojoxTreeGridPath]", inRowNode).forEach(function(rowNode){
+ this.rows.styleRowNode(dojo.attr(rowNode, 'dojoxTreeGridPath'), rowNode);
+ },this);
+ }
+ this.rows.styleRowNode(inRowIndex, inRowNode);
+ }
+ },
+ onCanSelect: function(inRowIndex){
+ var nodes = dojo.query("tr[dojoxTreeGridPath='" + inRowIndex + "']", this.domNode);
+ if(nodes.length){
+ if(dojo.hasClass(nodes[0], 'dojoxGridSummaryRow')){
+ return false;
+ }
+ }
+ return this.inherited(arguments);
+ },
+ onKeyDown: function(e){
+ if(e.altKey || e.metaKey){
+ return;
+ }
+ var dk = dojo.keys;
+ switch(e.keyCode){
+ case dk.UP_ARROW:
+ if(!this.edit.isEditing() && this.focus.rowIndex != "0"){
+ dojo.stopEvent(e);
+ this.focus.move(-1, 0);
+ }
+ break;
+ case dk.DOWN_ARROW:
+ var currPath = new dojox.grid.TreePath(this.focus.rowIndex, this);
+ var lastPath = new dojox.grid.TreePath(this.rowCount-1, this);
+ lastPath = lastPath.lastChild(true);
+ if(!this.edit.isEditing() && currPath.toString() != lastPath.toString()){
+ dojo.stopEvent(e);
+ this.focus.move(1, 0);
+ }
+ break;
+ default:
+ this.inherited(arguments);
+ break;
+ }
+ },
+ canEdit: function(inCell, inRowIndex){
+ var node = inCell.getNode(inRowIndex);
+ return node && this._canEdit;
+ },
+ doApplyCellEdit: function(inValue, inRowIndex, inAttrName){
+ var item = this.getItem(inRowIndex);
+ var oldValue = this.store.getValue(item, inAttrName);
+ if(typeof oldValue == 'number'){
+ inValue = isNaN(inValue) ? inValue : parseFloat(inValue);
+ }else if(typeof oldValue == 'boolean'){
+ inValue = inValue == 'true' ? true : inValue == 'false' ? false : inValue;
+ }else if(oldValue instanceof Date){
+ var asDate = new Date(inValue);
+ inValue = isNaN(asDate.getTime()) ? inValue : asDate;
+ }
+ this.store.setValue(item, inAttrName, inValue);
+ this.onApplyCellEdit(inValue, inRowIndex, inAttrName);
+ }
+});
+dojox.grid.TreeGrid.markupFactory = function(props, node, ctor, cellFunc){
+ var d = dojo;
+ var widthFromAttr = function(n){
+ var w = d.attr(n, "width")||"auto";
+ if((w != "auto")&&(w.slice(-2) != "em")&&(w.slice(-1) != "%")){
+ w = parseInt(w, 10)+"px";
+ }
+ return w;
+ };
+
+ var cellsFromMarkup = function(table){
+ var rows;
+ // Don't support colgroup on our grid - single view, single row only
+ if(table.nodeName.toLowerCase() == "table" &&
+ d.query("> colgroup", table).length === 0 &&
+ (rows = d.query("> thead > tr", table)).length == 1){
+ var tr = rows[0];
+ return d.query("> th", rows[0]).map(function(th){
+ // Grab type and field (the only ones that are shared
+ var cell = {
+ type: d.trim(d.attr(th, "cellType")||""),
+ field: d.trim(d.attr(th, "field")||"")
+ };
+ if(cell.type){
+ cell.type = d.getObject(cell.type);
+ }
+
+ var subTable = d.query("> table", th)[0];
+ if(subTable){
+ // If we have a subtable, we are an aggregate and a summary cell
+ cell.name = "";
+ cell.children = cellsFromMarkup(subTable);
+ if(d.hasAttr(th, "itemAggregates")){
+ cell.itemAggregates = d.map(d.attr(th, "itemAggregates").split(","), function(v){
+ return d.trim(v);
+ });
+ }else{
+ cell.itemAggregates = [];
+ }
+ if(d.hasAttr(th, "aggregate")){
+ cell.aggregate = d.attr(th, "aggregate");
+ }
+ cell.type = cell.type || dojox.grid.cells.SubtableCell;
+ }else{
+ // Grab our other stuff we need (mostly what's in the normal
+ // Grid)
+ cell.name = d.trim(d.attr(th, "name")||th.innerHTML);
+ if(d.hasAttr(th, "width")){
+ cell.width = widthFromAttr(th);
+ }
+ if(d.hasAttr(th, "relWidth")){
+ cell.relWidth = window.parseInt(d.attr(th, "relWidth"), 10);
+ }
+ if(d.hasAttr(th, "hidden")){
+ cell.hidden = d.attr(th, "hidden") == "true";
+ }
+ cell.field = cell.field||cell.name;
+ dojox.grid.DataGrid.cell_markupFactory(cellFunc, th, cell);
+ cell.type = cell.type || dojox.grid.cells.Cell;
+ }
+ if(cell.type && cell.type.markupFactory){
+ cell.type.markupFactory(th, cell);
+ }
+ return cell;
+ });
+ }
+ return [];
+ };
+
+ var rows;
+ if( !props.structure ){
+ var row = cellsFromMarkup(node);
+ if(row.length){
+ // Set our structure here - so that we don't try and set it in the
+ // markup factory
+ props.structure = [{__span: Infinity, cells:[row]}];
+ }
+ }
+ return dojox.grid.DataGrid.markupFactory(props, node, ctor, cellFunc);
+};
+
+}
+
+}};});
|
