dojox/grid/TreeGrid.js

  • Provides:

    • dojox.grid.TreeGrid
  • Requires:

    • dojox.grid.DataGrid in common
    • dojox.grid._TreeView in common
    • dojox.grid.cells.tree in common
    • dojox.grid.TreeSelection in common
  • dojox.grid._TreeAggregator

    • type
      Function
    • parameters:
      • kwArgs: (typeof )
    • source: [view]
        this.cells = kwArgs.cells || [];
        this.childFields = kwArgs.childFields || [];
        this.grid = kwArgs.grid;
        this.store = this.grid.store;
    • summary
  • dojox.grid._TreeAggregator.cells

    • summary
  • dojox.grid._TreeAggregator.grid

    • summary
  • dojox.grid._TreeAggregator.childFields

    • summary
  • dojox.grid._TreeAggregator._cacheValue

    • type
      Function
    • parameters:
      • cache: (typeof )
      • id: (typeof )
      • value: (typeof )
    • source: [view]
        cache[id] = value;
        return value;
    • summary
  • dojox.grid._TreeAggregator.clearSubtotalCache

    • type
      Function
    • source: [view]
        if(this.store){
         delete this.store._cachedAggregates;
        }
    • 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.
  • dojox.grid._TreeAggregator.cnt

    • type
      Function
    • parameters:
      • cell: (typeof )
      • level: (typeof )
      • item: (typeof )
    • source: [view]
        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;
    • summary
      calculates the count of the children of item at the given level
  • dojox.grid._TreeAggregator.sum

    • type
      Function
    • parameters:
      • cell: (typeof )
      • level: (typeof )
      • item: (typeof )
    • source: [view]
        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;
    • summary
      calculates the sum of the children of item at the given level
  • dojox.grid._TreeAggregator.value

    • type
      Function
    • parameters:
      • cell: (typeof )
      • level: (typeof )
      • item: (typeof )
    • source: [view]
        // summary:
        //  Empty function so that we can set "aggregate='value'" to
        //  force loading from the data - and bypass calculating
    • summary
      Empty function so that we can set &quot;aggregate='value'&quot; to
      force loading from the data - and bypass calculating
  • dojox.grid._TreeAggregator.getForCell

    • type
      Function
    • parameters:
      • cell: (typeof )
      • level: (typeof )
      • item: (typeof )
      • type: (typeof )
    • source: [view]
        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));
    • summary
      Gets the value of the given cell at the given level and type.
      type can be one of &quot;sum&quot;, &quot;cnt&quot;, or &quot;value&quot;.  If itemAggregates
      is set and can be used, it is used instead.  Values are also
      cached to prevent calculating them too often.
  • dojox.grid._TreeAggregator.store

    • summary
  • dojox.grid._TreeLayout

    • type
      Function
    • chains:
      • dojox.grid._Layout: (prototype)
      • dojox.grid._Layout: (call)
    • summary
  • dojox.grid._TreeLayout._isCollapsable

    • summary
  • dojox.grid._TreeLayout._getInternalStructure

    • type
      Function
    • parameters:
      • inStructure: (typeof )
    • source: [view]
      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 ];
    • summary
  • dojox.grid._TreeLayout.setStructure

    • type
      Function
    • parameters:
      • inStructure: (typeof )
    • source: [view]
      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);
    • summary
  • dojox.grid._TreeLayout.addCellDef

    • type
      Function
    • parameters:
      • inRowIndex: (typeof )
      • inCellIndex: (typeof )
      • inDef: (typeof )
    • source: [view]
        var obj = this.inherited(arguments);
        return dojo.mixin(obj, dojox.grid.cells.TreeCell);
    • summary
  • dojox.grid.TreePath

    • type
      Function
    • parameters:
      • path: (typeof String|Integer[]|Integer|dojox.grid.TreePath)
      • grid: (typeof dojox.grid.TreeGrid)
    • source: [view]
        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];
        }
    • summary
  • dojox.grid.TreePath.level

    • summary
  • dojox.grid.TreePath._str

    • summary
  • dojox.grid.TreePath._arr

    • summary
  • dojox.grid.TreePath.grid

    • summary
  • dojox.grid.TreePath.store

    • summary
  • dojox.grid.TreePath.cell

    • summary
  • dojox.grid.TreePath.item

    • type
      Function
    • source: [view]
        if(!this._item){
         this._item = this.grid.getItem(this._arr);
        }
        return this._item;
    • summary
      gets the dojo.data item associated with this path
  • dojox.grid.TreePath.compare

    • type
      Function
    • parameters:
      • path: (typeof dojox.grid.TreePath|String|Array)
    • source: [view]
        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   if(this._arr[i]   if(this._arr[i]>path._arr[i]){ return 1; }
        }
        if(this._arr.length  if(this._arr.length>path._arr.length){ return 1; }
        return 0;
    • summary
      compares two paths
  • dojox.grid.TreePath.isOpen

    • type
      Function
    • source: [view]
        return this.cell.openStates && this.cell.getOpenState(this.item());
    • summary
      Returns the open state of this cell.
  • dojox.grid.TreePath.previous

    • type
      Function
    • source: [view]
        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);
    • summary
      Returns the path that is before this path in the
      grid. If no path is found, returns null.
  • dojox.grid.TreePath.next

    • type
      Function
    • source: [view]
        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);
    • summary
      Returns the next path in the grid.  If no path
      is found, returns null.
  • dojox.grid.TreePath.children

    • type
      Function
    • parameters:
      • alwaysReturn: (typeof )
    • source: [view]
        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;
    • summary
      Returns the child data items of this row.  If this
      row isn't open and alwaysReturn is falsey, returns null.
  • dojox.grid.TreePath.childPaths

    • type
      Function
    • source: [view]
        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);
    • summary
  • dojox.grid.TreePath.parent

    • type
      Function
    • source: [view]
        if(this.level === 0){
         return null;
        }
        return new dojox.grid.TreePath(this._arr.slice(0, this.level), this.grid);
    • summary
      Returns the parent path of this path.  If this is a
      top-level row, returns null.
  • dojox.grid.TreePath.lastChild

    • type
      Function
    • parameters:
      • traverse: (typeof Boolean)
    • source: [view]
        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);
    • 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.
  • dojox.grid.TreePath.toString

    • type
      Function
    • source: [view]
        return this._str;
    • summary
  • dojox.grid.TreePath._item

    • summary
  • dojox.grid._TreeFocusManager

    • type
      Function
    • chains:
      • dojox.grid._FocusManager: (prototype)
      • dojox.grid._FocusManager: (call)
    • summary
  • dojox.grid._TreeFocusManager.setFocusCell

    • type
      Function
    • parameters:
      • inCell: (typeof )
      • inRowIndex: (typeof )
    • source: [view]
        if(inCell && inCell.getNode(inRowIndex)){
         this.inherited(arguments);
        }
    • summary
  • dojox.grid._TreeFocusManager.isLastFocusCell

    • type
      Function
    • source: [view]
        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;
    • summary
  • dojox.grid._TreeFocusManager.next

    • type
      Function
    • source: [view]
        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);
        }
    • summary
      focus next grid cell
  • dojox.grid._TreeFocusManager.previous

    • type
      Function
    • source: [view]
        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);
        }
    • summary
      focus previous grid cell
  • dojox.grid._TreeFocusManager.move

    • type
      Function
    • parameters:
      • inRowDelta: (typeof )
      • inColDelta: (typeof )
    • source: [view]
        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);
    • summary
  • dojox.grid._TreeFocusManager.cell.index

    • summary
  • dojox.grid._TreeFocusManager.rowIndex

    • summary
  • dojox.grid._TreeFocusManager.cell

    • summary
  • dojox.grid.TreeGrid

    • type
      Function
    • chains:
      • dojox.grid.DataGrid: (prototype)
      • dojox.grid.DataGrid: (call)
    • 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.
  • dojox.grid.TreeGrid.defaultOpen

    • type
      Boolean
    • summary
      Whether or not we default to open (all levels).  This defaults to
      false for grids with a treeModel.
  • dojox.grid.TreeGrid.sortChildItems

    • type
      Boolean
    • summary
      If true, child items will be returned sorted according to the sorting
      properties of the grid.
  • dojox.grid.TreeGrid.openAtLevels

    • type
      Array
    • summary
      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)
  • dojox.grid.TreeGrid.treeModel

    • type
      dijit.tree.ForestStoreModel
    • summary
      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.
  • dojox.grid.TreeGrid.expandoCell

    • type
      Integer
    • summary
      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
      
      
      private values
  • dojox.grid.TreeGrid.aggregator

    • type
      Object
    • summary
      The aggregator class - it will be populated automatically if we
      are a collapsable grid
  • dojox.grid.TreeGrid._layoutClass

    • summary
  • dojox.grid.TreeGrid.createSelection

    • type
      Function
    • source: [view]
        this.selection = new dojox.grid.TreeSelection(this);
    • summary
  • dojox.grid.TreeGrid._childItemSorter

    • type
      Function
    • parameters:
      • a: (typeof )
      • b: (typeof )
      • attribute: (typeof )
      • descending: (typeof )
    • source: [view]
        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;
    • summary
  • dojox.grid.TreeGrid._onNew

    • type
      Function
    • parameters:
      • item: (typeof )
      • parentInfo: (typeof )
    • source: [view]
        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);
         }
        }
    • summary
  • dojox.grid.TreeGrid._onSet

    • type
      Function
    • parameters:
      • item: (typeof )
      • attribute: (typeof )
      • oldValue: (typeof )
      • newValue: (typeof )
    • source: [view]
        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);
        }
    • summary
  • dojox.grid.TreeGrid._onDelete

    • type
      Function
    • parameters:
      • item: (typeof )
    • source: [view]
        this._cleanupExpandoCache(this._getItemIndex(item, true), this.store.getIdentity(item), item);
        this.inherited(arguments);
    • summary
  • dojox.grid.TreeGrid._cleanupExpandoCache

    • type
      Function
    • parameters:
      • index: (typeof )
      • identity: (typeof )
      • item: (typeof )
    • source: [view]
      }
    • summary
  • dojox.grid.TreeGrid._addItem

    • type
      Function
    • parameters:
      • item: (typeof )
      • index: (typeof )
      • noUpdate: (typeof )
      • dontUpdateRoot: (typeof )
    • source: [view]
      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   if(this._arr[i]   if(this._arr[i]>path._arr[i]){ return 1; }
        }
        if(this._arr.length  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);
    • summary
  • dojox.grid.TreeGrid.getItem

    • type
      Function
    • parameters:
      • idx: (typeof integer|Array|String)
    • source: [view]
        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     for(j=0, jl=cf.length; j      if(cf[j]){
             itm = (s.getValues(itm, cf[j])||[])[idx[i]];
            }else{
             itm = null;
            }
            if(itm){ break; }
           }
          }
         }
        }
        return itm || null;
    • 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 &quot;1/3/2&quot; will get the
      3rd (0-based) child from the 4th child of the 2nd top-level item.
    • chains:
      • dojox.grid.DataGrid.prototype.getItem: (call)
  • dojox.grid.TreeGrid._getItemIndex

    • type
      Function
    • parameters:
      • item: (typeof )
      • isDeleted: (typeof )
    • source: [view]
        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;
    • summary
  • dojox.grid.TreeGrid.postMixInProperties

    • type
      Function
    • source: [view]
        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);
    • summary
  • dojox.grid.TreeGrid.postCreate

    • type
      Function
    • source: [view]
      this.inherited(arguments);
        if(this.treeModel){
         this._setModel(this.treeModel);
        }
    • summary
  • dojox.grid.TreeGrid.setModel

    • type
      Function
    • parameters:
      • treeModel: (typeof )
    • source: [view]
        this._setModel(treeModel);
        this._refresh(true);
    • summary
  • dojox.grid.TreeGrid._setModel

    • type
      Function
    • parameters:
      • treeModel: (typeof )
    • source: [view]
        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);
    • summary
  • dojox.grid.TreeGrid.createScroller

    • type
      Function
    • source: [view]
        this.inherited(arguments);
        this.scroller._origDefaultRowHeight = this.scroller.defaultRowHeight;
    • summary
  • dojox.grid.TreeGrid.createManagers

    • type
      Function
    • source: [view]
      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   if(this._arr[i]   if(this._arr[i]>path._arr[i]){ return 1; }
        }
        if(this._arr.length  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     for(j=0, jl=cf.length; 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);
    • summary
  • dojox.grid.TreeGrid._setStore

    • type
      Function
    • parameters:
      • store: (typeof )
    • source: [view]
        this.inherited(arguments);
        if(this.treeModel&&!this.treeModel.root.children){
         this.treeModel.root.children = [];
        }
        if(this.aggregator){
         this.aggregator.store = store;
        }
    • summary
  • dojox.grid.TreeGrid.getDefaultOpenState

    • type
      Function
    • parameters:
      • cellDef: (typeof )
      • item: (typeof )
    • source: [view]
        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;
    • 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.
  • dojox.grid.TreeGrid.onStyleRow

    • type
      Function
    • parameters:
      • row: (typeof )
    • source: [view]
        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);
    • summary
  • dojox.grid.TreeGrid.styleRowNode

    • type
      Function
    • parameters:
      • inRowIndex: (typeof )
      • inRowNode: (typeof )
    • source: [view]
        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);
        }
    • summary
  • dojox.grid.TreeGrid.onCanSelect

    • type
      Function
    • parameters:
      • inRowIndex: (typeof )
    • source: [view]
        var nodes = dojo.query("tr[dojoxTreeGridPath='" + inRowIndex + "']", this.domNode);
        if(nodes.length){
         if(dojo.hasClass(nodes[0], 'dojoxGridSummaryRow')){
          return false;
         }
        }
        return this.inherited(arguments);
    • summary
  • dojox.grid.TreeGrid.onKeyDown

    • type
      Function
    • parameters:
      • e: (typeof )
    • source: [view]
        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;
        }
    • summary
  • dojox.grid.TreeGrid.canEdit

    • type
      Function
    • parameters:
      • inCell: (typeof )
      • inRowIndex: (typeof )
    • source: [view]
        var node = inCell.getNode(inRowIndex);
        return node && this._canEdit;
    • summary
  • dojox.grid.TreeGrid.doApplyCellEdit

    • type
      Function
    • parameters:
      • inValue: (typeof )
      • inRowIndex: (typeof )
      • inAttrName: (typeof )
    • source: [view]
        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);
    • summary
  • dojox.grid.TreeGrid.selection

    • summary
  • dojox.grid.TreeGrid._by_idty_paths

    • summary
  • dojox.grid.TreeGrid.scroller._origDefaultRowHeight

    • summary
  • dojox.grid.TreeGrid.rows

    • summary
  • dojox.grid.TreeGrid.focus

    • summary
  • dojox.grid.TreeGrid.edit

    • summary
  • dojox.grid.TreeGrid.treeModel.root.children

    • summary
  • dojox.grid.TreeGrid.aggregator.store

    • summary
  • dojox.grid.TreeGrid.markupFactory

    • type
      Function
    • parameters:
      • props: (typeof )
      • node: (typeof )
      • ctor: (typeof )
      • cellFunc: (typeof )
    • source: [view]
       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);
    • summary
  • n.level

    • summary
  • n.idxInParent

    • summary
  • n.parentCell

    • summary
  • obj

    • mixins:
      • dojox.grid.cells.TreeCell: (normal)
    • summary
  • dojox.grid

    • type
      Object
    • summary
  • dojox

    • type
      Object
    • summary