123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275 |
- define("dojox/grid/enhanced/plugins/CellMerge", [
- "dojo/_base/declare",
- "dojo/_base/array",
- "dojo/_base/lang",
- "dojo/_base/html",
- "../_Plugin",
- "../../EnhancedGrid"
- ], function(declare, array, lang, html, _Plugin, EnhancedGrid){
- var CellMerge = declare("dojox.grid.enhanced.plugins.CellMerge", _Plugin, {
- // summary:
- // This plugin provides functions to merge(un-merge) adjacent cells within one row.
- // Acceptable plugin paramters:
- // 1. mergedCells: Array
- // An array of objects with structure:
- // {
- // row: function(Integer)|Integer
- // If it's a function, it's a predicate to decide which rows are to be merged.
- // It takes an integer (the row index), and should return true or false;
- // start: Integer
- // The column index of the left most cell that shall be merged.
- // end: Integer
- // The column index of the right most cell that shall be merged.
- // major: Integer
- // The column index of the cell whose content should be used as the content of the merged cell.
- // It must be larger than or equal to the startColumnIndex, and less than or equal to the endColumnIndex.
- // If it is omitted, the content of the leading edge (left-most for ltr, right most for rtl) cell will be used.
- // }
-
- // name: String
- // Plugin name
- name: "cellMerge",
-
- constructor: function(grid, args){
- this.grid = grid;
- this._records = [];
- this._merged = {};
- if(args && lang.isObject(args)){
- this._setupConfig(args.mergedCells);
- }
- this._initEvents();
- this._mixinGrid();
- },
- //----------------Public----------------------------
- mergeCells: function(rowTester, startColumnIndex, endColumnIndex, majorColumnIndex){
- // summary:
- // Merge cells from *startColumnIndex* to *endColumnIndex* at rows that make *rowTester* return true,
- // using the content of the cell at *majorColumnIndex*
- // tags:
- // public
- // rowTester: function(Integer)|Integer
- // If it's a function, it's a predicate to decide which rows are to be merged.
- // It takes an integer (the row index), and should return true or false;
- // startColumnIndex: Integer
- // The column index of the left most cell that shall be merged.
- // endColumnIndex: Integer
- // The column index of the right most cell that shall be merged.
- // majorColumnIndex: Integer?
- // The column index of the cell whose content should be used as the content of the merged cell.
- // It must be larger than or equal to the startColumnIndex, and less than or equal to the endColumnIndex.
- // If it is omitted, the content of the leading edge (left-most for ltr, right most for rtl) cell will be used.
- // return: Object | null
- // A handler for the merged cells created by a call of this function.
- // This handler can be used later to unmerge cells using the function unmergeCells
- // If the merge is not valid, returns null;
- var item = this._createRecord({
- "row": rowTester,
- "start": startColumnIndex,
- "end": endColumnIndex,
- "major": majorColumnIndex
- });
- if(item){
- this._updateRows(item);
- }
- return item;
- },
- unmergeCells: function(mergeHandler){
- // summary:
- // Unmerge the cells that are merged by the *mergeHandler*, which represents a call to the function mergeCells.
- // tags:
- // public
- // mergeHandler: object
- // A handler for the merged cells created by a call of function mergeCells.
- var idx;
- if(mergeHandler && (idx = array.indexOf(this._records, mergeHandler)) >= 0){
- this._records.splice(idx, 1);
- this._updateRows(mergeHandler);
- }
- },
- getMergedCells: function(){
- // summary:
- // Get all records of currently merged cells.
- // tags:
- // public
- // return: Array
- // An array of records for merged-cells.
- // The record has the following structure:
- // {
- // "row": 1, //the row index
- // "start": 2, //the start column index
- // "end": 4, //the end column index
- // "major": 3, //the major column index
- // "handle": someHandle, //The handler that covers this merge cell record.
- // }
- var res = [];
- for(var i in this._merged){
- res = res.concat(this._merged[i]);
- }
- return res;
- },
- getMergedCellsByRow: function(rowIndex){
- // summary:
- // Get the records of currently merged cells at the given row.
- // tags:
- // public
- // return: Array
- // An array of records for merged-cells. See docs of getMergedCells.
- return this._merged[rowIndex] || [];
- },
-
- //----------------Private--------------------------
- _setupConfig: function(config){
- array.forEach(config, this._createRecord, this);
- },
- _initEvents: function(){
- array.forEach(this.grid.views.views, function(view){
- this.connect(view, "onAfterRow", lang.hitch(this, "_onAfterRow", view.index));
- }, this);
- },
- _mixinGrid: function(){
- var g = this.grid;
- g.mergeCells = lang.hitch(this, "mergeCells");
- g.unmergeCells = lang.hitch(this, "unmergeCells");
- g.getMergedCells = lang.hitch(this, "getMergedCells");
- g.getMergedCellsByRow = lang.hitch(this, "getMergedCellsByRow");
- },
- _getWidth: function(colIndex){
- var node = this.grid.layout.cells[colIndex].getHeaderNode();
- return html.position(node).w;
- },
- _onAfterRow: function(viewIdx, rowIndex, subrows){
- try{
- if(rowIndex < 0){
- return;
- }
- var result = [], i, j, len = this._records.length,
- cells = this.grid.layout.cells;
- //Apply merge-cell requests one by one.
- for(i = 0; i < len; ++i){
- var item = this._records[i];
- var storeItem = this.grid._by_idx[rowIndex];
- if(item.view == viewIdx && item.row(rowIndex, storeItem && storeItem.item, this.grid.store)){
- var res = {
- record: item,
- hiddenCells: [],
- totalWidth: 0,
- majorNode: cells[item.major].getNode(rowIndex),
- majorHeaderNode: cells[item.major].getHeaderNode()
- };
- //Calculated the width of merged cell.
- for(j = item.start; j <= item.end; ++j){
- var w = this._getWidth(j, rowIndex);
- res.totalWidth += w;
- if(j != item.major){
- res.hiddenCells.push(cells[j].getNode(rowIndex));
- }
- }
- //If width is valid, remember it. There may be multiple merges within one row.
- if(subrows.length != 1 || res.totalWidth > 0){
- //Remove conflicted merges.
- for(j = result.length - 1; j >= 0; --j){
- var r = result[j].record;
- if((r.start >= item.start && r.start <= item.end) ||
- (r.end >= item.start && r.end <= item.end)){
- result.splice(j, 1);
- }
- }
- result.push(res);
- }
- }
- }
- this._merged[rowIndex] = [];
- array.forEach(result, function(res){
- array.forEach(res.hiddenCells, function(node){
- html.style(node, "display", "none");
- });
- var pbm = html.marginBox(res.majorHeaderNode).w - html.contentBox(res.majorHeaderNode).w;
- var tw = res.totalWidth;
-
- //Tricky for WebKit.
- if(!html.isWebKit){
- tw -= pbm;
- }
-
- html.style(res.majorNode, "width", tw + "px");
- //In case we're dealing with multiple subrows.
- res.majorNode.setAttribute("colspan", res.hiddenCells.length + 1);
-
- this._merged[rowIndex].push({
- "row": rowIndex,
- "start": res.record.start,
- "end": res.record.end,
- "major": res.record.major,
- "handle": res.record
- });
- }, this);
- }catch(e){
- console.warn("CellMerge._onAfterRow() error: ", rowIndex, e);
- }
- },
- _createRecord: function(item){
- if(this._isValid(item)){
- item = {
- "row": item.row,
- "start": item.start,
- "end": item.end,
- "major": item.major
- };
- var cells = this.grid.layout.cells;
- item.view = cells[item.start].view.index;
- item.major = typeof item.major == "number" && !isNaN(item.major) ? item.major : item.start;
- if(typeof item.row == "number"){
- var r = item.row;
- item.row = function(rowIndex){
- return rowIndex === r;
- };
- }else if(typeof item.row == "string"){
- var id = item.row;
- item.row = function(rowIndex, storeItem, store){
- try{
- if(store && storeItem && store.getFeatures()['dojo.data.api.Identity']){
- return store.getIdentity(storeItem) == id;
- }
- }catch(e){
- console.error(e);
- }
- return false;
- };
- }
- if(lang.isFunction(item.row)){
- this._records.push(item);
- return item;
- }
- }
- return null;
- },
- _isValid: function(item){
- var cells = this.grid.layout.cells,
- colCount = cells.length;
- return (lang.isObject(item) && ("row" in item) && ("start" in item) && ("end" in item) &&
- item.start >= 0 && item.start < colCount &&
- item.end > item.start && item.end < colCount &&
- cells[item.start].view.index == cells[item.end].view.index &&
- cells[item.start].subrow == cells[item.end].subrow &&
- !(typeof item.major == "number" && (item.major < item.start || item.major > item.end)));
- },
- _updateRows: function(item){
- var min = null;
- for(var i = 0, count = this.grid.rowCount; i < count; ++i){
- var storeItem = this.grid._by_idx[i];
- if(storeItem && item.row(i, storeItem && storeItem.item, this.grid.store)){
- this.grid.views.updateRow(i);
- if(min === null){ min = i; }
- }
- }
- if(min >= 0){
- this.grid.scroller.rowHeightChanged(min);
- }
- }
- });
- EnhancedGrid.registerPlugin(CellMerge);
- return CellMerge;
- });
|