Subversion Repositories Applications.papyrus

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
2150 mathias 1
if(!dojo._hasResource["dojox.grid._grid.builder"]){ //_hasResource checks added by build. Do not use _hasResource directly in your code.
2
dojo._hasResource["dojox.grid._grid.builder"] = true;
3
dojo.provide("dojox.grid._grid.builder");
4
dojo.require("dojox.grid._grid.drag");
5
 
6
dojo.declare("dojox.grid.Builder", null, {
7
	// summary:
8
	//	Base class to produce html for grid content.
9
	//	Also provide event decoration, providing grid related information inside the event object
10
	// passed to grid events.
11
	constructor: function(inView){
12
		this.view = inView;
13
		this.grid = inView.grid;
14
	},
15
	view: null,
16
	// boilerplate HTML
17
	_table: '<table class="dojoxGrid-row-table" border="0" cellspacing="0" cellpadding="0" role="wairole:presentation">',
18
	// generate starting tags for a cell
19
	generateCellMarkup: function(inCell, inMoreStyles, inMoreClasses, isHeader){
20
		var result = [], html;
21
		if (isHeader){
22
			html = [ '<th tabIndex="-1" role="wairole:columnheader"' ];
23
		}else{
24
			html = [ '<td tabIndex="-1" role="wairole:gridcell"' ];
25
		}
26
		inCell.colSpan && html.push(' colspan="', inCell.colSpan, '"');
27
		inCell.rowSpan && html.push(' rowspan="', inCell.rowSpan, '"');
28
		html.push(' class="dojoxGrid-cell ');
29
		inCell.classes && html.push(inCell.classes, ' ');
30
		inMoreClasses && html.push(inMoreClasses, ' ');
31
		// result[0] => td opener, style
32
		result.push(html.join(''));
33
		// SLOT: result[1] => td classes
34
		result.push('');
35
		html = ['" idx="', inCell.index, '" style="'];
36
		html.push(inCell.styles, inMoreStyles||'');
37
		inCell.unitWidth && html.push('width:', inCell.unitWidth, ';');
38
		// result[2] => markup
39
		result.push(html.join(''));
40
		// SLOT: result[3] => td style
41
		result.push('');
42
		html = [ '"' ];
43
		inCell.attrs && html.push(" ", inCell.attrs);
44
		html.push('>');
45
		// result[4] => td postfix
46
		result.push(html.join(''));
47
		// SLOT: result[5] => content
48
		result.push('');
49
		// result[6] => td closes
50
		result.push('</td>');
51
		return result;
52
	},
53
	// cell finding
54
	isCellNode: function(inNode){
55
		return Boolean(inNode && inNode.getAttribute && inNode.getAttribute("idx"));
56
	},
57
	getCellNodeIndex: function(inCellNode){
58
		return inCellNode ? Number(inCellNode.getAttribute("idx")) : -1;
59
	},
60
	getCellNode: function(inRowNode, inCellIndex){
61
		for(var i=0, row; row=dojox.grid.getTr(inRowNode.firstChild, i); i++){
62
			for(var j=0, cell; cell=row.cells[j]; j++){
63
				if(this.getCellNodeIndex(cell) == inCellIndex){
64
					return cell;
65
				}
66
			}
67
		}
68
	},
69
	findCellTarget: function(inSourceNode, inTopNode){
70
		var n = inSourceNode;
71
		while(n && !this.isCellNode(n) && (n!=inTopNode)){
72
			n = n.parentNode;
73
		}
74
		return n!=inTopNode ? n : null
75
	},
76
	// event decoration
77
	baseDecorateEvent: function(e){
78
		e.dispatch = 'do' + e.type;
79
		e.grid = this.grid;
80
		e.sourceView = this.view;
81
		e.cellNode = this.findCellTarget(e.target, e.rowNode);
82
		e.cellIndex = this.getCellNodeIndex(e.cellNode);
83
		e.cell = (e.cellIndex >= 0 ? this.grid.getCell(e.cellIndex) : null);
84
	},
85
	// event dispatch
86
	findTarget: function(inSource, inTag){
87
		var n = inSource;
88
		while(n && !(inTag in n) && (n!=this.domNode)){
89
			n = n.parentNode;
90
		}
91
		return (n != this.domNode) ? n : null;
92
	},
93
	findRowTarget: function(inSource){
94
		return this.findTarget(inSource, dojox.grid.rowIndexTag);
95
	},
96
	isIntraNodeEvent: function(e){
97
		try{
98
			return (e.cellNode && e.relatedTarget && dojo.isDescendant(e.relatedTarget, e.cellNode));
99
		}catch(x){
100
			// e.relatedTarget has permission problem in FF if it's an input: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
101
			return false;
102
		}
103
	},
104
	isIntraRowEvent: function(e){
105
		try{
106
			var row = e.relatedTarget && this.findRowTarget(e.relatedTarget);
107
			return !row && (e.rowIndex==-1) || row && (e.rowIndex==row.gridRowIndex);
108
		}catch(x){
109
			// e.relatedTarget on INPUT has permission problem in FF: https://bugzilla.mozilla.org/show_bug.cgi?id=208427
110
			return false;
111
		}
112
	},
113
	dispatchEvent: function(e){
114
		if(e.dispatch in this){
115
			return this[e.dispatch](e);
116
		}
117
	},
118
	// dispatched event handlers
119
	domouseover: function(e){
120
		if(e.cellNode && (e.cellNode!=this.lastOverCellNode)){
121
			this.lastOverCellNode = e.cellNode;
122
			this.grid.onMouseOver(e);
123
		}
124
		this.grid.onMouseOverRow(e);
125
	},
126
	domouseout: function(e){
127
		if(e.cellNode && (e.cellNode==this.lastOverCellNode) && !this.isIntraNodeEvent(e, this.lastOverCellNode)){
128
			this.lastOverCellNode = null;
129
			this.grid.onMouseOut(e);
130
			if(!this.isIntraRowEvent(e)){
131
				this.grid.onMouseOutRow(e);
132
			}
133
		}
134
	}
135
});
136
 
137
dojo.declare("dojox.grid.contentBuilder", dojox.grid.Builder, {
138
	// summary:
139
	//	Produces html for grid data content. Owned by grid and used internally
140
	//	for rendering data. Override to implement custom rendering.
141
	update: function(){
142
		this.prepareHtml();
143
	},
144
	// cache html for rendering data rows
145
	prepareHtml: function(){
146
		var defaultGet=this.grid.get, rows=this.view.structure.rows;
147
		for(var j=0, row; (row=rows[j]); j++){
148
			for(var i=0, cell; (cell=row[i]); i++){
149
				cell.get = cell.get || (cell.value == undefined) && defaultGet;
150
				cell.markup = this.generateCellMarkup(cell, cell.cellStyles, cell.cellClasses, false);
151
			}
152
		}
153
	},
154
	// time critical: generate html using cache and data source
155
	generateHtml: function(inDataIndex, inRowIndex){
156
		var
157
			html = [ this._table ],
158
			v = this.view,
159
			obr = v.onBeforeRow,
160
			rows = v.structure.rows;
161
		obr && obr(inRowIndex, rows);
162
		for(var j=0, row; (row=rows[j]); j++){
163
			if(row.hidden || row.header){
164
				continue;
165
			}
166
			html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGrid-invisible">');
167
			for(var i=0, cell, m, cc, cs; (cell=row[i]); i++){
168
				m = cell.markup, cc = cell.customClasses = [], cs = cell.customStyles = [];
169
				// content (format can fill in cc and cs as side-effects)
170
				m[5] = cell.format(inDataIndex);
171
				// classes
172
				m[1] = cc.join(' ');
173
				// styles
174
				m[3] = cs.join(';');
175
				// in-place concat
176
				html.push.apply(html, m);
177
			}
178
			html.push('</tr>');
179
		}
180
		html.push('</table>');
181
		return html.join('');
182
	},
183
	decorateEvent: function(e){
184
		e.rowNode = this.findRowTarget(e.target);
185
		if(!e.rowNode){return false};
186
		e.rowIndex = e.rowNode[dojox.grid.rowIndexTag];
187
		this.baseDecorateEvent(e);
188
		e.cell = this.grid.getCell(e.cellIndex);
189
		return true;
190
	}
191
});
192
 
193
dojo.declare("dojox.grid.headerBuilder", dojox.grid.Builder, {
194
	// summary:
195
	//	Produces html for grid header content. Owned by grid and used internally
196
	//	for rendering data. Override to implement custom rendering.
197
	bogusClickTime: 0,
198
	overResizeWidth: 4,
199
	minColWidth: 1,
200
	_table: '<table class="dojoxGrid-row-table" border="0" cellspacing="0" cellpadding="0" role="wairole:presentation"',
201
	update: function(){
202
		this.tableMap = new dojox.grid.tableMap(this.view.structure.rows);
203
	},
204
	generateHtml: function(inGetValue, inValue){
205
		var html = [this._table], rows = this.view.structure.rows;
206
 
207
		// render header with appropriate width, if possible so that views with flex columns are correct height
208
		if(this.view.viewWidth){
209
			html.push([' style="width:', this.view.viewWidth, ';"'].join(''));
210
		}
211
		html.push('>');
212
		dojox.grid.fire(this.view, "onBeforeRow", [-1, rows]);
213
		for(var j=0, row; (row=rows[j]); j++){
214
			if(row.hidden){
215
				continue;
216
			}
217
			html.push(!row.invisible ? '<tr>' : '<tr class="dojoxGrid-invisible">');
218
			for(var i=0, cell, markup; (cell=row[i]); i++){
219
				cell.customClasses = [];
220
				cell.customStyles = [];
221
				markup = this.generateCellMarkup(cell, cell.headerStyles, cell.headerClasses, true);
222
				// content
223
				markup[5] = (inValue != undefined ? inValue : inGetValue(cell));
224
				// styles
225
				markup[3] = cell.customStyles.join(';');
226
				// classes
227
				markup[1] = cell.customClasses.join(' '); //(cell.customClasses ? ' ' + cell.customClasses : '');
228
				html.push(markup.join(''));
229
			}
230
			html.push('</tr>');
231
		}
232
		html.push('</table>');
233
		return html.join('');
234
	},
235
	// event helpers
236
	getCellX: function(e){
237
		var x = e.layerX;
238
		if(dojo.isMoz){
239
			var n = dojox.grid.ascendDom(e.target, dojox.grid.makeNotTagName("th"));
240
			x -= (n && n.offsetLeft) || 0;
241
			//x -= getProp(ascendDom(e.target, mkNotTagName("td")), "offsetLeft") || 0;
242
		}
243
		var n = dojox.grid.ascendDom(e.target, function(){
244
			if(!n || n == e.cellNode){
245
				return false;
246
			}
247
			// Mozilla 1.8 (FF 1.5) has a bug that makes offsetLeft = -parent border width
248
			// when parent has border, overflow: hidden, and is positioned
249
			// handle this problem here ... not a general solution!
250
			x += (n.offsetLeft < 0 ? 0 : n.offsetLeft);
251
			return true;
252
		});
253
		return x;
254
	},
255
	// event decoration
256
	decorateEvent: function(e){
257
		this.baseDecorateEvent(e);
258
		e.rowIndex = -1;
259
		e.cellX = this.getCellX(e);
260
		return true;
261
	},
262
	// event handlers
263
	// resizing
264
	prepareLeftResize: function(e){
265
		var i = dojox.grid.getTdIndex(e.cellNode);
266
		e.cellNode = (i ? e.cellNode.parentNode.cells[i-1] : null);
267
		e.cellIndex = (e.cellNode ? this.getCellNodeIndex(e.cellNode) : -1);
268
		return Boolean(e.cellNode);
269
	},
270
	canResize: function(e){
271
		if(!e.cellNode || e.cellNode.colSpan > 1){
272
			return false;
273
		}
274
		var cell = this.grid.getCell(e.cellIndex);
275
		return !cell.noresize && !cell.isFlex();
276
	},
277
	overLeftResizeArea: function(e){
278
		return (e.cellIndex>0) && (e.cellX < this.overResizeWidth) && this.prepareLeftResize(e);
279
	},
280
	overRightResizeArea: function(e){
281
		return e.cellNode && (e.cellX >= e.cellNode.offsetWidth - this.overResizeWidth);
282
	},
283
	domousemove: function(e){
284
		//console.log(e.cellIndex, e.cellX, e.cellNode.offsetWidth);
285
		var c = (this.overRightResizeArea(e) ? 'e-resize' : (this.overLeftResizeArea(e) ? 'w-resize' : ''));
286
		if(c && !this.canResize(e)){
287
			c = 'not-allowed';
288
		}
289
		e.sourceView.headerNode.style.cursor = c || ''; //'default';
290
	},
291
	domousedown: function(e){
292
		if(!dojox.grid.drag.dragging){
293
			if((this.overRightResizeArea(e) || this.overLeftResizeArea(e)) && this.canResize(e)){
294
				this.beginColumnResize(e);
295
			}
296
			//else{
297
			//	this.beginMoveColumn(e);
298
			//}
299
		}
300
	},
301
	doclick: function(e) {
302
		if (new Date().getTime() < this.bogusClickTime) {
303
			dojo.stopEvent(e);
304
			return true;
305
		}
306
	},
307
	// column resizing
308
	beginColumnResize: function(e){
309
		dojo.stopEvent(e);
310
		var spanners = [], nodes = this.tableMap.findOverlappingNodes(e.cellNode);
311
		for(var i=0, cell; (cell=nodes[i]); i++){
312
			spanners.push({ node: cell, index: this.getCellNodeIndex(cell), width: cell.offsetWidth });
313
			//console.log("spanner: " + this.getCellNodeIndex(cell));
314
		}
315
		var drag = {
316
			view: e.sourceView,
317
			node: e.cellNode,
318
			index: e.cellIndex,
319
			w: e.cellNode.clientWidth,
320
			spanners: spanners
321
		};
322
		//console.log(drag.index, drag.w);
323
		dojox.grid.drag.start(e.cellNode, dojo.hitch(this, 'doResizeColumn', drag), dojo.hitch(this, 'endResizeColumn', drag), e);
324
	},
325
	doResizeColumn: function(inDrag, inEvent){
326
		var w = inDrag.w + inEvent.deltaX;
327
		if(w >= this.minColWidth){
328
			for(var i=0, s, sw; (s=inDrag.spanners[i]); i++){
329
				sw = s.width + inEvent.deltaX;
330
				s.node.style.width = sw + 'px';
331
				inDrag.view.setColWidth(s.index, sw);
332
				//console.log('setColWidth', '#' + s.index, sw + 'px');
333
			}
334
			inDrag.node.style.width = w + 'px';
335
			inDrag.view.setColWidth(inDrag.index, w);
336
		}
337
		if(inDrag.view.flexCells && !inDrag.view.testFlexCells()){
338
			var t = dojox.grid.findTable(inDrag.node);
339
			t && (t.style.width = '');
340
		}
341
	},
342
	endResizeColumn: function(inDrag){
343
		this.bogusClickTime = new Date().getTime() + 30;
344
		setTimeout(dojo.hitch(inDrag.view, "update"), 50);
345
	}
346
});
347
 
348
dojo.declare("dojox.grid.tableMap", null, {
349
	// summary:
350
	//	Maps an html table into a structure parsable for information about cell row and col spanning.
351
	//	Used by headerBuilder
352
	constructor: function(inRows){
353
		this.mapRows(inRows);
354
	},
355
	map: null,
356
	// map table topography
357
	mapRows: function(inRows){
358
		//console.log('mapRows');
359
		// # of rows
360
		var rowCount = inRows.length;
361
		if(!rowCount){
362
			return;
363
		}
364
		// map which columns and rows fill which cells
365
		this.map = [ ];
366
		for(var j=0, row; (row=inRows[j]); j++){
367
			this.map[j] = [];
368
		}
369
		for(var j=0, row; (row=inRows[j]); j++){
370
			for(var i=0, x=0, cell, colSpan, rowSpan; (cell=row[i]); i++){
371
				while (this.map[j][x]){x++};
372
				this.map[j][x] = { c: i, r: j };
373
				rowSpan = cell.rowSpan || 1;
374
				colSpan = cell.colSpan || 1;
375
				for(var y=0; y<rowSpan; y++){
376
					for(var s=0; s<colSpan; s++){
377
						this.map[j+y][x+s] = this.map[j][x];
378
					}
379
				}
380
				x += colSpan;
381
			}
382
		}
383
		//this.dumMap();
384
	},
385
	dumpMap: function(){
386
		for(var j=0, row, h=''; (row=this.map[j]); j++,h=''){
387
			for(var i=0, cell; (cell=row[i]); i++){
388
				h += cell.r + ',' + cell.c + '   ';
389
			}
390
			console.log(h);
391
		}
392
	},
393
	// find node's map coords by it's structure coords
394
	getMapCoords: function(inRow, inCol){
395
		for(var j=0, row; (row=this.map[j]); j++){
396
			for(var i=0, cell; (cell=row[i]); i++){
397
				if(cell.c==inCol && cell.r == inRow){
398
					return { j: j, i: i };
399
				}
400
				//else{console.log(inRow, inCol, ' : ', i, j, " : ", cell.r, cell.c); };
401
			}
402
		}
403
		return { j: -1, i: -1 };
404
	},
405
	// find a node in inNode's table with the given structure coords
406
	getNode: function(inTable, inRow, inCol){
407
		var row = inTable && inTable.rows[inRow];
408
		return row && row.cells[inCol];
409
	},
410
	_findOverlappingNodes: function(inTable, inRow, inCol){
411
		var nodes = [];
412
		var m = this.getMapCoords(inRow, inCol);
413
		//console.log("node j: %d, i: %d", m.j, m.i);
414
		var row = this.map[m.j];
415
		for(var j=0, row; (row=this.map[j]); j++){
416
			if(j == m.j){ continue; }
417
			with(row[m.i]){
418
				//console.log("overlaps: r: %d, c: %d", r, c);
419
				var n = this.getNode(inTable, r, c);
420
				if(n){ nodes.push(n); }
421
			}
422
		}
423
		//console.log(nodes);
424
		return nodes;
425
	},
426
	findOverlappingNodes: function(inNode){
427
		return this._findOverlappingNodes(dojox.grid.findTable(inNode), dojox.grid.getTrIndex(inNode.parentNode), dojox.grid.getTdIndex(inNode));
428
	}
429
});
430
 
431
dojox.grid.rowIndexTag = "gridRowIndex";
432
 
433
}