summaryrefslogtreecommitdiff
path: root/frontend/beta/js/YUI-extensions/grid
Unidiff
Diffstat (limited to 'frontend/beta/js/YUI-extensions/grid') (more/less context) (ignore whitespace changes)
-rw-r--r--frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js131
-rw-r--r--frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js325
-rw-r--r--frontend/beta/js/YUI-extensions/grid/EditorGrid.js16
-rw-r--r--frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js182
-rw-r--r--frontend/beta/js/YUI-extensions/grid/Grid.js965
-rw-r--r--frontend/beta/js/YUI-extensions/grid/GridDD.js101
-rw-r--r--frontend/beta/js/YUI-extensions/grid/GridView.js790
-rw-r--r--frontend/beta/js/YUI-extensions/grid/PagedGridView.js194
-rw-r--r--frontend/beta/js/YUI-extensions/grid/SelectionModel.js445
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js91
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js60
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js268
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js166
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js37
-rw-r--r--frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js110
15 files changed, 3881 insertions, 0 deletions
diff --git a/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js b/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js
new file mode 100644
index 0000000..1f93590
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/AbstractColumnModel.js
@@ -0,0 +1,131 @@
1/**
2 * @class YAHOO.ext.grid.AbstractColumnModel
3 * @extends YAHOO.ext.util.Observable
4 * This abstract class defines the ColumnModel interface and provides default implementations of the events required by the Grid.
5 * @constructor
6*/
7YAHOO.ext.grid.AbstractColumnModel = function(){
8 // legacy events
9 this.onWidthChange = new YAHOO.util.CustomEvent('widthChanged');
10 this.onHeaderChange = new YAHOO.util.CustomEvent('headerChanged');
11 this.onHiddenChange = new YAHOO.util.CustomEvent('hiddenChanged');
12
13 this.events = {
14 /**
15 * @event widthchange
16 * Fires when the width of a column changes
17 * @param {ColumnModel} this
18 * @param {Number} columnIndex The column index
19 * @param {Number} newWidth The new width
20 */
21 'widthchange': this.onWidthChange,
22 /**
23 * @event headerchange
24 * Fires when the text of a header changes
25 * @param {ColumnModel} this
26 * @param {Number} columnIndex The column index
27 * @param {Number} newText The new header text
28 */
29 'headerchange': this.onHeaderChange,
30 /**
31 * @event hiddenchange
32 * Fires when a column is hidden or "unhidden"
33 * @param {ColumnModel} this
34 * @param {Number} columnIndex The column index
35 * @param {Number} hidden true if hidden, false otherwise
36 */
37 'hiddenchange': this.onHiddenChange
38 };
39};
40
41YAHOO.ext.grid.AbstractColumnModel.prototype = {
42 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
43 on : YAHOO.ext.util.Observable.prototype.on,
44 addListener : YAHOO.ext.util.Observable.prototype.addListener,
45 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
46 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
47 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
48 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
49
50 fireWidthChange : function(colIndex, newWidth){
51 this.onWidthChange.fireDirect(this, colIndex, newWidth);
52 },
53
54 fireHeaderChange : function(colIndex, newHeader){
55 this.onHeaderChange.fireDirect(this, colIndex, newHeader);
56 },
57
58 fireHiddenChange : function(colIndex, hidden){
59 this.onHiddenChange.fireDirect(this, colIndex, hidden);
60 },
61
62 /**
63 * Interface method - Returns the number of columns.
64 * @return {Number}
65 */
66 getColumnCount : function(){
67 return 0;
68 },
69
70 /**
71 * Interface method - Returns true if the specified column is sortable.
72 * @param {Number} col The column index
73 * @return {Boolean}
74 */
75 isSortable : function(col){
76 return false;
77 },
78
79 /**
80 * Interface method - Returns true if the specified column is hidden.
81 * @param {Number} col The column index
82 * @return {Boolean}
83 */
84 isHidden : function(col){
85 return false;
86 },
87
88 /**
89 * Interface method - Returns the sorting comparison function defined for the column (defaults to sortTypes.none).
90 * @param {Number} col The column index
91 * @return {Function}
92 */
93 getSortType : function(col){
94 return YAHOO.ext.grid.DefaultColumnModel.sortTypes.none;
95 },
96
97 /**
98 * Interface method - Returns the rendering (formatting) function defined for the column.
99 * @param {Number} col The column index
100 * @return {Function}
101 */
102 getRenderer : function(col){
103 return YAHOO.ext.grid.DefaultColumnModel.defaultRenderer;
104 },
105
106 /**
107 * Interface method - Returns the width for the specified column.
108 * @param {Number} col The column index
109 * @return {Number}
110 */
111 getColumnWidth : function(col){
112 return 0;
113 },
114
115 /**
116 * Interface method - Returns the total width of all columns.
117 * @return {Number}
118 */
119 getTotalWidth : function(){
120 return 0;
121 },
122
123 /**
124 * Interface method - Returns the header for the specified column.
125 * @param {Number} col The column index
126 * @return {String}
127 */
128 getColumnHeader : function(col){
129 return '';
130 }
131};
diff --git a/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js b/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js
new file mode 100644
index 0000000..fbdba26
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/DefaultColumnModel.js
@@ -0,0 +1,325 @@
1/**
2 * @class YAHOO.ext.grid.DefaultColumnModel
3 * @extends YAHOO.ext.grid.AbstractColumnModel
4 * This is the default implementation of a ColumnModel used by the Grid. It defines
5 * the columns in the grid.
6 * <br>Usage:<br>
7 <pre><code>
8 var sort = YAHOO.ext.grid.DefaultColumnModel.sortTypes;
9 var myColumns = [
10 {header: "Ticker", width: 60, sortable: true, sortType: sort.asUCString},
11 {header: "Company Name", width: 150, sortable: true, sortType: sort.asUCString},
12 {header: "Market Cap.", width: 100, sortable: true, sortType: sort.asFloat},
13 {header: "$ Sales", width: 100, sortable: true, sortType: sort.asFloat, renderer: money},
14 {header: "Employees", width: 100, sortable: true, sortType: sort.asFloat}
15 ];
16 var colModel = new YAHOO.ext.grid.DefaultColumnModel(myColumns);
17 </code></pre>
18 * @constructor
19 * @param {Object} config The config object
20*/
21YAHOO.ext.grid.DefaultColumnModel = function(config){
22 YAHOO.ext.grid.DefaultColumnModel.superclass.constructor.call(this);
23 /**
24 * The config passed into the constructor
25 */
26 this.config = config;
27
28 /**
29 * The width of columns which have no width specified (defaults to 100)
30 * @type Number
31 */
32 this.defaultWidth = 100;
33 /**
34 * Default sortable of columns which have no sortable specified (defaults to false)
35 * @type Boolean
36 */
37 this.defaultSortable = false;
38};
39YAHOO.extendX(YAHOO.ext.grid.DefaultColumnModel, YAHOO.ext.grid.AbstractColumnModel, {
40
41 /**
42 * Returns the number of columns.
43 * @return {Number}
44 */
45 getColumnCount : function(){
46 return this.config.length;
47 },
48
49 /**
50 * Returns true if the specified column is sortable.
51 * @param {Number} col The column index
52 * @return {Boolean}
53 */
54 isSortable : function(col){
55 if(typeof this.config[col].sortable == 'undefined'){
56 return this.defaultSortable;
57 }
58 return this.config[col].sortable;
59 },
60
61 /**
62 * Returns the sorting comparison function defined for the column (defaults to sortTypes.none).
63 * @param {Number} col The column index
64 * @return {Function}
65 */
66 getSortType : function(col){
67 if(!this.dataMap){
68 // build a lookup so we don't search every time
69 var map = [];
70 for(var i = 0, len = this.config.length; i < len; i++){
71 map[this.getDataIndex(i)] = i;
72 }
73 this.dataMap = map;
74 }
75 col = this.dataMap[col];
76 if(!this.config[col].sortType){
77 return YAHOO.ext.grid.DefaultColumnModel.sortTypes.none;
78 }
79 return this.config[col].sortType;
80 },
81
82 /**
83 * Sets the sorting comparison function for a column.
84 * @param {Number} col The column index
85 * @param {Function} fn
86 */
87 setSortType : function(col, fn){
88 this.config[col].sortType = fn;
89 },
90
91
92 /**
93 * Returns the rendering (formatting) function defined for the column.
94 * @param {Number} col The column index
95 * @return {Function}
96 */
97 getRenderer : function(col){
98 if(!this.config[col].renderer){
99 return YAHOO.ext.grid.DefaultColumnModel.defaultRenderer;
100 }
101 return this.config[col].renderer;
102 },
103
104 /**
105 * Sets the rendering (formatting) function for a column.
106 * @param {Number} col The column index
107 * @param {Function} fn
108 */
109 setRenderer : function(col, fn){
110 this.config[col].renderer = fn;
111 },
112
113 /**
114 * Returns the width for the specified column.
115 * @param {Number} col The column index
116 * @return {Number}
117 */
118 getColumnWidth : function(col){
119 return this.config[col].width || this.defaultWidth;
120 },
121
122 /**
123 * Sets the width for a column.
124 * @param {Number} col The column index
125 * @param {Number} width The new width
126 */
127 setColumnWidth : function(col, width, suppressEvent){
128 this.config[col].width = width;
129 this.totalWidth = null;
130 if(!suppressEvent){
131 this.onWidthChange.fireDirect(this, col, width);
132 }
133 },
134
135 /**
136 * Returns the total width of all columns.
137 * @param {Boolean} includeHidden True to include hidden column widths
138 * @return {Number}
139 */
140 getTotalWidth : function(includeHidden){
141 if(!this.totalWidth){
142 this.totalWidth = 0;
143 for(var i = 0; i < this.config.length; i++){
144 if(includeHidden || !this.isHidden(i)){
145 this.totalWidth += this.getColumnWidth(i);
146 }
147 }
148 }
149 return this.totalWidth;
150 },
151
152 /**
153 * Returns the header for the specified column.
154 * @param {Number} col The column index
155 * @return {String}
156 */
157 getColumnHeader : function(col){
158 return this.config[col].header;
159 },
160
161 /**
162 * Sets the header for a column.
163 * @param {Number} col The column index
164 * @param {String} header The new header
165 */
166 setColumnHeader : function(col, header){
167 this.config[col].header = header;
168 this.onHeaderChange.fireDirect(this, col, header);
169 },
170
171 /**
172 * Returns the tooltip for the specified column.
173 * @param {Number} col The column index
174 * @return {String}
175 */
176 getColumnTooltip : function(col){
177 return this.config[col].tooltip;
178 },
179 /**
180 * Sets the tooltip for a column.
181 * @param {Number} col The column index
182 * @param {String} tooltip The new tooltip
183 */
184 setColumnTooltip : function(col, header){
185 this.config[col].tooltip = tooltip;
186 },
187
188 /**
189 * Returns the dataIndex for the specified column.
190 * @param {Number} col The column index
191 * @return {Number}
192 */
193 getDataIndex : function(col){
194 if(typeof this.config[col].dataIndex != 'number'){
195 return col;
196 }
197 return this.config[col].dataIndex;
198 },
199
200 /**
201 * Sets the dataIndex for a column.
202 * @param {Number} col The column index
203 * @param {Number} dataIndex The new dataIndex
204 */
205 setDataIndex : function(col, dataIndex){
206 this.config[col].dataIndex = dataIndex;
207 },
208 /**
209 * Returns true if the cell is editable.
210 * @param {Number} colIndex The column index
211 * @param {Number} rowIndex The row index
212 * @return {Boolean}
213 */
214 isCellEditable : function(colIndex, rowIndex){
215 return this.config[colIndex].editable || (typeof this.config[colIndex].editable == 'undefined' && this.config[colIndex].editor);
216 },
217
218 /**
219 * Returns the editor defined for the cell/column.
220 * @param {Number} colIndex The column index
221 * @param {Number} rowIndex The row index
222 * @return {Object}
223 */
224 getCellEditor : function(colIndex, rowIndex){
225 return this.config[colIndex].editor;
226 },
227
228 /**
229 * Sets if a column is editable.
230 * @param {Number} col The column index
231 * @param {Boolean} editable True if the column is editable
232 */
233 setEditable : function(col, editable){
234 this.config[col].editable = editable;
235 },
236
237
238 /**
239 * Returns true if the column is hidden.
240 * @param {Number} colIndex The column index
241 * @return {Boolean}
242 */
243 isHidden : function(colIndex){
244 return this.config[colIndex].hidden;
245 },
246
247
248 /**
249 * Returns true if the column width cannot be changed
250 */
251 isFixed : function(colIndex){
252 return this.config[colIndex].fixed;
253 },
254
255 /**
256 * Returns true if the column cannot be resized
257 * @return {Boolean}
258 */
259 isResizable : function(colIndex){
260 return this.config[colIndex].resizable !== false;
261 },
262 /**
263 * Sets if a column is hidden.
264 * @param {Number} colIndex The column index
265 */
266 setHidden : function(colIndex, hidden){
267 this.config[colIndex].hidden = hidden;
268 this.totalWidth = null;
269 this.fireHiddenChange(colIndex, hidden);
270 },
271
272 /**
273 * Sets the editor for a column.
274 * @param {Number} col The column index
275 * @param {Object} editor The editor object
276 */
277 setEditor : function(col, editor){
278 this.config[col].editor = editor;
279 }
280});
281
282/**
283 * Defines the default sorting (casting?) comparison functions used when sorting data:
284 * <br>&nbsp;&nbsp;sortTypes.none - sorts data as it is without casting or parsing (the default)
285 * <br>&nbsp;&nbsp;sortTypes.asUCString - case insensitive string
286 * <br>&nbsp;&nbsp;sortTypes.asDate - attempts to parse data as a date
287 * <br>&nbsp;&nbsp;sortTypes.asFloat
288 * <br>&nbsp;&nbsp;sortTypes.asInt
289 * @static
290 */
291YAHOO.ext.grid.DefaultColumnModel.sortTypes = {
292 none : function(s) {
293 return s;
294 },
295
296 asUCString : function(s) {
297 return String(s).toUpperCase();
298 },
299
300 asDate : function(s) {
301 if(s instanceof Date){
302 return s.getTime();
303 }
304 return Date.parse(String(s));
305 },
306
307 asFloat : function(s) {
308 var val = parseFloat(String(s).replace(/,/g, ''));
309 if(isNaN(val)) val = 0;
310 return val;
311 },
312
313 asInt : function(s) {
314 var val = parseInt(String(s).replace(/,/g, ''));
315 if(isNaN(val)) val = 0;
316 return val;
317 }
318};
319
320YAHOO.ext.grid.DefaultColumnModel.defaultRenderer = function(value){
321 if(typeof value == 'string' && value.length < 1){
322 return '&#160;';
323 }
324 return value;
325}
diff --git a/frontend/beta/js/YUI-extensions/grid/EditorGrid.js b/frontend/beta/js/YUI-extensions/grid/EditorGrid.js
new file mode 100644
index 0000000..e7405a0
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/EditorGrid.js
@@ -0,0 +1,16 @@
1/**
2 * @class YAHOO.ext.grid.EditorGrid
3 * @extends YAHOO.ext.grid.Grid
4 * Shortcut class for creating and editable grid.
5 * @param {String/HTMLElement/YAHOO.ext.Element} container The element into which this grid will be rendered -
6 * The container MUST have some type of size defined for the grid to fill. The container will be
7 * automatically set to position relative if it isn't already.
8 * @param {Object} dataModel The data model to bind to
9 * @param {Object} colModel The column model with info about this grid's columns
10 */
11YAHOO.ext.grid.EditorGrid = function(container, dataModel, colModel){
12 YAHOO.ext.grid.EditorGrid.superclass.constructor.call(this, container, dataModel,
13 colModel, new YAHOO.ext.grid.EditorSelectionModel());
14 this.container.addClass('yeditgrid');
15};
16YAHOO.extendX(YAHOO.ext.grid.EditorGrid, YAHOO.ext.grid.Grid);
diff --git a/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js b/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js
new file mode 100644
index 0000000..c1cb240
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/EditorSelectionModel.js
@@ -0,0 +1,182 @@
1
2/**
3 @class YAHOO.ext.grid.EditorSelectionModel
4 * Extends {@link YAHOO.ext.grid.DefaultSelectionModel} to enable cell navigation. <br><br>
5 @extends YAHOO.ext.grid.DefaultSelectionModel
6 @constructor
7 */
8YAHOO.ext.grid.EditorSelectionModel = function(){
9 YAHOO.ext.grid.EditorSelectionModel.superclass.constructor.call(this);
10 /** Number of clicks to activate a cell (for editing) - valid values are 1 or 2
11 * @type Number */
12 this.clicksToActivateCell = 1;
13 this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
14};
15
16YAHOO.extendX(YAHOO.ext.grid.EditorSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
17
18YAHOO.ext.grid.EditorSelectionModel.prototype.disableArrowNavigation = false;
19YAHOO.ext.grid.EditorSelectionModel.prototype.controlForArrowNavigation = false;
20
21/** @ignore */
22YAHOO.ext.grid.EditorSelectionModel.prototype.initEvents = function(){
23 this.grid.addListener("cellclick", this.onCellClick, this, true);
24 this.grid.addListener("celldblclick", this.onCellDblClick, this, true);
25 this.grid.addListener("keydown", this.keyDown, this, true);
26};
27
28YAHOO.ext.grid.EditorSelectionModel.prototype.onCellClick = function(grid, rowIndex, colIndex){
29 if(this.clicksToActivateCell == 1){
30 var row = this.grid.getRow(rowIndex);
31 var cell = row.childNodes[colIndex];
32 if(cell){
33 this.activate(row, cell);
34 }
35 }
36};
37
38YAHOO.ext.grid.EditorSelectionModel.prototype.activate = function(row, cell){
39 this.fireEvent('cellactivate', this, row, cell);
40 this.grid.doEdit(row, cell);
41};
42
43YAHOO.ext.grid.EditorSelectionModel.prototype.onCellDblClick = function(grid, rowIndex, colIndex){
44 if(this.clicksToActivateCell == 2){
45 var row = this.grid.getRow(rowIndex);
46 var cell = row.childNodes[colIndex];
47 if(cell){
48 this.activate(row, cell);
49 }
50 }
51};
52
53/** @ignore */
54YAHOO.ext.grid.EditorSelectionModel.prototype.setRowState = function(row, selected){
55 YAHOO.ext.grid.EditorSelectionModel.superclass.setRowState.call(this, row, false, false);
56};
57/** @ignore */
58YAHOO.ext.grid.EditorSelectionModel.prototype.focusRow = function(row, selected){
59};
60
61YAHOO.ext.grid.EditorSelectionModel.prototype.getEditorCellAfter = function(cell, spanRows){
62 var g = this.grid;
63 var next = g.getCellAfter(cell);
64 while(next && !g.colModel.isCellEditable(next.columnIndex)){
65 next = g.getCellAfter(next);
66 }
67 if(!next && spanRows){
68 var row = g.getRowAfter(g.getRowFromChild(cell));
69 if(row){
70 next = g.getFirstCell(row);
71 if(!g.colModel.isCellEditable(next.columnIndex)){
72 next = this.getEditorCellAfter(next);
73 }
74 }
75 }
76 return next;
77};
78
79YAHOO.ext.grid.EditorSelectionModel.prototype.getEditorCellBefore = function(cell, spanRows){
80 var g = this.grid;
81 var prev = g.getCellBefore(cell);
82 while(prev && !g.colModel.isCellEditable(prev.columnIndex)){
83 prev = g.getCellBefore(prev);
84 }
85 if(!prev && spanRows){
86 var row = g.getRowBefore(g.getRowFromChild(cell));
87 if(row){
88 prev = g.getLastCell(row);
89 if(!g.colModel.isCellEditable(prev.columnIndex)){
90 prev = this.getEditorCellBefore(prev);
91 }
92 }
93 }
94 return prev;
95};
96
97YAHOO.ext.grid.EditorSelectionModel.prototype.allowArrowNav = function(e){
98 return (!this.disableArrowNavigation && (!this.controlForArrowNavigation || e.ctrlKey));
99}
100/** @ignore */
101YAHOO.ext.grid.EditorSelectionModel.prototype.keyDown = function(e){
102 var g = this.grid, cm = g.colModel, cell = g.getEditingCell();
103 if(!cell) return;
104 var newCell;
105 switch(e.browserEvent.keyCode){
106 case e.TAB:
107 if(e.shiftKey){
108 newCell = this.getEditorCellBefore(cell, true);
109 }else{
110 newCell = this.getEditorCellAfter(cell, true);
111 }
112 e.preventDefault();
113 break;
114 case e.DOWN:
115 if(this.allowArrowNav(e)){
116 var next = g.getRowAfter(g.getRowFromChild(cell));
117 if(next){
118 newCell = next.childNodes[cell.columnIndex];
119 }
120 }
121 break;
122 case e.UP:
123 if(this.allowArrowNav(e)){
124 var prev = g.getRowBefore(g.getRowFromChild(cell));
125 if(prev){
126 newCell = prev.childNodes[cell.columnIndex];
127 }
128 }
129 break;
130 case e.RETURN:
131 if(e.shiftKey){
132 var prev = g.getRowBefore(g.getRowFromChild(cell));
133 if(prev){
134 newCell = prev.childNodes[cell.columnIndex];
135 }
136 }else{
137 var next = g.getRowAfter(g.getRowFromChild(cell));
138 if(next){
139 newCell = next.childNodes[cell.columnIndex];
140 }
141 }
142 break;
143 case e.RIGHT:
144 if(this.allowArrowNav(e)){
145 newCell = this.getEditorCellAfter(cell);
146 }
147 break;
148 case e.LEFT:
149 if(this.allowArrowNav(e)){
150 newCell = this.getEditorCellBefore(cell);
151 }
152 break;
153 };
154 if(newCell){
155 this.activate(g.getRowFromChild(newCell), newCell);
156 e.stopEvent();
157 }
158};
159
160/**
161 * @class YAHOO.ext.grid.EditorAndSelectionModel
162 */
163YAHOO.ext.grid.EditorAndSelectionModel = function(){
164 YAHOO.ext.grid.EditorAndSelectionModel.superclass.constructor.call(this);
165 this.events['cellactivate'] = new YAHOO.util.CustomEvent('cellactivate');
166};
167
168YAHOO.extendX(YAHOO.ext.grid.EditorAndSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
169
170YAHOO.ext.grid.EditorAndSelectionModel.prototype.initEvents = function(){
171 YAHOO.ext.grid.EditorAndSelectionModel.superclass.initEvents.call(this);
172 this.grid.addListener("celldblclick", this.onCellDblClick, this, true);
173};
174
175YAHOO.ext.grid.EditorAndSelectionModel.prototype.onCellDblClick = function(grid, rowIndex, colIndex){
176 var row = this.grid.getRow(rowIndex);
177 var cell = row.childNodes[colIndex];
178 if(cell){
179 this.fireEvent('cellactivate', this, row, cell);
180 this.grid.doEdit(row, cell);
181 }
182};
diff --git a/frontend/beta/js/YUI-extensions/grid/Grid.js b/frontend/beta/js/YUI-extensions/grid/Grid.js
new file mode 100644
index 0000000..46d5de4
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/Grid.js
@@ -0,0 +1,965 @@
1/**
2 * @class YAHOO.ext.grid.Grid
3 * @extends YAHOO.ext.util.Observable
4 * This class represents the primary interface of a component based grid control.
5 * <br><br>Usage:<pre><code>
6 var grid = new YAHOO.ext.grid.Grid('my-container-id', dataModel, columnModel);
7 // set any options
8 grid.render();
9 // or using a config
10 var grid = new YAHOO.ext.grid.Grid('my-container-id', {
11 dataModel: myDataModel,
12 colModel: myColModel,
13 selModel: mySelectionModel,
14 autoSizeColumns: true,
15 monitorWindowResize: false,
16 trackMouseOver: true
17 }).render();
18 * </code></pre>
19 * <b>Common Problems:</b><br/>
20 * - Grid does not resize properly when going smaller: Setting overflow hidden on the container
21 * element will correct this<br/>
22 * - If you get el.style[camel]= NaNpx or -2px or something related, be certain you have given your container element
23 * dimensions. The grid adapts to your container's size, if your container has no size defined then the results
24 * are unpredictable.<br/>
25 * - Do not render the grid into an element with display:none. Try using visibility:hidden. Otherwise there is no way for the
26 * grid to calculate dimensions/offsets.<br/>
27 * @requires YAHOO.util.Dom
28 * @requires YAHOO.util.Event
29 * @requires YAHOO.util.CustomEvent
30 * @requires YAHOO.ext.Element
31 * @requires YAHOO.ext.util.Browser
32 * @requires YAHOO.ext.util.CSS
33 * @requires YAHOO.ext.SplitBar
34 * @requires YAHOO.ext.EventObject
35 * @constructor
36 * @param {String/HTMLElement/YAHOO.ext.Element} container The element into which this grid will be rendered -
37 * The container MUST have some type of size defined for the grid to fill. The container will be
38 * automatically set to position relative if it isn't already.
39 * @param {Object} config A config object that sets properties on this grid OR the data model to bind to
40 * @param {Object} colModel (optional) The column model with info about this grid's columns
41 * @param {Object} selectionModel (optional) The selection model for this grid (defaults to DefaultSelectionModel)
42 */
43YAHOO.ext.grid.Grid = function(container, config, colModel, selectionModel){
44 /** @private */
45 this.container = YAHOO.ext.Element.get(container);
46 this.container.update('');
47 this.container.setStyle('overflow', 'hidden');
48 this.id = this.container.id;
49 this.rows = [];
50 this.rowCount = 0;
51 this.fieldId = null;
52 var dataModel = config; // for legacy pre config support
53 this.dataModel = dataModel;
54 this.colModel = colModel;
55 this.selModel = selectionModel;
56 this.activeEditor = null;
57 this.editingCell = null;
58
59
60 if(typeof config == 'object' && !config.getRowCount){// must be config object
61 YAHOO.ext.util.Config.apply(this, config);
62 }
63
64 /** @private */
65 this.setValueDelegate = this.setCellValue.createDelegate(this);
66
67 /** @private */
68 this.events = {
69 // raw events
70 /**
71 * @event click
72 * The raw click event for the entire grid.
73 * @param {YAHOO.ext.EventObject} e
74 */
75 'click' : true,
76 /**
77 * @event dblclick
78 * The raw dblclick event for the entire grid.
79 * @param {YAHOO.ext.EventObject} e
80 */
81 'dblclick' : true,
82 /**
83 * @event mousedown
84 * The raw mousedown event for the entire grid.
85 * @param {YAHOO.ext.EventObject} e
86 */
87 'mousedown' : true,
88 /**
89 * @event mouseup
90 * The raw mouseup event for the entire grid.
91 * @param {YAHOO.ext.EventObject} e
92 */
93 'mouseup' : true,
94 /**
95 * @event mouseover
96 * The raw mouseover event for the entire grid.
97 * @param {YAHOO.ext.EventObject} e
98 */
99 'mouseover' : true,
100 /**
101 * @event mouseout
102 * The raw mouseout event for the entire grid.
103 * @param {YAHOO.ext.EventObject} e
104 */
105 'mouseout' : true,
106 /**
107 * @event keypress
108 * The raw keypress event for the entire grid.
109 * @param {YAHOO.ext.EventObject} e
110 */
111 'keypress' : true,
112 /**
113 * @event keydown
114 * The raw keydown event for the entire grid.
115 * @param {YAHOO.ext.EventObject} e
116 */
117 'keydown' : true,
118
119 // custom events
120
121 /**
122 * @event cellclick
123 * Fires when a cell is clicked
124 * @param {Grid} this
125 * @param {Number} rowIndex
126 * @param {Number} columnIndex
127 * @param {YAHOO.ext.EventObject} e
128 */
129 'cellclick' : true,
130 /**
131 * @event celldblclick
132 * Fires when a cell is double clicked
133 * @param {Grid} this
134 * @param {Number} rowIndex
135 * @param {Number} columnIndex
136 * @param {YAHOO.ext.EventObject} e
137 */
138 'celldblclick' : true,
139 /**
140 * @event rowclick
141 * Fires when a row is clicked
142 * @param {Grid} this
143 * @param {Number} rowIndex
144 * @param {YAHOO.ext.EventObject} e
145 */
146 'rowclick' : true,
147 /**
148 * @event rowdblclick
149 * Fires when a row is double clicked
150 * @param {Grid} this
151 * @param {Number} rowIndex
152 * @param {YAHOO.ext.EventObject} e
153 */
154 'rowdblclick' : true,
155 /**
156 * @event headerclick
157 * Fires when a header is clicked
158 * @param {Grid} this
159 * @param {Number} columnIndex
160 * @param {YAHOO.ext.EventObject} e
161 */
162 'headerclick' : true,
163 /**
164 * @event rowcontextmenu
165 * Fires when a row is right clicked
166 * @param {Grid} this
167 * @param {Number} rowIndex
168 * @param {YAHOO.ext.EventObject} e
169 */
170 'rowcontextmenu' : true,
171 /**
172 * @event cellcontextmenu
173 * Fires when a cell is right clicked
174 * @param {Grid} this
175 * @param {Number} rowIndex
176 * @param {Number} cellIndex
177 * @param {YAHOO.ext.EventObject} e
178 */
179 'cellcontextmenu' : true,
180 /**
181 * @event headercontextmenu
182 * Fires when a header is right clicked
183 * @param {Grid} this
184 * @param {Number} columnIndex
185 * @param {YAHOO.ext.EventObject} e
186 */
187 'headercontextmenu' : true,
188 /**
189 * @event beforeedit
190 * Fires before a cell is edited
191 * @param {Grid} this
192 * @param {Number} rowIndex
193 * @param {Number} columnIndex
194 */
195 'beforeedit' : true,
196 /**
197 * @event afteredit
198 * Fires after a cell is edited
199 * @param {Grid} this
200 * @param {Number} rowIndex
201 * @param {Number} columnIndex
202 */
203 'afteredit' : true,
204 /**
205 * @event bodyscroll
206 * Fires when the body element is scrolled
207 * @param {Number} scrollLeft
208 * @param {Number} scrollTop
209 */
210 'bodyscroll' : true,
211 /**
212 * @event columnresize
213 * Fires when the user resizes a column
214 * @param {Number} columnIndex
215 * @param {Number} newSize
216 */
217 'columnresize' : true,
218 /**
219 * @event startdrag
220 * Fires when row(s) start being dragged
221 * @param {Grid} this
222 * @param {YAHOO.ext.GridDD} dd The drag drop object
223 * @param {event} e The raw browser event
224 */
225 'startdrag' : true,
226 /**
227 * @event enddrag
228 * Fires when a drag operation is complete
229 * @param {Grid} this
230 * @param {YAHOO.ext.GridDD} dd The drag drop object
231 * @param {event} e The raw browser event
232 */
233 'enddrag' : true,
234 /**
235 * @event dragdrop
236 * Fires when dragged row(s) are dropped on a valid DD target
237 * @param {Grid} this
238 * @param {YAHOO.ext.GridDD} dd The drag drop object
239 * @param {String} targetId The target drag drop object
240 * @param {event} e The raw browser event
241 */
242 'dragdrop' : true,
243 /**
244 * @event dragover
245 * Fires while row(s) are being dragged. "targetId" is the id of the Yahoo.util.DD object the selected rows are being dragged over.
246 * @param {Grid} this
247 * @param {YAHOO.ext.GridDD} dd The drag drop object
248 * @param {String} targetId The target drag drop object
249 * @param {event} e The raw browser event
250 */
251 'dragover' : true,
252 /**
253 * @event dragenter
254 * Fires when the dragged row(s) first cross another DD target while being dragged
255 * @param {Grid} this
256 * @param {YAHOO.ext.GridDD} dd The drag drop object
257 * @param {String} targetId The target drag drop object
258 * @param {event} e The raw browser event
259 */
260 'dragenter' : true,
261 /**
262 * @event dragout
263 * Fires when the dragged row(s) leave another DD target while being dragged
264 * @param {Grid} this
265 * @param {YAHOO.ext.GridDD} dd The drag drop object
266 * @param {String} targetId The target drag drop object
267 * @param {event} e The raw browser event
268 */
269 'dragout' : true
270 };
271};
272
273YAHOO.ext.grid.Grid.prototype = {
274 /** The minimum width a column can be resized to. (Defaults to 25)
275 * @type Number */
276 minColumnWidth : 25,
277
278 /** True to automatically resize the columns to fit their content <b>on initial render</b>
279 * @type Boolean */
280 autoSizeColumns : false,
281
282 /** True to measure headers with column data when auto sizing columns
283 * @type Boolean */
284 autoSizeHeaders : false,
285
286 /**
287 * True to autoSize the grid when the window resizes - defaults to true
288 */
289 monitorWindowResize : true,
290
291 /** If autoSizeColumns is on, maxRowsToMeasure can be used to limit the number of
292 * rows measured to get a columns size - defaults to 0 (all rows).
293 * @type Number */
294 maxRowsToMeasure : 0,
295
296 /** True to highlight rows when the mouse is over (default is false)
297 * @type Boolean */
298 trackMouseOver : false,
299
300 /** True to enable drag and drop of rows
301 * @type Boolean */
302 enableDragDrop : false,
303
304 /** True to stripe the rows (default is true)
305 * @type Boolean */
306 stripeRows : true,
307 /** True to fit the height of the grid container to the height of the data (defaults to false)
308 * @type Boolean */
309 autoHeight : false,
310
311 /** True to fit the width of the grid container to the width of the columns (defaults to false)
312 * @type Boolean */
313 autoWidth : false,
314
315 /**
316 * The view used by the grid. This can be set before a call to render().
317 * Defaults to a YAHOO.ext.grid.GridView or PagedGridView depending on the data model.
318 * @type Object
319 */
320 view : null,
321
322 /** A regular expression defining tagNames
323 * allowed to have text selection (Defaults to <code>/INPUT|TEXTAREA|SELECT/i</code>) */
324 allowTextSelectionPattern : /INPUT|TEXTAREA|SELECT/i,
325
326 /**
327 * Called once after all setup has been completed and the grid is ready to be rendered.
328 * @return {YAHOO.ext.grid.Grid} this
329 */
330 render : function(){
331 if((!this.container.dom.offsetHeight || this.container.dom.offsetHeight < 20)
332 || this.container.getStyle('height') == 'auto'){
333 this.autoHeight = true;
334 }
335 if((!this.container.dom.offsetWidth || this.container.dom.offsetWidth < 20)){
336 this.autoWidth = true;
337 }
338 if(!this.view){
339 if(this.dataModel.isPaged()){
340 this.view = new YAHOO.ext.grid.PagedGridView();
341 }else{
342 this.view = new YAHOO.ext.grid.GridView();
343 }
344 }
345 this.view.init(this);
346 this.el = getEl(this.view.render(), true);
347 var c = this.container;
348 c.mon("click", this.onClick, this, true);
349 c.mon("dblclick", this.onDblClick, this, true);
350 c.mon("contextmenu", this.onContextMenu, this, true);
351 c.mon("selectstart", this.cancelTextSelection, this, true);
352 c.mon("mousedown", this.cancelTextSelection, this, true);
353 c.mon("mousedown", this.onMouseDown, this, true);
354 c.mon("mouseup", this.onMouseUp, this, true);
355 if(this.trackMouseOver){
356 this.el.mon("mouseover", this.onMouseOver, this, true);
357 this.el.mon("mouseout", this.onMouseOut, this, true);
358 }
359 c.mon("keypress", this.onKeyPress, this, true);
360 c.mon("keydown", this.onKeyDown, this, true);
361 this.init();
362 return this;
363 },
364
365 init : function(){
366 this.rows = this.el.dom.rows;
367 if(!this.disableSelection){
368 if(!this.selModel){
369 this.selModel = new YAHOO.ext.grid.DefaultSelectionModel(this);
370 }
371 this.selModel.init(this);
372 this.selModel.onSelectionChange.subscribe(this.updateField, this, true);
373 }else{
374 this.selModel = new YAHOO.ext.grid.DisableSelectionModel(this);
375 this.selModel.init(this);
376 }
377
378 if(this.enableDragDrop){
379 this.dd = new YAHOO.ext.grid.GridDD(this, this.container.dom);
380 }
381 },
382
383 /**
384 * Resets the grid for use with a new configuration and/or data and column models. After calling this function
385 * you will need to call render() again. Any listeners for this grid will be retained.
386 * Warning: any listeners manually attached (not through the grid) to the grid's container
387 * element will be removed.
388 * @param {Object} config Standard config object with properties to set on this grid
389 * @return {YAHOO.ext.grid.Grid} this
390 */
391 reset : function(config){
392 this.destroy(false, true);
393 YAHOO.ext.util.Config.apply(this, config);
394 return this;
395 },
396
397 /**
398 * Destroy this grid.
399 * @param {Boolean} removeEl True to remove the element
400 */
401 destroy : function(removeEl, keepListeners){
402 var c = this.container;
403 c.removeAllListeners();
404 this.view.destroy();
405 YAHOO.ext.EventManager.removeResizeListener(this.view.onWindowResize, this.view);
406 this.view = null;
407 this.colModel.purgeListeners();
408 if(!keepListeners){
409 this.purgeListeners();
410 }
411 c.update('');
412 if(removeEl === true){
413 c.remove();
414 }
415 },
416
417 /**
418 * Replace the current data model with a new one (experimental)
419 * @param {DataModel} dm The new data model
420 * @pram {Boolean} rerender true to render the grid rows from scratch
421 */
422 setDataModel : function(dm, rerender){
423 this.view.unplugDataModel(this.dataModel);
424 this.dataModel = dm;
425 this.view.plugDataModel(dm);
426 if(rerender){
427 dm.fireEvent('datachanged');
428 }
429 },
430
431 onMouseDown : function(e){
432 this.fireEvent('mousedown', e);
433 },
434
435 onMouseUp : function(e){
436 this.fireEvent('mouseup', e);
437 },
438
439 onMouseOver : function(e){
440 this.fireEvent('mouseover', e);
441 },
442
443 onMouseOut : function(e){
444 this.fireEvent('mouseout', e);
445 },
446
447 onKeyPress : function(e){
448 this.fireEvent('keypress', e);
449 },
450
451 onKeyDown : function(e){
452 this.fireEvent('keydown', e);
453 },
454
455 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
456 on : YAHOO.ext.util.Observable.prototype.on,
457 addListener : YAHOO.ext.util.Observable.prototype.addListener,
458 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
459 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
460 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
461 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
462
463 onClick : function(e){
464 this.fireEvent('click', e);
465 var target = e.getTarget();
466 var row = this.getRowFromChild(target);
467 var cell = this.getCellFromChild(target);
468 var header = this.getHeaderFromChild(target);
469 if(cell){
470 this.fireEvent('cellclick', this, row.rowIndex, cell.columnIndex, e);
471 }
472 if(row){
473 this.fireEvent('rowclick', this, row.rowIndex, e);
474 }
475 if(header){
476 this.fireEvent('headerclick', this, header.columnIndex, e);
477 }
478 },
479
480 onContextMenu : function(e){
481 var target = e.getTarget();
482 var row = this.getRowFromChild(target);
483 var cell = this.getCellFromChild(target);
484 var header = this.getHeaderFromChild(target);
485 if(cell){
486 this.fireEvent('cellcontextmenu', this, row.rowIndex, cell.columnIndex, e);
487 }
488 if(row){
489 this.fireEvent('rowcontextmenu', this, row.rowIndex, e);
490 }
491 if(header){
492 this.fireEvent('headercontextmenu', this, header.columnIndex, e);
493 }
494 e.preventDefault();
495 },
496
497 onDblClick : function(e){
498 this.fireEvent('dblclick', e);
499 var target = e.getTarget();
500 var row = this.getRowFromChild(target);
501 var cell = this.getCellFromChild(target);
502 if(row){
503 this.fireEvent('rowdblclick', this, row.rowIndex, e);
504 }
505 if(cell){
506 this.fireEvent('celldblclick', this, row.rowIndex, cell.columnIndex, e);
507 }
508 },
509
510 /**
511 * Starts editing the specified for the specified row/column
512 * @param {Number} rowIndex
513 * @param {Number} colIndex
514 */
515 startEditing : function(rowIndex, colIndex){
516 var row = this.rows[rowIndex];
517 var cell = row.childNodes[colIndex];
518 this.stopEditing();
519 setTimeout(this.doEdit.createDelegate(this, [row, cell]), 10);
520 },
521
522 /**
523 * Stops any active editing
524 */
525 stopEditing : function(){
526 if(this.activeEditor){
527 this.activeEditor.stopEditing();
528 }
529 },
530
531 /** @ignore */
532 doEdit : function(row, cell){
533 if(!row || !cell) return;
534 var cm = this.colModel;
535 var dm = this.dataModel;
536 var colIndex = cell.columnIndex;
537 var rowIndex = row.rowIndex;
538 if(cm.isCellEditable(colIndex, rowIndex)){
539 var ed = cm.getCellEditor(colIndex, rowIndex);
540 if(ed){
541 if(this.activeEditor){
542 this.activeEditor.stopEditing();
543 }
544 this.fireEvent('beforeedit', this, rowIndex, colIndex);
545 this.activeEditor = ed;
546 this.editingCell = cell;
547 this.view.ensureVisible(row, true);
548 try{
549 cell.focus();
550 }catch(e){}
551 ed.init(this, this.el.dom.parentNode, this.setValueDelegate);
552 var value = dm.getValueAt(rowIndex, cm.getDataIndex(colIndex));
553 // set timeout so firefox stops editing before starting a new edit
554 setTimeout(ed.startEditing.createDelegate(ed, [value, row, cell]), 1);
555 }
556 }
557 },
558
559 setCellValue : function(value, rowIndex, colIndex){
560 this.dataModel.setValueAt(value, rowIndex, this.colModel.getDataIndex(colIndex));
561 this.fireEvent('afteredit', this, rowIndex, colIndex);
562 },
563
564 /** @ignore Called when text selection starts or mousedown to prevent default */
565 cancelTextSelection : function(e){
566 var target = e.getTarget();
567 if(target && target != this.el.dom.parentNode && !this.allowTextSelectionPattern.test(target.tagName)){
568 e.preventDefault();
569 }
570 },
571
572 /**
573 * Causes the grid to manually recalculate it's dimensions. Generally this is done automatically,
574 * but if manual update is required this method will initiate it.
575 */
576 autoSize : function(){
577 this.view.updateWrapHeight();
578 this.view.adjustForScroll();
579 },
580
581 /**
582 * Scrolls the grid to the specified row
583 * @param {Number/HTMLElement} row The row object or index of the row
584 */
585 scrollTo : function(row){
586 if(typeof row == 'number'){
587 row = this.rows[row];
588 }
589 this.view.ensureVisible(row, true);
590 },
591
592 /** @private */
593 getEditingCell : function(){
594 return this.editingCell;
595 },
596
597 /**
598 * Binds this grid to the field with the specified id. Initially reads and parses the comma
599 * delimited ids in the field and selects those items. All selections made in the grid
600 * will be persisted to the field by their ids comma delimited.
601 * @param {String} The id of the field to bind to
602 */
603 bindToField : function(fieldId){
604 this.fieldId = fieldId;
605 this.readField();
606 },
607
608 /** @private */
609 updateField : function(){
610 if(this.fieldId){
611 var field = YAHOO.util.Dom.get(this.fieldId);
612 field.value = this.getSelectedRowIds().join(',');
613 }
614 },
615
616 /**
617 * Causes the grid to read and select the ids from the bound field - See {@link #bindToField}.
618 */
619 readField : function(){
620 if(this.fieldId){
621 var field = YAHOO.util.Dom.get(this.fieldId);
622 var values = field.value.split(',');
623 var rows = this.getRowsById(values);
624 this.selModel.selectRows(rows, false);
625 }
626 },
627
628 /**
629 * Returns the table row at the specified index
630 * @param {Number} index
631 * @return {HTMLElement}
632 */
633 getRow : function(index){
634 return this.rows[index];
635 },
636
637 /**
638 * Returns the rows that have the specified id(s). The id value for a row is provided
639 * by the DataModel. See {@link YAHOO.ext.grid.DefaultDataModel#getRowId}.
640 * @param {String/Array} An id to find or an array of ids
641 * @return {HtmlElement/Array} If one id was passed in, it returns one result.
642 * If an array of ids was specified, it returns an Array of HTMLElements
643 */
644 getRowsById : function(id){
645 var dm = this.dataModel;
646 if(!(id instanceof Array)){
647 for(var i = 0; i < this.rows.length; i++){
648 if(dm.getRowId(i) == id){
649 return this.rows[i];
650 }
651 }
652 return null;
653 }
654 var found = [];
655 var re = "^(?:";
656 for(var i = 0; i < id.length; i++){
657 re += id[i];
658 if(i != id.length-1) re += "|";
659 }
660 var regex = new RegExp(re + ")$");
661 for(var i = 0; i < this.rows.length; i++){
662 if(regex.test(dm.getRowId(i))){
663 found.push(this.rows[i]);
664 }
665 }
666 return found;
667 },
668
669 /**
670 * Returns the row that comes after the specified row - text nodes are skipped.
671 * @param {HTMLElement} row
672 * @return {HTMLElement}
673 */
674 getRowAfter : function(row){
675 return this.getSibling('next', row);
676 },
677
678 /**
679 * Returns the row that comes before the specified row - text nodes are skipped.
680 * @param {HTMLElement} row
681 * @return {HTMLElement}
682 */
683 getRowBefore : function(row){
684 return this.getSibling('previous', row);
685 },
686
687 /**
688 * Returns the cell that comes after the specified cell - text nodes are skipped.
689 * @param {HTMLElement} cell
690 * @param {Boolean} includeHidden
691 * @return {HTMLElement}
692 */
693 getCellAfter : function(cell, includeHidden){
694 var next = this.getSibling('next', cell);
695 if(next && !includeHidden && this.colModel.isHidden(next.columnIndex)){
696 return this.getCellAfter(next);
697 }
698 return next;
699 },
700
701 /**
702 * Returns the cell that comes before the specified cell - text nodes are skipped.
703 * @param {HTMLElement} cell
704 * @param {Boolean} includeHidden
705 * @return {HTMLElement}
706 */
707 getCellBefore : function(cell, includeHidden){
708 var prev = this.getSibling('previous', cell);
709 if(prev && !includeHidden && this.colModel.isHidden(prev.columnIndex)){
710 return this.getCellBefore(prev);
711 }
712 return prev;
713 },
714
715 /**
716 * Returns the last cell for the row - text nodes and hidden columns are skipped.
717 * @param {HTMLElement} row
718 * @param {Boolean} includeHidden
719 * @return {HTMLElement}
720 */
721 getLastCell : function(row, includeHidden){
722 var cell = this.getElement('previous', row.lastChild);
723 if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
724 return this.getCellBefore(cell);
725 }
726 return cell;
727 },
728
729 /**
730 * Returns the first cell for the row - text nodes and hidden columns are skipped.
731 * @param {HTMLElement} row
732 * @param {Boolean} includeHidden
733 * @return {HTMLElement}
734 */
735 getFirstCell : function(row, includeHidden){
736 var cell = this.getElement('next', row.firstChild);
737 if(cell && !includeHidden && this.colModel.isHidden(cell.columnIndex)){
738 return this.getCellAfter(cell);
739 }
740 return cell;
741 },
742
743 /**
744 * @private
745 * Gets siblings, skipping text nodes
746 * @param {String} type The direction to walk: 'next' or 'previous'
747 * @param {HTMLElement} node
748 */
749 getSibling : function(type, node){
750 if(!node) return null;
751 type += 'Sibling';
752 var n = node[type];
753 while(n && n.nodeType != 1){
754 n = n[type];
755 }
756 return n;
757 },
758
759 /**
760 * Returns node if node is an HTMLElement else walks the siblings in direction looking for
761 * a node that is an element
762 * @param {String} direction The direction to walk: 'next' or 'previous'
763 * @private
764 */
765 getElement : function(direction, node){
766 if(!node || node.nodeType == 1) return node;
767 else return this.getSibling(direction, node);
768 },
769
770 /**
771 * @private
772 */
773 getElementFromChild : function(childEl, parentClass){
774 if(!childEl || (YAHOO.util.Dom.hasClass(childEl, parentClass))){
775 return childEl;
776 }
777 var p = childEl.parentNode;
778 var b = document.body;
779 while(p && p != b){
780 if(YAHOO.util.Dom.hasClass(p, parentClass)){
781 return p;
782 }
783 p = p.parentNode;
784 }
785 return null;
786 },
787
788 /**
789 * Returns the row that contains the specified child element.
790 * @param {HTMLElement} childEl
791 * @return {HTMLElement}
792 */
793 getRowFromChild : function(childEl){
794 return this.getElementFromChild(childEl, 'ygrid-row');
795 },
796
797 /**
798 * Returns the cell that contains the specified child element.
799 * @param {HTMLElement} childEl
800 * @return {HTMLElement}
801 */
802 getCellFromChild : function(childEl){
803 return this.getElementFromChild(childEl, 'ygrid-col');
804 },
805
806
807 /**
808 * Returns the header element that contains the specified child element.
809 * @param {HTMLElement} childEl
810 * @return {HTMLElement}
811 */
812 getHeaderFromChild : function(childEl){
813 return this.getElementFromChild(childEl, 'ygrid-hd');
814 },
815
816 /**
817 * Convenience method for getSelectionModel().getSelectedRows() -
818 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
819 * @return {Array}
820 */
821 getSelectedRows : function(){
822 return this.selModel.getSelectedRows();
823 },
824
825 /**
826 * Convenience method for getSelectionModel().getSelectedRows()[0] -
827 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRows}</small> for more details.
828 * @return {HTMLElement}
829 */
830 getSelectedRow : function(){
831 if(this.selModel.hasSelection()){
832 return this.selModel.getSelectedRows()[0];
833 }
834 return null;
835 },
836
837 /**
838 * Get the selected row indexes
839 * @return {Array} Array of indexes
840 */
841 getSelectedRowIndexes : function(){
842 var a = [];
843 var rows = this.selModel.getSelectedRows();
844 for(var i = 0; i < rows.length; i++) {
845 a[i] = rows[i].rowIndex;
846 }
847 return a;
848 },
849
850 /**
851 * Gets the first selected row or -1 if none are selected
852 * @return {Number}
853 */
854 getSelectedRowIndex : function(){
855 if(this.selModel.hasSelection()){
856 return this.selModel.getSelectedRows()[0].rowIndex;
857 }
858 return -1;
859 },
860
861 /**
862 * Convenience method for getSelectionModel().getSelectedRowIds()[0] -
863 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
864 * @return {String}
865 */
866 getSelectedRowId : function(){
867 if(this.selModel.hasSelection()){
868 return this.selModel.getSelectedRowIds()[0];
869 }
870 return null;
871 },
872
873 /**
874 * Convenience method for getSelectionModel().getSelectedRowIds() -
875 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getSelectedRowIds}</small> for more details.
876 * @return {Array}
877 */
878 getSelectedRowIds : function(){
879 return this.selModel.getSelectedRowIds();
880 },
881
882 /**
883 * Convenience method for getSelectionModel().clearSelections() -
884 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#clearSelections}</small> for more details.
885 */
886 clearSelections : function(){
887 this.selModel.clearSelections();
888 },
889
890
891 /**
892 * Convenience method for getSelectionModel().selectAll() -
893 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#selectAll}</small> for more details.
894 */
895 selectAll : function(){
896 this.selModel.selectAll();
897 },
898
899
900 /**
901 * Convenience method for getSelectionModel().getCount() -
902 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#getCount}</small> for more details.
903 * @return {Number}
904 */
905 getSelectionCount : function(){
906 return this.selModel.getCount();
907 },
908
909 /**
910 * Convenience method for getSelectionModel().hasSelection() -
911 * See <small>{@link YAHOO.ext.grid.DefaultSelectionModel#hasSelection}</small> for more details.
912 * @return {Boolean}
913 */
914 hasSelection : function(){
915 return this.selModel.hasSelection();
916 },
917
918 /**
919 * Returns the grid's SelectionModel.
920 * @return {SelectionModel}
921 */
922 getSelectionModel : function(){
923 if(!this.selModel){
924 this.selModel = new DefaultSelectionModel();
925 }
926 return this.selModel;
927 },
928
929 /**
930 * Returns the grid's DataModel.
931 * @return {DataModel}
932 */
933 getDataModel : function(){
934 return this.dataModel;
935 },
936
937 /**
938 * Returns the grid's ColumnModel.
939 * @return {ColumnModel}
940 */
941 getColumnModel : function(){
942 return this.colModel;
943 },
944
945 /**
946 * Returns the grid's GridView object.
947 * @return {GridView}
948 */
949 getView : function(){
950 return this.view;
951 },
952 /**
953 * Called to get grid's drag proxy text, by default returns this.ddText.
954 * @return {String}
955 */
956 getDragDropText : function(){
957 return this.ddText.replace('%0', this.selModel.getCount());
958 }
959};
960/**
961 * Configures the text is the drag proxy (defaults to "%0 selected row(s)").
962 * %0 is replaced with the number of selected rows.
963 * @type String
964 */
965YAHOO.ext.grid.Grid.prototype.ddText = "%0 selected row(s)";
diff --git a/frontend/beta/js/YUI-extensions/grid/GridDD.js b/frontend/beta/js/YUI-extensions/grid/GridDD.js
new file mode 100644
index 0000000..cdcaf39
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/GridDD.js
@@ -0,0 +1,101 @@
1
2// kill dependency issue
3if(YAHOO.util.DDProxy){
4/**
5 * @class YAHOO.ext.grid.GridDD
6 * Custom implementation of YAHOO.util.DDProxy used internally by the grid
7 * @extends YAHOO.util.DDProxy
8 */
9YAHOO.ext.grid.GridDD = function(grid, bwrap){
10 this.grid = grid;
11 var ddproxy = document.createElement('div');
12 ddproxy.id = grid.container.id + '-ddproxy';
13 ddproxy.className = 'ygrid-drag-proxy';
14 document.body.insertBefore(ddproxy, document.body.firstChild);
15 YAHOO.util.Dom.setStyle(ddproxy, 'opacity', .80);
16 var ddicon = document.createElement('span');
17 ddicon.className = 'ygrid-drop-icon ygrid-drop-nodrop';
18 ddproxy.appendChild(ddicon);
19 var ddtext = document.createElement('span');
20 ddtext.className = 'ygrid-drag-text';
21 ddtext.innerHTML = "&#160;";
22 ddproxy.appendChild(ddtext);
23
24 this.ddproxy = ddproxy;
25 this.ddtext = ddtext;
26 this.ddicon = ddicon;
27 YAHOO.util.Event.on(bwrap, 'click', this.handleClick, this, true);
28 YAHOO.ext.grid.GridDD.superclass.constructor.call(this, bwrap.id, 'GridDD',
29 {dragElId : ddproxy.id, resizeFrame: false});
30
31 this.unlockDelegate = grid.selModel.unlock.createDelegate(grid.selModel);
32};
33YAHOO.extendX(YAHOO.ext.grid.GridDD, YAHOO.util.DDProxy);
34
35YAHOO.ext.grid.GridDD.prototype.handleMouseDown = function(e){
36 var row = this.grid.getRowFromChild(YAHOO.util.Event.getTarget(e));
37 if(!row) return;
38 if(this.grid.selModel.isSelected(row)){
39 YAHOO.ext.grid.GridDD.superclass.handleMouseDown.call(this, e);
40 }else {
41 this.grid.selModel.unlock();
42 YAHOO.ext.EventObject.setEvent(e);
43 this.grid.selModel.rowClick(this.grid, row.rowIndex, YAHOO.ext.EventObject);
44 YAHOO.ext.grid.GridDD.superclass.handleMouseDown.call(this, e);
45 this.grid.selModel.lock();
46 }
47};
48
49YAHOO.ext.grid.GridDD.prototype.handleClick = function(e){
50 if(this.grid.selModel.isLocked()){
51 setTimeout(this.unlockDelegate, 1);
52 YAHOO.util.Event.stopEvent(e);
53 }
54};
55
56/**
57 * Updates the DD visual element to allow/not allow a drop
58 * @param {Boolean} dropStatus True if drop is allowed on the target
59 */
60YAHOO.ext.grid.GridDD.prototype.setDropStatus = function(dropStatus){
61 if(dropStatus === true){
62 YAHOO.util.Dom.replaceClass(this.ddicon, 'ygrid-drop-nodrop', 'ygrid-drop-ok');
63 }else{
64 YAHOO.util.Dom.replaceClass(this.ddicon, 'ygrid-drop-ok', 'ygrid-drop-nodrop');
65 }
66};
67
68YAHOO.ext.grid.GridDD.prototype.startDrag = function(e){
69 this.ddtext.innerHTML = this.grid.getDragDropText();
70 this.setDropStatus(false);
71 this.grid.selModel.lock();
72 this.grid.fireEvent('startdrag', this.grid, this, e);
73};
74
75YAHOO.ext.grid.GridDD.prototype.endDrag = function(e){
76 YAHOO.util.Dom.setStyle(this.ddproxy, 'visibility', 'hidden');
77 this.grid.fireEvent('enddrag', this.grid, this, e);
78};
79
80YAHOO.ext.grid.GridDD.prototype.autoOffset = function(iPageX, iPageY) {
81 this.setDelta(-12, -20);
82};
83
84YAHOO.ext.grid.GridDD.prototype.onDragEnter = function(e, id) {
85 this.setDropStatus(true);
86 this.grid.fireEvent('dragenter', this.grid, this, id, e);
87};
88
89YAHOO.ext.grid.GridDD.prototype.onDragDrop = function(e, id) {
90 this.grid.fireEvent('dragdrop', this.grid, this, id, e);
91};
92
93YAHOO.ext.grid.GridDD.prototype.onDragOver = function(e, id) {
94 this.grid.fireEvent('dragover', this.grid, this, id, e);
95};
96
97YAHOO.ext.grid.GridDD.prototype.onDragOut = function(e, id) {
98 this.setDropStatus(false);
99 this.grid.fireEvent('dragout', this.grid, this, id, e);
100};
101};
diff --git a/frontend/beta/js/YUI-extensions/grid/GridView.js b/frontend/beta/js/YUI-extensions/grid/GridView.js
new file mode 100644
index 0000000..dbd47e3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/GridView.js
@@ -0,0 +1,790 @@
1/**
2 * @class YAHOO.ext.grid.GridView
3 * Default UI code used internally by the Grid. This is the object returned by {@link YAHOO.ext.grid.Grid#getView}.
4 * @constructor
5 */
6YAHOO.ext.grid.GridView = function(){
7 this.grid = null;
8 this.lastFocusedRow = null;
9 this.onScroll = new YAHOO.util.CustomEvent('onscroll');
10 this.adjustScrollTask = new YAHOO.ext.util.DelayedTask(this._adjustForScroll, this);
11 this.ensureVisibleTask = new YAHOO.ext.util.DelayedTask();
12};
13
14YAHOO.ext.grid.GridView.prototype = {
15 init: function(grid){
16 this.grid = grid;
17 },
18
19 fireScroll: function(scrollLeft, scrollTop){
20 this.onScroll.fireDirect(this.grid, scrollLeft, scrollTop);
21 },
22
23 /**
24 * @private
25 * Utility method that gets an array of the cell renderers
26 */
27 getColumnRenderers : function(){
28 var renderers = [];
29 var cm = this.grid.colModel;
30 var colCount = cm.getColumnCount();
31 for(var i = 0; i < colCount; i++){
32 renderers.push(cm.getRenderer(i));
33 }
34 return renderers;
35 },
36
37 buildIndexMap : function(){
38 var colToData = {};
39 var dataToCol = {};
40 var cm = this.grid.colModel;
41 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
42 var di = cm.getDataIndex(i);
43 colToData[i] = di;
44 dataToCol[di] = i;
45 }
46 return {'colToData': colToData, 'dataToCol': dataToCol};
47 },
48
49 getDataIndexes : function(){
50 if(!this.indexMap){
51 this.indexMap = this.buildIndexMap();
52 }
53 return this.indexMap.colToData;
54 },
55
56 getColumnIndexByDataIndex : function(dataIndex){
57 if(!this.indexMap){
58 this.indexMap = this.buildIndexMap();
59 }
60 return this.indexMap.dataToCol[dataIndex];
61 },
62
63 updateHeaders : function(){
64 var colModel = this.grid.colModel;
65 var hcells = this.headers;
66 var colCount = colModel.getColumnCount();
67 for(var i = 0; i < colCount; i++){
68 hcells[i].textNode.innerHTML = colModel.getColumnHeader(i);
69 }
70 },
71
72 adjustForScroll : function(disableDelay){
73 if(!disableDelay){
74 this.adjustScrollTask.delay(50);
75 }else{
76 this._adjustForScroll();
77 }
78 },
79
80 /**
81 * Returns the rowIndex/columnIndex of the cell found at the passed page coordinates
82 * @param {Number} x
83 * @param {Number} y
84 * @return {Array} [rowIndex, columnIndex]
85 */
86 getCellAtPoint : function(x, y){
87 var colIndex = null;
88 var rowIndex = null;
89
90 // translate page coordinates to local coordinates
91 var xy = YAHOO.util.Dom.getXY(this.wrap);
92 x = (x - xy[0]) + this.wrap.scrollLeft;
93 y = (y - xy[1]) + this.wrap.scrollTop;
94
95 var colModel = this.grid.colModel;
96 var pos = 0;
97 var colCount = colModel.getColumnCount();
98 for(var i = 0; i < colCount; i++){
99 if(colModel.isHidden(i)) continue;
100 var width = colModel.getColumnWidth(i);
101 if(x >= pos && x < pos+width){
102 colIndex = i;
103 break;
104 }
105 pos += width;
106 }
107 if(colIndex != null){
108 rowIndex = (y == 0 ? 0 : Math.floor(y / this.getRowHeight()));
109 if(rowIndex >= this.grid.dataModel.getRowCount()){
110 return null;
111 }
112 return [colIndex, rowIndex];
113 }
114 return null;
115 },
116
117 /** @private */
118 _adjustForScroll : function(){
119 this.forceScrollUpdate();
120 if(this.scrollbarMode == YAHOO.ext.grid.GridView.SCROLLBARS_OVERLAP){
121 var adjustment = 0;
122 if(this.wrap.clientWidth && this.wrap.clientWidth !== 0){
123 adjustment = this.wrap.offsetWidth - this.wrap.clientWidth;
124 }
125 this.hwrap.setWidth(this.wrap.offsetWidth-adjustment);
126 }else{
127 this.hwrap.setWidth(this.wrap.offsetWidth);
128 }
129 this.bwrap.setWidth(Math.max(this.grid.colModel.getTotalWidth(), this.wrap.clientWidth));
130 },
131
132 /**
133 * Focuses the specified row. The preferred way to scroll to a row is {@link #ensureVisible}.
134 * @param {Number/HTMLElement} row The index of a row or the row itself
135 */
136 focusRow : function(row){
137 if(typeof row == 'number'){
138 row = this.getBodyTable().childNodes[row];
139 }
140 if(!row) return;
141 var left = this.wrap.scrollLeft;
142 try{ // try catch for IE occasional focus bug
143 row.childNodes.item(0).hideFocus = true;
144 row.childNodes.item(0).focus();
145 }catch(e){}
146 this.ensureVisible(row);
147 this.wrap.scrollLeft = left;
148 this.handleScroll();
149 this.lastFocusedRow = row;
150 },
151
152 /**
153 * Scrolls the specified row into view. This call is automatically buffered (delayed), to disable
154 * the delay, pass true for disableDelay.
155 * @param {Number/HTMLElement} row The index of a row or the row itself
156 * @param {Boolean} disableDelay
157 */
158 ensureVisible : function(row, disableDelay){
159 if(!disableDelay){
160 this.ensureVisibleTask.delay(50, this._ensureVisible, this, [row]);
161 }else{
162 this._ensureVisible(row);
163 }
164 },
165
166 /** @ignore */
167 _ensureVisible : function(row){
168 if(typeof row == 'number'){
169 row = this.getBodyTable().childNodes[row];
170 }
171 if(!row) return;
172 var left = this.wrap.scrollLeft;
173 var rowTop = parseInt(row.offsetTop, 10); // parseInt for safari bug
174 var rowBottom = rowTop + row.offsetHeight;
175 var clientTop = parseInt(this.wrap.scrollTop, 10); // parseInt for safari bug
176 var clientBottom = clientTop + this.wrap.clientHeight;
177 if(rowTop < clientTop){
178 this.wrap.scrollTop = rowTop;
179 }else if(rowBottom > clientBottom){
180 this.wrap.scrollTop = rowBottom-this.wrap.clientHeight;
181 }
182 this.wrap.scrollLeft = left;
183 this.handleScroll();
184 },
185
186 updateColumns : function(){
187 this.grid.stopEditing();
188 var colModel = this.grid.colModel;
189 var hcols = this.headers;
190 var colCount = colModel.getColumnCount();
191 var pos = 0;
192 var totalWidth = colModel.getTotalWidth();
193 for(var i = 0; i < colCount; i++){
194 if(colModel.isHidden(i)) continue;
195 var width = colModel.getColumnWidth(i);
196 hcols[i].style.width = width + 'px';
197 hcols[i].style.left = pos + 'px';
198 hcols[i].split.style.left = (pos+width-3) + 'px';
199 this.setCSSWidth(i, width, pos);
200 pos += width;
201 }
202 this.lastWidth = totalWidth;
203 if(this.grid.autoWidth){
204 this.grid.container.setWidth(totalWidth+this.grid.container.getBorderWidth('lr'));
205 this.grid.autoSize();
206 }
207 this.bwrap.setWidth(Math.max(totalWidth, this.wrap.clientWidth));
208 if(!YAHOO.ext.util.Browser.isIE){ // fix scrolling prob in gecko and opera
209 this.wrap.scrollLeft = this.hwrap.dom.scrollLeft;
210 }
211 this.syncScroll();
212 this.forceScrollUpdate();
213 if(this.grid.autoHeight){
214 this.autoHeight();
215 this.updateWrapHeight();
216 }
217 },
218
219 setCSSWidth : function(colIndex, width, pos){
220 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
221 YAHOO.ext.util.CSS.updateRule(selector, 'width', width + 'px');
222 if(typeof pos == 'number'){
223 YAHOO.ext.util.CSS.updateRule(selector, 'left', pos + 'px');
224 }
225 },
226
227 /**
228 * Set a css style for a column dynamically.
229 * @param {Number} colIndex The index of the column
230 * @param {String} name The css property name
231 * @param {String} value The css value
232 */
233 setCSSStyle : function(colIndex, name, value){
234 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
235 YAHOO.ext.util.CSS.updateRule(selector, name, value);
236 },
237
238 handleHiddenChange : function(colModel, colIndex, hidden){
239 if(hidden){
240 this.hideColumn(colIndex);
241 }else{
242 this.unhideColumn(colIndex);
243 }
244 this.updateColumns();
245 },
246
247 hideColumn : function(colIndex){
248 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
249 YAHOO.ext.util.CSS.updateRule(selector, 'position', 'absolute');
250 YAHOO.ext.util.CSS.updateRule(selector, 'visibility', 'hidden');
251
252 this.headers[colIndex].style.display = 'none';
253 this.headers[colIndex].split.style.display = 'none';
254 },
255
256 unhideColumn : function(colIndex){
257 var selector = ["#" + this.grid.id + " .ygrid-col-" + colIndex, ".ygrid-col-" + colIndex];
258 YAHOO.ext.util.CSS.updateRule(selector, 'position', '');
259 YAHOO.ext.util.CSS.updateRule(selector, 'visibility', 'visible');
260
261 this.headers[colIndex].style.display = '';
262 this.headers[colIndex].split.style.display = '';
263 },
264
265 getBodyTable : function(){
266 return this.bwrap.dom;
267 },
268
269 updateRowIndexes : function(firstRow, lastRow){
270 var stripeRows = this.grid.stripeRows;
271 var bt = this.getBodyTable();
272 var nodes = bt.childNodes;
273 firstRow = firstRow || 0;
274 lastRow = lastRow || nodes.length-1;
275 var re = /^(?:ygrid-row ygrid-row-alt|ygrid-row)/;
276 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
277 var node = nodes[rowIndex];
278 if(stripeRows && (rowIndex+1) % 2 == 0){
279 node.className = node.className.replace(re, 'ygrid-row ygrid-row-alt');
280 }else{
281 node.className = node.className.replace(re, 'ygrid-row');
282 }
283 node.rowIndex = rowIndex;
284 nodes[rowIndex].style.top = (rowIndex * this.rowHeight) + 'px';
285 }
286 },
287
288 insertRows : function(dataModel, firstRow, lastRow){
289 this.updateBodyHeight();
290 this.adjustForScroll(true);
291 var renderers = this.getColumnRenderers();
292 var dindexes = this.getDataIndexes();
293 var colCount = this.grid.colModel.getColumnCount();
294 var beforeRow = null;
295 var bt = this.getBodyTable();
296 if(firstRow < bt.childNodes.length){
297 beforeRow = bt.childNodes[firstRow];
298 }
299 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
300 var row = document.createElement('span');
301 row.className = 'ygrid-row';
302 row.style.top = (rowIndex * this.rowHeight) + 'px';
303 this.renderRow(dataModel, row, rowIndex, colCount, renderers, dindexes);
304 if(beforeRow){
305 bt.insertBefore(row, beforeRow);
306 }else{
307 bt.appendChild(row);
308 }
309 }
310 this.updateRowIndexes(firstRow);
311 this.adjustForScroll(true);
312 },
313
314 renderRow : function(dataModel, row, rowIndex, colCount, renderers, dindexes){
315 for(var colIndex = 0; colIndex < colCount; colIndex++){
316 var td = document.createElement('span');
317 td.className = 'ygrid-col ygrid-col-' + colIndex + (colIndex == colCount-1 ? ' ygrid-col-last' : '');
318 td.columnIndex = colIndex;
319 td.tabIndex = 0;
320 var span = document.createElement('span');
321 span.className = 'ygrid-cell-text';
322 td.appendChild(span);
323 var val = renderers[colIndex](dataModel.getValueAt(rowIndex, dindexes[colIndex]), rowIndex, colIndex, td, dataModel);
324 if(typeof val == 'undefined' || val === '') val = '&#160;';
325 span.innerHTML = val;
326 row.appendChild(td);
327 }
328 },
329
330 deleteRows : function(dataModel, firstRow, lastRow){
331 this.updateBodyHeight();
332 // first make sure they are deselected
333 this.grid.selModel.deselectRange(firstRow, lastRow);
334 var bt = this.getBodyTable();
335 var rows = []; // get references because the rowIndex will change
336 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
337 rows.push(bt.childNodes[rowIndex]);
338 }
339 for(var i = 0; i < rows.length; i++){
340 bt.removeChild(rows[i]);
341 rows[i] = null;
342 }
343 rows = null;
344 this.updateRowIndexes(firstRow);
345 this.adjustForScroll();
346 },
347
348 updateRows : function(dataModel, firstRow, lastRow){
349 var bt = this.getBodyTable();
350 var dindexes = this.getDataIndexes();
351 var renderers = this.getColumnRenderers();
352 var colCount = this.grid.colModel.getColumnCount();
353 for(var rowIndex = firstRow; rowIndex <= lastRow; rowIndex++){
354 var row = bt.rows[rowIndex];
355 var cells = row.childNodes;
356 for(var colIndex = 0; colIndex < colCount; colIndex++){
357 var td = cells[colIndex];
358 var val = renderers[colIndex](dataModel.getValueAt(rowIndex, dindexes[colIndex]), rowIndex, colIndex, td, dataModel);
359 if(typeof val == 'undefined' || val === '') val = '&#160;';
360 td.firstChild.innerHTML = val;
361 }
362 }
363 },
364
365 handleSort : function(dataModel, sortColumnIndex, sortDir, noRefresh){
366 varselectedRows;
367 this.grid.selModel.syncSelectionsToIds();
368 if(!noRefresh){
369 this.updateRows(dataModel, 0, dataModel.getRowCount()-1);
370 }
371 this.updateHeaderSortState();
372 selectedRows = this.grid.selModel.getSelectedRows();
373 if (selectedRows.length > 0) {
374 this.focusRow(selectedRows[0]);
375 }
376 },
377
378 syncScroll : function(){
379 this.hwrap.dom.scrollLeft = this.wrap.scrollLeft;
380 },
381
382 handleScroll : function(){
383 this.syncScroll();
384 this.fireScroll(this.wrap.scrollLeft, this.wrap.scrollTop);
385 this.grid.fireEvent('bodyscroll', this.wrap.scrollLeft, this.wrap.scrollTop);
386 },
387
388 getRowHeight : function(){
389 if(!this.rowHeight){
390 var rule = YAHOO.ext.util.CSS.getRule(["#" + this.grid.id + " .ygrid-row", ".ygrid-row"]);
391 if(rule && rule.style.height){
392 this.rowHeight = parseInt(rule.style.height, 10);
393 }else{
394 this.rowHeight = 21;
395 }
396 }
397 return this.rowHeight;
398 },
399
400 renderRows : function(dataModel){
401 this.grid.stopEditing();
402 if(this.grid.selModel){
403 this.grid.selModel.clearSelections();
404 }
405 var bt = this.getBodyTable();
406 bt.innerHTML = '';
407 this.rowHeight = this.getRowHeight();
408 this.insertRows(dataModel, 0, dataModel.getRowCount()-1);
409 },
410
411 updateCell : function(dataModel, rowIndex, dataIndex){
412 var colIndex = this.getColumnIndexByDataIndex(dataIndex);
413 if(typeof colIndex == 'undefined'){ // not present in grid
414 return;
415 }
416 var bt = this.getBodyTable();
417 var row = bt.childNodes[rowIndex];
418 var cell = row.childNodes[colIndex];
419 var renderer = this.grid.colModel.getRenderer(colIndex);
420 var val = renderer(dataModel.getValueAt(rowIndex, dataIndex), rowIndex, colIndex, cell, dataModel);
421 if(typeof val == 'undefined' || val === '') val = '&#160;';
422 cell.firstChild.innerHTML = val;
423 },
424
425 calcColumnWidth : function(colIndex, maxRowsToMeasure){
426 var maxWidth = 0;
427 var bt = this.getBodyTable();
428 var rows = bt.childNodes;
429 var stopIndex = Math.min(maxRowsToMeasure || rows.length, rows.length);
430 if(this.grid.autoSizeHeaders){
431 var h = this.headers[colIndex];
432 var curWidth = h.style.width;
433 h.style.width = this.grid.minColumnWidth+'px';
434 maxWidth = Math.max(maxWidth, h.scrollWidth);
435 h.style.width = curWidth;
436 }
437 for(var i = 0; i < stopIndex; i++){
438 var cell = rows[i].childNodes[colIndex].firstChild;
439 maxWidth = Math.max(maxWidth, cell.scrollWidth);
440 }
441 return maxWidth + /*margin for error in IE*/ 5;
442 },
443
444 /**
445 * Autofit a column to it's content.
446 * @param {Number} colIndex
447 * @param {Boolean} forceMinSize true to force the column to go smaller if possible
448 */
449 autoSizeColumn : function(colIndex, forceMinSize){
450 if(forceMinSize){
451 this.setCSSWidth(colIndex, this.grid.minColumnWidth);
452 }
453 var newWidth = this.calcColumnWidth(colIndex);
454 this.grid.colModel.setColumnWidth(colIndex,
455 Math.max(this.grid.minColumnWidth, newWidth));
456 this.grid.fireEvent('columnresize', colIndex, newWidth);
457 },
458
459 /**
460 * Autofits all columns to their content and then expands to fit any extra space in the grid
461 */
462 autoSizeColumns : function(){
463 var colModel = this.grid.colModel;
464 var colCount = colModel.getColumnCount();
465 var wrap = this.wrap;
466 for(var i = 0; i < colCount; i++){
467 this.setCSSWidth(i, this.grid.minColumnWidth);
468 colModel.setColumnWidth(i, this.calcColumnWidth(i, this.grid.maxRowsToMeasure), true);
469 }
470 if(colModel.getTotalWidth() < wrap.clientWidth){
471 var diff = Math.floor((wrap.clientWidth - colModel.getTotalWidth()) / colCount);
472 for(var i = 0; i < colCount; i++){
473 colModel.setColumnWidth(i, colModel.getColumnWidth(i) + diff, true);
474 }
475 }
476 this.updateColumns();
477 },
478
479 /**
480 * Autofits all columns to the grid's width proportionate with their current size
481 */
482 fitColumns : function(){
483 var cm = this.grid.colModel;
484 var colCount = cm.getColumnCount();
485 var cols = [];
486 var width = 0;
487 var i, w;
488 for (i = 0; i < colCount; i++){
489 if(!cm.isHidden(i) && !cm.isFixed(i)){
490 w = cm.getColumnWidth(i);
491 cols.push(i);
492 cols.push(w);
493 width += w;
494 }
495 }
496 var frac = (this.wrap.clientWidth - cm.getTotalWidth())/width;
497 while (cols.length){
498 w = cols.pop();
499 i = cols.pop();
500 cm.setColumnWidth(i, Math.floor(w + w*frac), true);
501 }
502 this.updateColumns();
503 },
504
505 onWindowResize : function(){
506 if(this.grid.monitorWindowResize){
507 this.adjustForScroll();
508 this.updateWrapHeight();
509 this.adjustForScroll();
510 }
511 },
512
513 updateWrapHeight : function(){
514 this.grid.container.beginMeasure();
515 this.autoHeight();
516 var box = this.grid.container.getSize(true);
517 this.wrapEl.setHeight(box.height-this.footerHeight-parseInt(this.wrap.offsetTop, 10));
518 this.pwrap.setSize(box.width, box.height);
519 this.grid.container.endMeasure();
520 },
521
522 forceScrollUpdate : function(){
523 var wrap = this.wrapEl;
524 wrap.setWidth(wrap.getWidth(true));
525 setTimeout(function(){ // set timeout so FireFox works
526 wrap.setWidth('');
527 }, 1);
528 },
529
530 updateHeaderSortState : function(){
531 var state = this.grid.dataModel.getSortState();
532 if(!state || typeof state.column == 'undefined') return;
533 var sortColumn = this.getColumnIndexByDataIndex(state.column);
534 var sortDir = state.direction;
535 for(var i = 0, len = this.headers.length; i < len; i++){
536 var h = this.headers[i];
537 if(i != sortColumn){
538 h.sortDesc.style.display = 'none';
539 h.sortAsc.style.display = 'none';
540 YAHOO.util.Dom.removeClass(h, 'ygrid-sort-col');
541 }else{
542 h.sortDesc.style.display = sortDir == 'DESC' ? 'block' : 'none';
543 h.sortAsc.style.display = sortDir == 'ASC' ? 'block' : 'none';
544 YAHOO.util.Dom.addClass(h, 'ygrid-sort-col');
545 }
546 }
547 },
548
549 unplugDataModel : function(dm){
550 dm.removeListener('cellupdated', this.updateCell, this);
551 dm.removeListener('datachanged', this.renderRows, this);
552 dm.removeListener('rowsdeleted', this.deleteRows, this);
553 dm.removeListener('rowsinserted', this.insertRows, this);
554 dm.removeListener('rowsupdated', this.updateRows, this);
555 dm.removeListener('rowssorted', this.handleSort, this);
556 },
557
558 plugDataModel : function(dm){
559 dm.on('cellupdated', this.updateCell, this, true);
560 dm.on('datachanged', this.renderRows, this, true);
561 dm.on('rowsdeleted', this.deleteRows, this, true);
562 dm.on('rowsinserted', this.insertRows, this, true);
563 dm.on('rowsupdated', this.updateRows, this, true);
564 dm.on('rowssorted', this.handleSort, this, true);
565 },
566
567 destroy : function(){
568 this.unplugDataModel(this.grid.dataModel);
569 var sp = this.splitters;
570 if(sp){
571 for(var i in sp){
572 if(sp[i] && typeof sp[i] != 'function'){
573 sp[i].destroy(true);
574 }
575 }
576 }
577 },
578
579 render : function(){
580 var grid = this.grid;
581 var container = grid.container.dom;
582 var dataModel = grid.dataModel;
583 this.plugDataModel(dataModel);
584
585 var colModel = grid.colModel;
586 colModel.onWidthChange.subscribe(this.updateColumns, this, true);
587 colModel.onHeaderChange.subscribe(this.updateHeaders, this, true);
588 colModel.onHiddenChange.subscribe(this.handleHiddenChange, this, true);
589
590 if(grid.monitorWindowResize === true){
591 YAHOO.ext.EventManager.onWindowResize(this.onWindowResize, this, true);
592 }
593 var autoSizeDelegate = this.autoSizeColumn.createDelegate(this);
594
595 var colCount = colModel.getColumnCount();
596
597 var dh = YAHOO.ext.DomHelper;
598 this.pwrap = dh.append(container,
599 {tag: 'div', cls: 'ygrid-positioner',
600 style: 'position:relative;width:100%;height:100%;left:0;top:0;overflow:hidden;'}, true);
601 var pos = this.pwrap.dom;
602
603 //create wrapper elements that handle offsets and scrolling
604 var wrap = dh.append(pos, {tag: 'div', cls: 'ygrid-wrap'});
605 this.wrap = wrap;
606 this.wrapEl = getEl(wrap, true);
607 YAHOO.ext.EventManager.on(wrap, 'scroll', this.handleScroll, this, true);
608
609 var hwrap = dh.append(pos, {tag: 'div', cls: 'ygrid-wrap-headers'});
610 this.hwrap = getEl(hwrap, true);
611
612 var bwrap = dh.append(wrap, {tag: 'div', cls: 'ygrid-wrap-body', id: container.id + '-body'});
613 this.bwrap = getEl(bwrap, true);
614 this.bwrap.setWidth(colModel.getTotalWidth());
615 bwrap.rows = bwrap.childNodes;
616
617 this.footerHeight = 0;
618 var foot = this.appendFooter(this.pwrap.dom);
619 if(foot){
620 this.footer = getEl(foot, true);
621 this.footerHeight = this.footer.getHeight();
622 }
623 this.updateWrapHeight();
624
625 var hrow = dh.append(hwrap, {tag: 'span', cls: 'ygrid-hrow'});
626 this.hrow = hrow;
627
628 if(!YAHOO.ext.util.Browser.isGecko){
629 // IE doesn't like iframes, we will leave this alone
630 var iframe = document.createElement('iframe');
631 iframe.className = 'ygrid-hrow-frame';
632 iframe.frameBorder = 0;
633 iframe.src = YAHOO.ext.SSL_SECURE_URL;
634 hwrap.appendChild(iframe);
635 }
636 this.headerCtrl = new YAHOO.ext.grid.HeaderController(this.grid);
637 this.headers = [];
638 this.cols = [];
639 this.splitters = [];
640
641 var htemplate = dh.createTemplate({
642 tag: 'span', cls: 'ygrid-hd ygrid-header-{0}', children: [{
643 tag: 'span',
644 cls: 'ygrid-hd-body',
645 html: '<table border="0" cellpadding="0" cellspacing="0" title="{2}">' +
646 '<tbody><tr><td><span>{1}</span></td>' +
647 '<td><span class="sort-desc"></span><span class="sort-asc"></span></td>' +
648 '</tr></tbody></table>'
649 }]
650 });
651 htemplate.compile();
652
653 var ruleBuf = [];
654
655 for(var i = 0; i < colCount; i++){
656 var hd = htemplate.append(hrow, [i, colModel.getColumnHeader(i), colModel.getColumnTooltip(i) || '']);
657 var spans = hd.getElementsByTagName('span');
658 hd.textNode = spans[1];
659 hd.sortDesc = spans[2];
660 hd.sortAsc = spans[3];
661 hd.columnIndex = i;
662 this.headers.push(hd);
663 if(colModel.isSortable(i)){
664 this.headerCtrl.register(hd);
665 }
666 var split = dh.append(hrow, {tag: 'span', cls: 'ygrid-hd-split'});
667 hd.split = split;
668
669 if(colModel.isResizable(i) && !colModel.isFixed(i)){
670 YAHOO.util.Event.on(split, 'dblclick', autoSizeDelegate.createCallback(i+0, true));
671 var sb = new YAHOO.ext.SplitBar(split, hd, null, YAHOO.ext.SplitBar.LEFT);
672 sb.columnIndex = i;
673 sb.minSize = grid.minColumnWidth;
674 sb.onMoved.subscribe(this.onColumnSplitterMoved, this, true);
675 YAHOO.util.Dom.addClass(sb.proxy, 'ygrid-column-sizer');
676 YAHOO.util.Dom.setStyle(sb.proxy, 'background-color', '');
677 sb.dd._resizeProxy = function(){
678 var el = this.getDragEl();
679 YAHOO.util.Dom.setStyle(el, 'height', (hwrap.clientHeight+wrap.clientHeight-2) +'px');
680 };
681 this.splitters[i] = sb;
682 }else{
683 split.style.cursor = 'default';
684 }
685 ruleBuf.push('#', container.id, ' .ygrid-col-', i, ' {\n}\n');
686 }
687
688 YAHOO.ext.util.CSS.createStyleSheet(ruleBuf.join(''));
689
690 if(grid.autoSizeColumns){
691 this.renderRows(dataModel);
692 this.autoSizeColumns();
693 }else{
694 this.updateColumns();
695 this.renderRows(dataModel);
696 }
697
698 for(var i = 0; i < colCount; i++){
699 if(colModel.isHidden(i)){
700 this.hideColumn(i);
701 }
702 }
703 this.updateHeaderSortState();
704 return this.bwrap;
705 },
706
707 onColumnSplitterMoved : function(splitter, newSize){
708 this.grid.colModel.setColumnWidth(splitter.columnIndex, newSize);
709 this.grid.fireEvent('columnresize', splitter.columnIndex, newSize);
710 },
711
712 appendFooter : function(parentEl){
713 return null;
714 },
715
716 autoHeight : function(){
717 if(this.grid.autoHeight){
718 var h = this.getBodyHeight();
719 var c = this.grid.container;
720 var total = h + (parseInt(this.wrap.offsetTop, 10)||0) +
721 this.footerHeight + c.getBorderWidth('tb') + c.getPadding('tb')
722 + (this.wrap.offsetHeight - this.wrap.clientHeight);
723 c.setHeight(total);
724
725 }
726 },
727
728 getBodyHeight : function(){
729 return this.grid.dataModel.getRowCount() * this.getRowHeight();;
730 },
731
732 updateBodyHeight : function(){
733 this.getBodyTable().style.height = this.getBodyHeight() + 'px';
734 if(this.grid.autoHeight){
735 this.autoHeight();
736 this.updateWrapHeight();
737 }
738 }
739};
740YAHOO.ext.grid.GridView.SCROLLBARS_UNDER = 0;
741YAHOO.ext.grid.GridView.SCROLLBARS_OVERLAP = 1;
742YAHOO.ext.grid.GridView.prototype.scrollbarMode = YAHOO.ext.grid.GridView.SCROLLBARS_UNDER;
743
744YAHOO.ext.grid.GridView.prototype.fitColumnsToContainer = YAHOO.ext.grid.GridView.prototype.fitColumns;
745
746YAHOO.ext.grid.HeaderController = function(grid){
747 this.grid = grid;
748 this.headers = [];
749};
750
751YAHOO.ext.grid.HeaderController.prototype = {
752 register : function(header){
753 this.headers.push(header);
754 YAHOO.ext.EventManager.on(header, 'selectstart', this.cancelTextSelection, this, true);
755 YAHOO.ext.EventManager.on(header, 'mousedown', this.cancelTextSelection, this, true);
756 YAHOO.ext.EventManager.on(header, 'mouseover', this.headerOver, this, true);
757 YAHOO.ext.EventManager.on(header, 'mouseout', this.headerOut, this, true);
758 YAHOO.ext.EventManager.on(header, 'click', this.headerClick, this, true);
759 },
760
761 headerClick : function(e){
762 var grid = this.grid, cm = grid.colModel, dm = grid.dataModel;
763 grid.stopEditing();
764 var header = grid.getHeaderFromChild(e.getTarget());
765 var state = dm.getSortState();
766 var direction = header.sortDir || 'ASC';
767 if(typeof state.column != 'undefined' &&
768 grid.getView().getColumnIndexByDataIndex(state.column) == header.columnIndex){
769 direction = (state.direction == 'ASC' ? 'DESC' : 'ASC');
770 }
771 header.sortDir = direction;
772 dm.sort(cm, cm.getDataIndex(header.columnIndex), direction);
773 },
774
775 headerOver : function(e){
776 var header = this.grid.getHeaderFromChild(e.getTarget());
777 YAHOO.util.Dom.addClass(header, 'ygrid-hd-over');
778 //YAHOO.ext.util.CSS.applyFirst(header, this.grid.id, '.ygrid-hd-over');
779 },
780
781 headerOut : function(e){
782 var header = this.grid.getHeaderFromChild(e.getTarget());
783 YAHOO.util.Dom.removeClass(header, 'ygrid-hd-over');
784 //YAHOO.ext.util.CSS.revertFirst(header, this.grid.id, '.ygrid-hd-over');
785 },
786
787 cancelTextSelection : function(e){
788 e.preventDefault();
789 }
790}; \ No newline at end of file
diff --git a/frontend/beta/js/YUI-extensions/grid/PagedGridView.js b/frontend/beta/js/YUI-extensions/grid/PagedGridView.js
new file mode 100644
index 0000000..ecaece2
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/PagedGridView.js
@@ -0,0 +1,194 @@
1/**
2 * @class YAHOO.ext.grid.PagedGridView
3 * @extends YAHOO.ext.grid.GridView
4 * Extends the default GridView to add a paging interface.
5 * @constructor
6 * This class is created for you automatically if your data model is set to use paging.
7 */
8YAHOO.ext.grid.PagedGridView = function(){
9 YAHOO.ext.grid.PagedGridView.superclass.constructor.call(this);
10 this.cursor = 1;
11};
12
13YAHOO.extendX(YAHOO.ext.grid.PagedGridView, YAHOO.ext.grid.GridView, {
14 appendFooter : function(parentEl){
15 var fwrap = document.createElement('div');
16 fwrap.className = 'ygrid-wrap-footer';
17 var fbody = document.createElement('span');
18 fbody.className = 'ygrid-footer';
19 fwrap.appendChild(fbody);
20 parentEl.appendChild(fwrap);
21 this.createPagingToolbar(fbody);
22 return fwrap;
23 },
24
25 createPagingToolbar : function(container){
26 var tb = new YAHOO.ext.Toolbar(container);
27 this.pageToolbar = tb;
28 this.first = tb.addButton({
29 tooltip: this.firstText,
30 className: 'ygrid-page-first',
31 disabled: true,
32 click: this.onClick.createDelegate(this, ['first'])
33 });
34 this.prev = tb.addButton({
35 tooltip: this.prevText,
36 className: 'ygrid-page-prev',
37 disabled: true,
38 click: this.onClick.createDelegate(this, ['prev'])
39 });
40 tb.addSeparator();
41 tb.add(this.beforePageText);
42 var pageBox = document.createElement('input');
43 pageBox.type = 'text';
44 pageBox.size = 3;
45 pageBox.value = '1';
46 pageBox.className = 'ygrid-page-number';
47 tb.add(pageBox);
48 this.field = getEl(pageBox, true);
49 this.field.mon('keydown', this.onEnter, this, true);
50 this.field.on('focus', function(){pageBox.select();});
51 this.afterTextEl = tb.addText(this.afterPageText.replace('%0', '1'));
52 this.field.setHeight(18);
53 tb.addSeparator();
54 this.next = tb.addButton({
55 tooltip: this.nextText,
56 className: 'ygrid-page-next',
57 disabled: true,
58 click: this.onClick.createDelegate(this, ['next'])
59 });
60 this.last = tb.addButton({
61 tooltip: this.lastText,
62 className: 'ygrid-page-last',
63 disabled: true,
64 click: this.onClick.createDelegate(this, ['last'])
65 });
66 tb.addSeparator();
67 this.loading = tb.addButton({
68 tooltip: this.refreshText,
69 className: 'ygrid-loading',
70 disabled: true,
71 click: this.onClick.createDelegate(this, ['refresh'])
72 });
73 this.onPageLoaded(1, this.grid.dataModel.getTotalPages());
74 },
75
76 /**
77 * Returns the toolbar used for paging so you can add new buttons.
78 * @return {YAHOO.ext.Toolbar}
79 */
80 getPageToolbar : function(){
81 return this.pageToolbar;
82 },
83
84 onPageLoaded : function(pageNum, totalPages){
85 this.cursor = pageNum;
86 this.lastPage = totalPages;
87 this.afterTextEl.innerHTML = this.afterPageText.replace('%0', totalPages);
88 this.field.dom.value = pageNum;
89 this.first.setDisabled(pageNum == 1);
90 this.prev.setDisabled(pageNum == 1);
91 this.next.setDisabled(pageNum == totalPages);
92 this.last.setDisabled(pageNum == totalPages);
93 this.loading.enable();
94 },
95
96 onLoadError : function(){
97 this.loading.enable();
98 },
99
100 onEnter : function(e){
101 if(e.browserEvent.keyCode == e.RETURN){
102 var v = this.field.dom.value;
103 if(!v){
104 this.field.dom.value = this.cursor;
105 return;
106 }
107 var pageNum = parseInt(v, 10);
108 if(isNaN(pageNum)){
109 this.field.dom.value = this.cursor;
110 return;
111 }
112 pageNum = Math.min(Math.max(1, pageNum), this.lastPage);
113 this.grid.dataModel.loadPage(pageNum);
114 e.stopEvent();
115 }
116 },
117
118 beforeLoad : function(){
119 this.grid.stopEditing();
120 if(this.loading){
121 this.loading.disable();
122 }
123 },
124
125 onClick : function(which){
126 switch(which){
127 case 'first':
128 this.grid.dataModel.loadPage(1);
129 break;
130 case 'prev':
131 this.grid.dataModel.loadPage(this.cursor -1);
132 break;
133 case 'next':
134 this.grid.dataModel.loadPage(this.cursor + 1);
135 break;
136 case 'last':
137 this.grid.dataModel.loadPage(this.lastPage);
138 break;
139 case 'refresh':
140 this.grid.dataModel.loadPage(this.cursor);
141 break;
142 }
143 },
144
145 unplugDataModel : function(dm){
146 dm.removeListener('beforeload', this.beforeLoad, this);
147 dm.removeListener('load', this.onPageLoaded, this);
148 dm.removeListener('loadexception', this.onLoadError, this);
149 YAHOO.ext.grid.PagedGridView.superclass.unplugDataModel.call(this, dm);
150 },
151
152 plugDataModel : function(dm){
153 dm.on('beforeload', this.beforeLoad, this, true);
154 dm.on('load', this.onPageLoaded, this, true);
155 dm.on('loadexception', this.onLoadError, this);
156 YAHOO.ext.grid.PagedGridView.superclass.plugDataModel.call(this, dm);
157 },
158
159 /**
160 * Customizable piece of the default paging text (defaults to "Page")
161 * @type String
162 */
163 beforePageText : "Page",
164 /**
165 * Customizable piece of the default paging text (defaults to "of %0")
166 * @type String
167 */
168 afterPageText : "of %0",
169 /**
170 * Customizable piece of the default paging text (defaults to "First Page")
171 * @type String
172 */
173 firstText : "First Page",
174 /**
175 * Customizable piece of the default paging text (defaults to "Previous Page")
176 * @type String
177 */
178 prevText : "Previous Page",
179 /**
180 * Customizable piece of the default paging text (defaults to "Next Page")
181 * @type String
182 */
183 nextText : "Next Page",
184 /**
185 * Customizable piece of the default paging text (defaults to "Last Page")
186 * @type String
187 */
188 lastText : "Last Page",
189 /**
190 * Customizable piece of the default paging text (defaults to "Refresh")
191 * @type String
192 */
193 refreshText : "Refresh"
194});
diff --git a/frontend/beta/js/YUI-extensions/grid/SelectionModel.js b/frontend/beta/js/YUI-extensions/grid/SelectionModel.js
new file mode 100644
index 0000000..6981440
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/SelectionModel.js
@@ -0,0 +1,445 @@
1/**
2 @class YAHOO.ext.grid.DefaultSelectionModel
3 * @extends YAHOO.ext.util.Observable
4 * The default SelectionModel used by {@link YAHOO.ext.grid.Grid}.
5 It supports multiple selections and keyboard selection/navigation. <br><br>
6 @constructor
7 */
8YAHOO.ext.grid.DefaultSelectionModel = function(){
9 this.selectedRows = [];
10 this.selectedRowIds = [];
11 this.lastSelectedRow = null;
12
13 this.onRowSelect = new YAHOO.util.CustomEvent('SelectionTable.rowSelected');
14 this.onSelectionChange = new YAHOO.util.CustomEvent('SelectionTable.selectionChanged');
15
16 this.events = {
17 /**
18 * @event selectionchange
19 * Fires when the selection changes
20 * @param {SelectionModel} this
21 * @param {Array} rows Array of row elements that are selected
22 * @param {String} ids Array of ids that are selected
23 */
24 'selectionchange' : this.onSelectionChange,
25 /**
26 * @event rowselect
27 * Fires when a row is selected or deselected
28 * @param {SelectionModel} this
29 * @param {HTMLElement} row The row element
30 * @param {Boolean} selected true if the row was selected, false if deselected
31 */
32 'rowselect' : this.onRowSelect
33 };
34
35 this.locked = false;
36};
37
38YAHOO.ext.grid.DefaultSelectionModel.prototype = {
39 /** @ignore Called by the grid automatically. Do not call directly. */
40 init : function(grid){
41 this.grid = grid;
42 this.initEvents();
43 },
44
45 /**
46 * Lock the selections
47 */
48 lock : function(){
49 this.locked = true;
50 },
51
52 /**
53 * Unlock the selections
54 */
55 unlock : function(){
56 this.locked = false;
57 },
58
59 /**
60 * Returns true if the selections are locked
61 * @return {Boolean}
62 */
63 isLocked : function(){
64 return this.locked;
65 },
66
67 /** @ignore */
68 initEvents : function(){
69 if(this.grid.trackMouseOver){
70 this.grid.addListener("mouseover", this.handleOver, this, true);
71 this.grid.addListener("mouseout", this.handleOut, this, true);
72 }
73 this.grid.addListener("rowclick", this.rowClick, this, true);
74 this.grid.addListener("keydown", this.keyDown, this, true);
75 },
76
77 fireEvent : YAHOO.ext.util.Observable.prototype.fireEvent,
78 on : YAHOO.ext.util.Observable.prototype.on,
79 addListener : YAHOO.ext.util.Observable.prototype.addListener,
80 delayedListener : YAHOO.ext.util.Observable.prototype.delayedListener,
81 removeListener : YAHOO.ext.util.Observable.prototype.removeListener,
82 purgeListeners : YAHOO.ext.util.Observable.prototype.purgeListeners,
83 bufferedListener : YAHOO.ext.util.Observable.prototype.bufferedListener,
84
85 /** @ignore Syncs selectedRows with the correct row by looking it up by id.
86 Used after a sort moves data around. */
87 syncSelectionsToIds : function(){
88 if(this.getCount() > 0){
89 var ids = this.selectedRowIds.concat();
90 this.clearSelections();
91 this.selectRowsById(ids, true);
92 }
93 },
94
95 /**
96 * Set the selected rows by their ID(s). IDs must match what is returned by the DataModel getRowId(index).
97 * @param {String/Array} id The id(s) to select
98 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
99 */
100 selectRowsById : function(id, keepExisting){
101 var rows = this.grid.getRowsById(id);
102 if (!(rows instanceof Array)){
103 this.selectRow(rows, keepExisting);
104 return;
105 }
106 this.selectRows(rows, keepExisting);
107 },
108
109 /**
110 * Gets the number of selected rows.
111 * @return {Number}
112 */
113 getCount : function(){
114 return this.selectedRows.length;
115 },
116
117 /**
118 * Selects the first row in the grid.
119 */
120 selectFirstRow : function(){
121 for(var j = 0; j < this.grid.rows.length; j++){
122 if(this.isSelectable(this.grid.rows[j])){
123 this.focusRow(this.grid.rows[j]);
124 this.setRowState(this.grid.rows[j], true);
125 return;
126 }
127 }
128 },
129
130 /**
131 * Selects the row immediately following the last selected row.
132 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
133 */
134 selectNext : function(keepExisting){
135 if(this.lastSelectedRow){
136 for(var j = (this.lastSelectedRow.rowIndex+1); j < this.grid.rows.length; j++){
137 var row = this.grid.rows[j];
138 if(this.isSelectable(row)){
139 this.focusRow(row);
140 this.setRowState(row, true, keepExisting);
141 return;
142 }
143 }
144 }
145 },
146
147 /**
148 * Selects the row that precedes the last selected row.
149 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
150 */
151 selectPrevious : function(keepExisting){
152 if(this.lastSelectedRow){
153 for(var j = (this.lastSelectedRow.rowIndex-1); j >= 0; j--){
154 var row = this.grid.rows[j];
155 if(this.isSelectable(row)){
156 this.focusRow(row);
157 this.setRowState(row, true, keepExisting);
158 return;
159 }
160 }
161 }
162 },
163
164 /**
165 * Returns the selected rows.
166 * @return {Array} Array of DOM row elements
167 */
168 getSelectedRows : function(){
169 return this.selectedRows;
170 },
171
172 /**
173 * Returns the selected row ids.
174 * @return {Array} Array of String ids
175 */
176 getSelectedRowIds : function(){
177 return this.selectedRowIds;
178 },
179
180 /**
181 * Clears all selections.
182 */
183 clearSelections : function(){
184 if(this.isLocked()) return;
185 var oldSelections = this.selectedRows.concat();
186 for(var j = 0; j < oldSelections.length; j++){
187 this.setRowState(oldSelections[j], false);
188 }
189 this.selectedRows = [];
190 this.selectedRowIds = [];
191 },
192
193
194 /**
195 * Selects all rows.
196 */
197 selectAll : function(){
198 if(this.isLocked()) return;
199 this.selectedRows = [];
200 this.selectedRowIds = [];
201 for(var j = 0, len = this.grid.rows.length; j < len; j++){
202 this.setRowState(this.grid.rows[j], true, true);
203 }
204 },
205
206 /**
207 * Returns True if there is a selection.
208 * @return {Boolean}
209 */
210 hasSelection : function(){
211 return this.selectedRows.length > 0;
212 },
213
214 /**
215 * Returns True if the specified row is selected.
216 * @param {HTMLElement} row The row to check
217 * @return {Boolean}
218 */
219 isSelected : function(row){
220 return row && (row.selected === true || row.getAttribute('selected') == 'true');
221 },
222
223 /**
224 * Returns True if the specified row is selectable.
225 * @param {HTMLElement} row The row to check
226 * @return {Boolean}
227 */
228 isSelectable : function(row){
229 return row && row.getAttribute('selectable') != 'false';
230 },
231
232 /** @ignore */
233 rowClick : function(grid, rowIndex, e){
234 if(this.isLocked()) return;
235 var row = grid.getRow(rowIndex);
236 if(this.isSelectable(row)){
237 if(e.shiftKey && this.lastSelectedRow){
238 var lastIndex = this.lastSelectedRow.rowIndex;
239 this.selectRange(this.lastSelectedRow, row, e.ctrlKey);
240 this.lastSelectedRow = this.grid.el.dom.rows[lastIndex];
241 }else{
242 this.focusRow(row);
243 var rowState = e.ctrlKey ? !this.isSelected(row) : true;
244 this.setRowState(row, rowState, e.hasModifier());
245 }
246 }
247 },
248
249 /**
250 * Deprecated. Tries to focus the row and scroll it into view - Use grid.scrollTo or grid.getView().focusRow() instead.
251 * @deprecated
252 * @param {HTMLElement} row The row to focus
253 */
254 focusRow : function(row){
255 this.grid.view.focusRow(row);
256 },
257
258 /**
259 * Selects a row.
260 * @param {Number/HTMLElement} row The row or index of the row to select
261 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
262 */
263 selectRow : function(row, keepExisting){
264 this.setRowState(this.getRow(row), true, keepExisting);
265 },
266
267 /**
268 * Selects multiple rows.
269 * @param {Array} rows Array of the rows or indexes of the row to select
270 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
271 */
272 selectRows : function(rows, keepExisting){
273 if(!keepExisting){
274 this.clearSelections();
275 }
276 for(var i = 0; i < rows.length; i++){
277 this.selectRow(rows[i], true);
278 }
279 },
280
281 /**
282 * Deselects a row.
283 * @param {Number/HTMLElement} row The row or index of the row to deselect
284 */
285 deselectRow : function(row){
286 this.setRowState(this.getRow(row), false);
287 },
288
289 /** @ignore */
290 getRow : function(row){
291 if(typeof row == 'number'){
292 row = this.grid.rows[row];
293 }
294 return row;
295 },
296
297 /**
298 * Selects a range of rows. All rows in between startRow and endRow are also selected.
299 * @param {Number/HTMLElement} startRow The row or index of the first row in the range
300 * @param {Number/HTMLElement} endRow The row or index of the last row in the range
301 * @param {<i>Boolean</i>} keepExisting (optional) True to retain existing selections
302 */
303 selectRange : function(startRow, endRow, keepExisting){
304 startRow = this.getRow(startRow);
305 endRow = this.getRow(endRow);
306 this.setRangeState(startRow, endRow, true, keepExisting);
307 },
308
309 /**
310 * Deselects a range of rows. All rows in between startRow and endRow are also deselected.
311 * @param {Number/HTMLElement} startRow The row or index of the first row in the range
312 * @param {Number/HTMLElement} endRow The row or index of the last row in the range
313 */
314 deselectRange : function(startRow, endRow){
315 startRow = this.getRow(startRow);
316 endRow = this.getRow(endRow);
317 this.setRangeState(startRow, endRow, false, true);
318 },
319
320 /** @ignore */
321 setRowStateFromChild : function(childEl, selected, keepExisting){
322 var row = this.grid.getRowFromChild(childEl);
323 this.setRowState(row, selected, keepExisting);
324 },
325
326 /** @ignore */
327 setRangeState : function(startRow, endRow, selected, keepExisting){
328 if(this.isLocked()) return;
329 if(!keepExisting){
330 this.clearSelections();
331 }
332 var curRow = startRow;
333 while(curRow.rowIndex != endRow.rowIndex){
334 this.setRowState(curRow, selected, true);
335 curRow = (startRow.rowIndex < endRow.rowIndex ?
336 this.grid.getRowAfter(curRow) : this.grid.getRowBefore(curRow))
337 }
338 this.setRowState(endRow, selected, true);
339 },
340
341 /** @ignore */
342 setRowState : function(row, selected, keepExisting){
343 if(this.isLocked()) return;
344 if(this.isSelectable(row)){
345 if(selected){
346 if(!keepExisting){
347 this.clearSelections();
348 }
349 this.setRowClass(row, 'selected');
350 row.selected = true;
351 this.selectedRows.push(row);
352 this.selectedRowIds.push(this.grid.dataModel.getRowId(row.rowIndex));
353 this.lastSelectedRow = row;
354 }else{
355 this.setRowClass(row, '');
356 row.selected = false;
357 this._removeSelected(row);
358 }
359 this.fireEvent('rowselect', this, row, selected);
360 this.fireEvent('selectionchange', this, this.selectedRows, this.selectedRowIds);
361 }
362 },
363
364 /** @ignore */
365 handleOver : function(e){
366 var row = this.grid.getRowFromChild(e.getTarget());
367 if(this.isSelectable(row) && !this.isSelected(row)){
368 this.setRowClass(row, 'over');
369 }
370 },
371
372 /** @ignore */
373 handleOut : function(e){
374 var row = this.grid.getRowFromChild(e.getTarget());
375 if(this.isSelectable(row) && !this.isSelected(row)){
376 this.setRowClass(row, '');
377 }
378 },
379
380 /** @ignore */
381 keyDown : function(e){
382 if(e.browserEvent.keyCode == e.DOWN){
383 this.selectNext(e.shiftKey);
384 e.preventDefault();
385 }else if(e.browserEvent.keyCode == e.UP){
386 this.selectPrevious(e.shiftKey);
387 e.preventDefault();
388 }
389 },
390
391 /** @ignore */
392 setRowClass : function(row, cssClass){
393 if(this.isSelectable(row)){
394 if(cssClass == 'selected'){
395 YAHOO.util.Dom.removeClass(row, 'ygrid-row-over');
396 YAHOO.util.Dom.addClass(row, 'ygrid-row-selected');
397 }else if(cssClass == 'over'){
398 YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected');
399 YAHOO.util.Dom.addClass(row, 'ygrid-row-over');
400 }else if(cssClass == ''){
401 YAHOO.util.Dom.removeClass(row, 'ygrid-row-selected');
402 YAHOO.util.Dom.removeClass(row, 'ygrid-row-over');
403 }
404 }
405 },
406
407 /** @ignore */
408 _removeSelected : function(row){
409 var sr = this.selectedRows;
410 for (var i = 0; i < sr.length; i++) {
411 if (sr[i] === row){
412 this.selectedRows.splice(i, 1);
413 this.selectedRowIds.splice(i, 1);
414 return;
415 }
416 }
417 }
418};
419
420/**
421 @class YAHOO.ext.grid.SingleSelectionModel
422 @extends YAHOO.ext.grid.DefaultSelectionModel
423 Allows only one row to be selected at a time.
424 @constructor
425 * Create new SingleSelectionModel
426 */
427YAHOO.ext.grid.SingleSelectionModel = function(){
428 YAHOO.ext.grid.SingleSelectionModel.superclass.constructor.call(this);
429};
430
431YAHOO.extendX(YAHOO.ext.grid.SingleSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
432
433/** @ignore */
434YAHOO.ext.grid.SingleSelectionModel.prototype.setRowState = function(row, selected){
435 YAHOO.ext.grid.SingleSelectionModel.superclass.setRowState.call(this, row, selected, false);
436};
437
438YAHOO.ext.grid.DisableSelectionModel = function(){
439 YAHOO.ext.grid.DisableSelectionModel.superclass.constructor.call(this);
440};
441
442YAHOO.extendX(YAHOO.ext.grid.DisableSelectionModel, YAHOO.ext.grid.DefaultSelectionModel);
443
444YAHOO.ext.grid.DisableSelectionModel.prototype.initEvents = function(){
445};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js
new file mode 100644
index 0000000..7c51a48
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/CellEditor.js
@@ -0,0 +1,91 @@
1/**
2 * @class YAHOO.ext.grid.CellEditor
3 * Base class for all EditorGrid editors
4 */
5YAHOO.ext.grid.CellEditor = function(element){
6 this.colIndex = null;
7 this.rowIndex = null;
8 this.grid = null;
9 this.editing = false;
10 this.originalValue = null;
11 this.element = getEl(element, true);
12 this.element.addClass('ygrid-editor');
13 this.element.dom.tabIndex = 1;
14 this.initialized = false;
15 this.callback = null;
16};
17
18YAHOO.ext.grid.CellEditor.prototype = {
19 init : function(grid, bodyElement, callback){
20 // there's no way for the grid to know if multiple columns
21 // share the same editor so it will try to initialize the
22 // same one over and over
23 if(this.initialized) return;
24 this.initialized = true;
25 this.callback = callback;
26 this.grid = grid;
27 bodyElement.appendChild(this.element.dom);
28 this.initEvents();
29 },
30
31 initEvents : function(){
32 var stopOnEnter = function(e){
33 if(e.browserEvent.keyCode == e.RETURN){
34 this.stopEditing(true);
35 }else if(e.browserEvent.keyCode == e.ESC){
36 this.setValue(this.originalValue);
37 this.stopEditing(true);
38 }
39 }
40 this.element.mon('keydown', stopOnEnter, this, true);
41 this.element.on('blur', this.stopEditing, this, true);
42 },
43
44 startEditing : function(value, row, cell){
45 this.originalValue = value;
46 this.rowIndex = row.rowIndex;
47 this.colIndex = cell.columnIndex;
48 this.cell = cell;
49 this.setValue(value);
50 var cellbox = getEl(cell, true).getBox();
51 this.fitToCell(cellbox);
52 this.editing = true;
53 this.show();
54 },
55
56 stopEditing : function(focusCell){
57 if(this.editing){
58 this.editing = false;
59 var newValue = this.getValue();
60 this.hide();
61 //if(focusCell){try{this.cell.focus();}catch(e){}}; // try to give the cell focus so keyboard nav still works
62 if(this.originalValue != newValue){
63 this.callback(newValue, this.rowIndex, this.colIndex);
64 }
65 }
66 },
67
68 setValue : function(value){
69 this.element.dom.value = value;
70 },
71
72 getValue : function(){
73 return this.element.dom.value;
74 },
75
76 fitToCell : function(box){
77 this.element.setBox(box, true);
78 },
79
80 show : function(){
81 this.element.show();
82 this.element.focus();
83 },
84
85 hide : function(){
86 try{
87 this.element.dom.blur();
88 }catch(e){}
89 this.element.hide();
90 }
91};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js
new file mode 100644
index 0000000..681b847
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/CheckboxEditor.js
@@ -0,0 +1,60 @@
1/**
2 * @class YAHOO.ext.grid.CheckboxEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a checkbox for editing boolean values. It currently has no configuration options.<br><br>
5For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
6* @constructor
7* Create a new CheckboxEditor
8 */
9YAHOO.ext.grid.CheckboxEditor = function(){
10 var div = document.createElement('span');
11 div.className = 'ygrid-editor ygrid-checkbox-editor';
12 var cb = document.createElement('input');
13 cb.type = 'checkbox';
14 cb.setAttribute('autocomplete', 'off');
15 div.appendChild(cb);
16 document.body.appendChild(div);
17 YAHOO.ext.grid.CheckboxEditor.superclass.constructor.call(this, div);
18 div.tabIndex = '';
19 cb.tabIndex = 1;
20 this.cb = getEl(cb, true);
21};
22
23YAHOO.extendX(YAHOO.ext.grid.CheckboxEditor, YAHOO.ext.grid.CellEditor);
24
25YAHOO.ext.grid.CheckboxEditor.prototype.fitToCell = function(box){
26 this.element.setBox(box, true);
27};
28
29YAHOO.ext.grid.CheckboxEditor.prototype.setValue = function(value){
30 this.cb.dom.checked = (value === true || value === 'true' || value === 1 || value === '1');
31};
32
33YAHOO.ext.grid.CheckboxEditor.prototype.getValue = function(){
34 return this.cb.dom.checked;
35};
36
37YAHOO.ext.grid.CheckboxEditor.prototype.show = function(){
38 this.element.show();
39 this.cb.focus();
40};
41
42YAHOO.ext.grid.CheckboxEditor.prototype.initEvents = function(){
43 var stopOnEnter = function(e){
44 if(e.browserEvent.keyCode == e.RETURN){
45 this.stopEditing(true);
46 }else if(e.browserEvent.keyCode == e.ESC){
47 this.setValue(this.originalValue);
48 this.stopEditing(true);
49 }
50 }
51 this.cb.mon('keydown', stopOnEnter, this, true);
52 this.cb.on('blur', this.stopEditing, this, true);
53};
54
55YAHOO.ext.grid.CheckboxEditor.prototype.hide = function(){
56 try{
57 this.cb.dom.blur();
58 }catch(e){}
59 this.element.hide();
60};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js
new file mode 100644
index 0000000..303ad2b
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/DateEditor.js
@@ -0,0 +1,268 @@
1/**
2 * @class YAHOO.ext.grid.DateEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a date editor field, and optionally a DatePicker. The DateEditor provides a method to override (showCalendar) if you don't want to use the built in DatePicker control. The reason I chose to use my own DatePicker control rather than the nice YUI Calendar component is my control was very easy to override events to make it work well with the grid. It's also only 5k compressed, while the YUI Calendar is 40k compressed. The DatePicker supports left/right keys to move months, up/down keys to move years and the mouse wheel to quickly go through the months. The DateEditor supports the following configuration options:
5<ul class="list">
6<li><i>format</i> - The date format for the editor. The format is identical to <a href="http://www.php.net/date">PHP date()</a> and text is allowed. Credit for that goes to <a style="font-weight:normal;" href="http://www.xaprb.com/blog/2006/05/14/javascript-date-formatting-benchmarks/">this fantastic date library</a>. This format is for the editor only and doesn't affect the rendering of the cell when not in edit mode. Your rendering function can use any date format it wants.</li>
7<li><i>minValue</i> - The minimum allowed date. Can be either a Javascript date object or a string date in the specified format.</li>
8<li><i>maxValue</i> - The maximum allowed date. Can be either a Javascript date object or a string date in the specified format.</li>
9<li><i>minText</i> - The tooltip to display when the date in the cell is before minValue.</li>
10<li><i>maxText</i> - The tooltip to display when the date in the cell is after maxValue.</li>
11<li><i>invalidText</i> - The text to display when the date in the field is invalid (for example: 02/31/06)</li>
12<li><i>disabledDays</i> - An array of days to disable, 0 based. For example, [0, 6] disables Sunday and Saturday.</li>
13<li><i>disabledDaysText</i> - The tooltip to display when the date in the cell (or DatePicker) falls on a disabled day.</li>
14<li><i>disabledDates</i> - An array of "dates" to disable, as strings. These strings will be used to build a dynamic regular expression so they are very powerful. For example, ["03/08/2003", "09/16/2003"] would disable those dates, but ["03/08", "09/16"] would disable them for every year. If you are using short years, you will want to use ^ to tell the regular expression to only match the beginning like ["^03/08"]. To disable March of 2006: ["03/../2006"] or every March ["^03"]. In order to support regular expressions, if you are using a date format that has "." in it, you will have to escape the dot when restricting dates. For example: ["03\\.08\\.03"].</li>
15<li><i>disabledDatesText</i> - The tooltip to display when the date in the cell (or DatePicker) falls on a disabled date.</li>
16<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
17<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
18<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
19<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
20</ul>
21For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
22* @constructor
23* Create a new DateEditor
24* @param {Object} config
25 */
26YAHOO.ext.grid.DateEditor = function(config){
27 var div = document.createElement('span');
28 div.className = 'ygrid-editor ygrid-editor-container';
29
30 var element = document.createElement('input');
31 element.type = 'text';
32 element.tabIndex = 1;
33 element.setAttribute('autocomplete', 'off');
34 div.appendChild(element);
35
36 var pick = document.createElement('span');
37 pick.className = 'pick-button';
38 div.appendChild(pick);
39
40 document.body.appendChild(div);
41
42 this.div = getEl(div, true);
43 this.element = getEl(element, true);
44 this.pick = getEl(pick, true);
45
46 this.colIndex = null;
47 this.rowIndex = null;
48 this.grid = null;
49 this.editing = false;
50 this.originalValue = null;
51 this.initialized = false;
52 this.callback = null;
53
54 this.cal = null;
55 this.mouseDownHandler = YAHOO.ext.EventManager.wrap(this.handleMouseDown, this, true);
56
57 YAHOO.ext.util.Config.apply(this, config);
58 if(typeof this.minValue == 'string') this.minValue = this.parseDate(this.minValue);
59 if(typeof this.maxValue == 'string') this.maxValue = this.parseDate(this.maxValue);
60 this.ddMatch = /ddnone/;
61 if(this.disabledDates){
62 var dd = this.disabledDates;
63 var re = "(?:";
64 for(var i = 0; i < dd.length; i++){
65 re += dd[i];
66 if(i != dd.length-1) re += "|";
67 }
68 this.ddMatch = new RegExp(re + ")");
69 }
70};
71
72YAHOO.ext.grid.DateEditor.prototype = {
73 init : function(grid, bodyElement, callback){
74 if(this.initialized) return;
75
76 this.initialized = true;
77 this.callback = callback;
78 this.grid = grid;
79 bodyElement.appendChild(this.div.dom);
80 this.initEvents();
81 },
82
83 initEvents : function(){
84 var stopOnEnter = function(e){
85 if(e.browserEvent.keyCode == e.RETURN){
86 this.stopEditing(true);
87 }else if(e.browserEvent.keyCode == e.ESC){
88 this.setValue(this.originalValue);
89 this.stopEditing(true);
90 }
91 }
92 this.element.mon('keydown', stopOnEnter, this, true);
93 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
94 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
95 this.pick.on('click', this.showCalendar, this, true);
96 },
97
98 startEditing : function(value, row, cell){
99 this.originalValue = value;
100 this.rowIndex = row.rowIndex;
101 this.colIndex = cell.columnIndex;
102 this.cell = cell;
103 this.setValue(value);
104 this.validate();
105 var cellbox = getEl(cell, true).getBox();
106 this.div.setBox(cellbox, true);
107 this.element.setWidth(cellbox.width-this.pick.getWidth());
108 this.editing = true;
109 YAHOO.util.Event.on(document, "mousedown", this.mouseDownHandler);
110 this.show();
111 },
112
113 stopEditing : function(focusCell){
114 if(this.editing){
115 YAHOO.util.Event.removeListener(document, "mousedown", this.mouseDownHandler);
116 this.editing = false;
117 var newValue = this.getValue();
118 this.hide();
119 //if(focusCell){try{this.cell.focus();}catch(e){}}// try to give the cell focus so keyboard nav still works
120 if(this.originalValue != newValue){
121 this.callback(newValue, this.rowIndex, this.colIndex);
122 }
123 }
124 },
125
126 setValue : function(value){
127 this.element.dom.value = this.formatDate(value);
128 this.validate();
129 },
130
131 getValue : function(){
132 if(!this.validate()){
133 return this.originalValue;
134 }else{
135 var value = this.element.dom.value;
136 if(value.length < 1){
137 return value;
138 } else{
139 return this.parseDate(value);
140 }
141 }
142 },
143
144 show : function() {
145 this.div.show();
146 this.element.focus();
147 this.validate();
148 },
149
150 hide : function(){
151 try{
152 this.element.dom.blur();
153 }catch(e){}
154 this.div.hide();
155 },
156
157 validate : function(){
158 var dom = this.element.dom;
159 var value = dom.value;
160 if(value.length < 1){ // if it's blank
161 if(this.allowBlank){
162 dom.title = '';
163 this.element.removeClass('ygrid-editor-invalid');
164 return true;
165 }else{
166 dom.title = this.blankText;
167 this.element.addClass('ygrid-editor-invalid');
168 return false;
169 }
170 }
171 value = this.parseDate(value);
172 if(!value){
173 dom.title = this.invalidText.replace('%0', dom.value).replace('%1', this.format);
174 this.element.addClass('ygrid-editor-invalid');
175 return false;
176 }
177 var time = value.getTime();
178 if(this.minValue && time < this.minValue.getTime()){
179 dom.title = this.minText.replace('%0', this.formatDate(this.minValue));
180 this.element.addClass('ygrid-editor-invalid');
181 return false;
182 }
183 if(this.maxValue && time > this.maxValue.getTime()){
184 dom.title = this.maxText.replace('%0', this.formatDate(this.maxValue));
185 this.element.addClass('ygrid-editor-invalid');
186 return false;
187 }
188 if(this.disabledDays){
189 var day = value.getDay();
190 for(var i = 0; i < this.disabledDays.length; i++) {
191 if(day === this.disabledDays[i]){
192 dom.title = this.disabledDaysText;
193 this.element.addClass('ygrid-editor-invalid');
194 return false;
195 }
196 }
197 }
198 var fvalue = this.formatDate(value);
199 if(this.ddMatch.test(fvalue)){
200 dom.title = this.disabledDatesText.replace('%0', fvalue);
201 this.element.addClass('ygrid-editor-invalid');
202 return false;
203 }
204 var msg = this.validator(value);
205 if(msg !== true){
206 dom.title = msg;
207 this.element.addClass('ygrid-editor-invalid');
208 return false;
209 }
210 dom.title = '';
211 this.element.removeClass('ygrid-editor-invalid');
212 return true;
213 },
214
215 handleMouseDown : function(e){
216 var t = e.getTarget();
217 var dom = this.div.dom;
218 if(t != dom && !YAHOO.util.Dom.isAncestor(dom, t)){
219 this.stopEditing();
220 }
221 },
222
223 showCalendar : function(value){
224 if(this.cal == null){
225 this.cal = new YAHOO.ext.DatePicker(this.div.dom.parentNode.parentNode);
226 }
227 this.cal.minDate = this.minValue;
228 this.cal.maxDate = this.maxValue;
229 this.cal.disabledDatesRE = this.ddMatch;
230 this.cal.disabledDatesText = this.disabledDatesText;
231 this.cal.disabledDays = this.disabledDays;
232 this.cal.disabledDaysText = this.disabledDaysText;
233 this.cal.format = this.format;
234 if(this.minValue){
235 this.cal.minText = this.minText.replace('%0', this.formatDate(this.minValue));
236 }
237 if(this.maxValue){
238 this.cal.maxText = this.maxText.replace('%0', this.formatDate(this.maxValue));
239 }
240 var r = this.div.getRegion();
241 this.cal.show(r.left, r.bottom, this.getValue(), this.setValue.createDelegate(this));
242 },
243
244 parseDate : function(value){
245 if(!value || value instanceof Date) return value;
246 return Date.parseDate(value, this.format);
247 },
248
249 formatDate : function(date){
250 if(!date || !(date instanceof Date)) return date;
251 return date.format(this.format);
252 }
253};
254
255YAHOO.ext.grid.DateEditor.prototype.format = 'm/d/y';
256YAHOO.ext.grid.DateEditor.prototype.disabledDays = null;
257YAHOO.ext.grid.DateEditor.prototype.disabledDaysText = '';
258YAHOO.ext.grid.DateEditor.prototype.disabledDates = null;
259YAHOO.ext.grid.DateEditor.prototype.disabledDatesText = '';
260YAHOO.ext.grid.DateEditor.prototype.allowBlank = true;
261YAHOO.ext.grid.DateEditor.prototype.minValue = null;
262YAHOO.ext.grid.DateEditor.prototype.maxValue = null;
263YAHOO.ext.grid.DateEditor.prototype.minText = 'The date in this field must be after %0';
264YAHOO.ext.grid.DateEditor.prototype.maxText = 'The date in this field must be before %0';
265YAHOO.ext.grid.DateEditor.prototype.blankText = 'This field cannot be blank';
266YAHOO.ext.grid.DateEditor.prototype.invalidText = '%0 is not a valid date - it must be in the format %1';
267YAHOO.ext.grid.DateEditor.prototype.validationDelay = 200;
268YAHOO.ext.grid.DateEditor.prototype.validator = function(){return true;};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js
new file mode 100644
index 0000000..f74d3d9
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/NumberEditor.js
@@ -0,0 +1,166 @@
1/**
2 * @class YAHOO.ext.grid.NumberEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides a masked editor for numeric values. Invalid keys are ignored. It supports the following configuration options:
5<ul class="list">
6<li><i>allowDecimals</i> - True if the cell can have decimal values.</li>
7<li><i>decimalSeparator</i> - Character(s) to allow as the decimal separator.</li>
8<li><i>decimalPrecision</i> - Set the maximum decimal precision.</li>
9<li><i>decimalPrecisionFcn</i> - Define the function to call to remove extra precision (ie. Math.floor, Math.round, Math.ceil or your own function).</li>
10<li><i>allowNegative</i> - True if the cell allows negative values.</li>
11<li><i>selectOnFocus</i> - True to select the text when the editor is activated.</li>
12<li><i>minValue</i> - The minimum value the cell will allow.</li>
13<li><i>maxValue</i> - The maximum value the cell will allow.</li>
14<li><i>minText</i> - The tooltip to display when the value in the cell is below the minimum.</li>
15<li><i>maxText</i> - The tooltip to display when the value in the cell is above the maximum.</li>
16<li><i>nanText</i> - The tooltip to display when the value in the cell is not a valid number (for example, negatives are allowed and the value in the cell is just "-" with no numbers).</li>
17<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
18<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
19<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
20<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
21</ul>
22For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
23* @constructor
24* Create a new NumberEditor
25* @param {Object} config
26 */
27YAHOO.ext.grid.NumberEditor = function(config){
28 var element = document.createElement('input');
29 element.type = 'text';
30 element.className = 'ygrid-editor ygrid-num-editor';
31 element.setAttribute('autocomplete', 'off');
32 document.body.appendChild(element);
33 YAHOO.ext.grid.NumberEditor.superclass.constructor.call(this, element);
34 YAHOO.ext.util.Config.apply(this, config);
35};
36YAHOO.extendX(YAHOO.ext.grid.NumberEditor, YAHOO.ext.grid.CellEditor);
37
38YAHOO.ext.grid.NumberEditor.prototype.initEvents = function(){
39 var stopOnEnter = function(e){
40 if(e.browserEvent.keyCode == e.RETURN){
41 this.stopEditing(true);
42 }else if(e.browserEvent.keyCode == e.ESC){
43 this.setValue(this.originalValue);
44 this.stopEditing(true);
45 }
46 };
47
48 var allowed = "0123456789";
49 if(this.allowDecimals){
50 allowed += this.decimalSeparator;
51 }
52 if(this.allowNegative){
53 allowed += '-';
54 }
55 var keyPress = function(e){
56 var c = e.getCharCode();
57 if(c != e.BACKSPACE && allowed.indexOf(String.fromCharCode(c)) === -1){
58 e.stopEvent();
59 }
60 };
61 this.element.mon('keydown', stopOnEnter, this, true);
62 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
63 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
64 this.element.mon('keypress', keyPress, this, true);
65 this.element.on('blur', this.stopEditing, this, true);
66};
67
68YAHOO.ext.grid.NumberEditor.prototype.validate = function(){
69 var dom = this.element.dom;
70 var value = dom.value;
71 if(value.length < 1){ // if it's blank
72 if(this.allowBlank){
73 dom.title = '';
74 this.element.removeClass('ygrid-editor-invalid');
75 return true;
76 }else{
77 dom.title = this.blankText;
78 this.element.addClass('ygrid-editor-invalid');
79 return false;
80 }
81 }
82 if(value.search(/\d+/) === -1){
83 dom.title = this.nanText.replace('%0', value);
84 this.element.addClass('ygrid-editor-invalid');
85 return false;
86 }
87 var num = this.parseValue(value);
88 if(num < this.minValue){
89 dom.title = this.minText.replace('%0', this.minValue);
90 this.element.addClass('ygrid-editor-invalid');
91 return false;
92 }
93 if(num > this.maxValue){
94 dom.title = this.maxText.replace('%0', this.maxValue);
95 this.element.addClass('ygrid-editor-invalid');
96 return false;
97 }
98 var msg = this.validator(value);
99 if(msg !== true){
100 dom.title = msg;
101 this.element.addClass('ygrid-editor-invalid');
102 return false;
103 }
104 dom.title = '';
105 this.element.removeClass('ygrid-editor-invalid');
106 return true;
107};
108
109YAHOO.ext.grid.NumberEditor.prototype.show = function(){
110 this.element.dom.title = '';
111 YAHOO.ext.grid.NumberEditor.superclass.show.call(this);
112 if(this.selectOnFocus){
113 try{
114 this.element.dom.select();
115 }catch(e){}
116 }
117 this.validate(this.element.dom.value);
118};
119
120YAHOO.ext.grid.NumberEditor.prototype.getValue = function(){
121 if(!this.validate()){
122 return this.originalValue;
123 }else{
124 var value = this.element.dom.value;
125 if(value.length < 1){
126 return value;
127 } else{
128 return this.fixPrecision(this.parseValue(value));
129 }
130 }
131};
132YAHOO.ext.grid.NumberEditor.prototype.parseValue = function(value){
133 return parseFloat(new String(value).replace(this.decimalSeparator, '.'));
134};
135
136YAHOO.ext.grid.NumberEditor.prototype.fixPrecision = function(value){
137 if(!this.allowDecimals || this.decimalPrecision == -1 || isNaN(value) || value == 0 || !value){
138 return value;
139 }
140 // this should work but doesn't due to precision error in JS
141 // var scale = Math.pow(10, this.decimalPrecision);
142 // var fixed = this.decimalPrecisionFcn(value * scale);
143 // return fixed / scale;
144 //
145 // so here's our workaround:
146 var scale = Math.pow(10, this.decimalPrecision+1);
147 var fixed = this.decimalPrecisionFcn(value * scale);
148 fixed = this.decimalPrecisionFcn(fixed/10);
149 return fixed / (scale/10);
150};
151
152YAHOO.ext.grid.NumberEditor.prototype.allowBlank = true;
153YAHOO.ext.grid.NumberEditor.prototype.allowDecimals = true;
154YAHOO.ext.grid.NumberEditor.prototype.decimalSeparator = '.';
155YAHOO.ext.grid.NumberEditor.prototype.decimalPrecision = 2;
156YAHOO.ext.grid.NumberEditor.prototype.decimalPrecisionFcn = Math.floor;
157YAHOO.ext.grid.NumberEditor.prototype.allowNegative = true;
158YAHOO.ext.grid.NumberEditor.prototype.selectOnFocus = true;
159YAHOO.ext.grid.NumberEditor.prototype.minValue = Number.NEGATIVE_INFINITY;
160YAHOO.ext.grid.NumberEditor.prototype.maxValue = Number.MAX_VALUE;
161YAHOO.ext.grid.NumberEditor.prototype.minText = 'The minimum value for this field is %0';
162YAHOO.ext.grid.NumberEditor.prototype.maxText = 'The maximum value for this field is %0';
163YAHOO.ext.grid.NumberEditor.prototype.blankText = 'This field cannot be blank';
164YAHOO.ext.grid.NumberEditor.prototype.nanText = '%0 is not a valid number';
165YAHOO.ext.grid.NumberEditor.prototype.validationDelay = 100;
166YAHOO.ext.grid.NumberEditor.prototype.validator = function(){return true;};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js
new file mode 100644
index 0000000..200b8e3
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/SelectEditor.js
@@ -0,0 +1,37 @@
1/**
2 * @class YAHOO.ext.grid.SelectEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Creates an editor out of an existing select field. You can create the select element through DOM in Javascript and pass it to the SelectEditor's constructor <b>or</b> an easier way is like this:
5<br><br>
6Define the select field in your document, giving it the ygrid-editor class.
7<pre><code>
8&lt;select id="light" class="ygrid-editor"&gt;
9 &lt;option value="Shade"&gt;Shade&lt;/option&gt;
10 &lt;option value="Mostly Shady"&gt;Mostly Shady&lt;/option&gt;
11 &lt;option value="Sun or Shade"&gt;Sun or Shade&lt;/option&gt;
12 &lt;option value="Mostly Sunny"&gt;Mostly Sunny&lt;/option&gt;
13 &lt;option value="Sunny"&gt;Sunny&lt;/option&gt;
14&lt;/select&gt;
15</code></pre>
16Create the SelectEditor object, passing in the id of your select field.
17<pre><code>
18var editor = new YAHOO.ext.grid.SelectEditor('light');
19</code></pre>
20For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
21* @constructor
22* Create a new SelectEditor
23* @param {HTMLElement/String} element
24 */
25YAHOO.ext.grid.SelectEditor = function(element){
26 element.hideFocus = true;
27 YAHOO.ext.grid.SelectEditor.superclass.constructor.call(this, element);
28 this.element.swallowEvent('click');
29};
30YAHOO.extendX(YAHOO.ext.grid.SelectEditor, YAHOO.ext.grid.CellEditor);
31
32YAHOO.ext.grid.SelectEditor.prototype.fitToCell = function(box){
33 if(YAHOO.ext.util.Browser.isGecko){
34 box.height -= 3;
35 }
36 this.element.setBox(box, true);
37};
diff --git a/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js b/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js
new file mode 100644
index 0000000..3c97acd
--- a/dev/null
+++ b/frontend/beta/js/YUI-extensions/grid/editor/TextEditor.js
@@ -0,0 +1,110 @@
1/**
2 * @class YAHOO.ext.grid.TextEditor
3 * @extends YAHOO.ext.grid.CellEditor
4Provides basic text editing for a cells and supports the following configuration options:
5<ul class="list">
6<li><i>allowBlank</i> - True if the cell is allowed to be empty.</li>
7<li><i>minLength</i> - The minimum length the cell will accept.</li>
8<li><i>maxLength</i> - The maximum length the cell will allow.</li>
9<li><i>minText</i> - The tooltip to display when the length of the value in the cell is below the minimum.</li>
10<li><i>maxText</i> - The tooltip to display when the length of the value in the cell is above the maximum.</li>
11<li><i>selectOnFocus</i> - True to select the text when the editor is activated.</li>
12<li><i>blankText</i> - The tooltip (error message) to display when the cell is empty and is not allowed to be.</li>
13<li><i>regex</i> - A regular expression to match if the value is valid. If the regex.test(value) returns false, the value is considered invalid.</li>
14<li><i>regexText</i> - The tooltip (error message) to display when regex does not match.</li>
15<li><i>validator</i> - Any custom validation function you want called. The function must return true if the data is valid or an error message otherwise.</li>
16<li><i>validationDelay</i> - The delay in milliseconds for validation. Each time the user types something the field is validated after a specified delay, setting this value allows you to customize that delay (for example, if your custom validation routine is slow).</li>
17</ul>
18For more information on using this editor, see <a href="http://www.jackslocum.com/yui/2006/09/10/adding-built-in-editing-support-to-the-yahoo-ui-extensions-grid/">this blog post</a>.
19* @constructor
20* Create a new TextEditor
21* @param {Object} config
22 */
23YAHOO.ext.grid.TextEditor = function(config){
24 var element = document.createElement('input');
25 element.type = 'text';
26 element.className = 'ygrid-editor ygrid-text-editor';
27 element.setAttribute('autocomplete', 'off');
28 document.body.appendChild(element);
29 YAHOO.ext.grid.TextEditor.superclass.constructor.call(this, element);
30 YAHOO.ext.util.Config.apply(this, config);
31};
32YAHOO.extendX(YAHOO.ext.grid.TextEditor, YAHOO.ext.grid.CellEditor);
33
34YAHOO.ext.grid.TextEditor.prototype.validate = function(){
35 var dom = this.element.dom;
36 var value = dom.value;
37 if(value.length < 1){ // if it's blank
38 if(this.allowBlank){
39 dom.title = '';
40 this.element.removeClass('ygrid-editor-invalid');
41 return true;
42 }else{
43 dom.title = this.blankText;
44 this.element.addClass('ygrid-editor-invalid');
45 return false;
46 }
47 }
48 if(value.length < this.minLength){
49 dom.title = this.minText.replace('%0', this.minLength);
50 this.element.addClass('ygrid-editor-invalid');
51 return false;
52 }
53 if(value.length > this.maxLength){
54 dom.title = this.maxText.replace('%0', this.maxLength);
55 this.element.addClass('ygrid-editor-invalid');
56 return false;
57 }
58 var msg = this.validator(value);
59 if(msg !== true){
60 dom.title = msg;
61 this.element.addClass('ygrid-editor-invalid');
62 return false;
63 }
64 if(this.regex && !this.regex.test(value)){
65 dom.title = this.regexText;
66 this.element.addClass('ygrid-editor-invalid');
67 return false;
68 }
69 dom.title = '';
70 this.element.removeClass('ygrid-editor-invalid');
71 return true;
72};
73
74YAHOO.ext.grid.TextEditor.prototype.initEvents = function(){
75 YAHOO.ext.grid.TextEditor.superclass.initEvents.call(this);
76 var vtask = new YAHOO.ext.util.DelayedTask(this.validate, this);
77 this.element.mon('keyup', vtask.delay.createDelegate(vtask, [this.validationDelay]));
78};
79
80YAHOO.ext.grid.TextEditor.prototype.show = function(){
81 this.element.dom.title = '';
82 YAHOO.ext.grid.TextEditor.superclass.show.call(this);
83 this.element.focus();
84 if(this.selectOnFocus){
85 try{
86 this.element.dom.select();
87 }catch(e){}
88 }
89 this.validate(this.element.dom.value);
90};
91
92YAHOO.ext.grid.TextEditor.prototype.getValue = function(){
93 if(!this.validate()){
94 return this.originalValue;
95 }else{
96 return this.element.dom.value;
97 }
98};
99
100YAHOO.ext.grid.TextEditor.prototype.allowBlank = true;
101YAHOO.ext.grid.TextEditor.prototype.minLength = 0;
102YAHOO.ext.grid.TextEditor.prototype.maxLength = Number.MAX_VALUE;
103YAHOO.ext.grid.TextEditor.prototype.minText = 'The minimum length for this field is %0';
104YAHOO.ext.grid.TextEditor.prototype.maxText = 'The maximum length for this field is %0';
105YAHOO.ext.grid.TextEditor.prototype.selectOnFocus = true;
106YAHOO.ext.grid.TextEditor.prototype.blankText = 'This field cannot be blank';
107YAHOO.ext.grid.TextEditor.prototype.validator = function(){return true;};
108YAHOO.ext.grid.TextEditor.prototype.validationDelay = 200;
109YAHOO.ext.grid.TextEditor.prototype.regex = null;
110YAHOO.ext.grid.TextEditor.prototype.regexText = '';