3 <title>The source code</title>
\r
4 <link href="../resources/prettify/prettify.css" type="text/css" rel="stylesheet" />
\r
5 <script type="text/javascript" src="../resources/prettify/prettify.js"></script>
\r
7 <body onload="prettyPrint();">
\r
8 <pre class="prettyprint lang-js">Ext.ns('Ext.ux.grid');
10 <div id="cls-Ext.ux.grid.RowEditor"></div>/**
11 * @class Ext.ux.grid.RowEditor
13 * Plugin (ptype = 'roweditor') that adds the ability to rapidly edit full rows in a grid.
14 * A validation mode may be enabled which uses AnchorTips to notify the user of all
15 * validation errors at once.
19 Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
23 cls: 'x-small-editor',
24 buttonAlign: 'center',
25 baseCls: 'x-row-editor',
26 elements: 'header,footer,body',
38 initComponent: function(){
39 Ext.ux.grid.RowEditor.superclass.initComponent.call(this);
41 <div id="event-Ext.ux.grid.RowEditor-beforeedit"></div>/**
43 * Fired before the row editor is activated.
44 * If the listener returns <tt>false</tt> the editor will not be activated.
45 * @param {Ext.ux.grid.RowEditor} roweditor This object
46 * @param {Number} rowIndex The rowIndex of the row just edited
49 <div id="event-Ext.ux.grid.RowEditor-validateedit"></div>/**
51 * Fired after a row is edited and passes validation.
52 * If the listener returns <tt>false</tt> changes to the record will not be set.
53 * @param {Ext.ux.grid.RowEditor} roweditor This object
54 * @param {Object} changes Object with changes made to the record.
55 * @param {Ext.data.Record} r The Record that was edited.
56 * @param {Number} rowIndex The rowIndex of the row just edited
59 <div id="event-Ext.ux.grid.RowEditor-afteredit"></div>/**
61 * Fired after a row is edited and passes validation. This event is fired
62 * after the store's update event is fired with this edit.
63 * @param {Ext.ux.grid.RowEditor} roweditor This object
64 * @param {Object} changes Object with changes made to the record.
65 * @param {Ext.data.Record} r The Record that was edited.
66 * @param {Number} rowIndex The rowIndex of the row just edited
75 if(this.clicksToEdit === 2){
76 grid.on('rowdblclick', this.onRowDblClick, this);
78 grid.on('rowclick', this.onRowClick, this);
80 grid.on('rowdblclick', this.onRowDblClick, this);
84 // stopEditing without saving when a record is removed from Store.
85 grid.getStore().on('remove', function() {
86 this.stopEditing(false);
91 keydown: this.onGridKey,
92 columnresize: this.verifyLayout,
93 columnmove: this.refreshFields,
94 reconfigure: this.refreshFields,
95 destroy : this.destroy,
98 fn: this.positionButtons
101 grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});
102 grid.getView().on('refresh', this.stopEditing.createDelegate(this, []));
105 refreshFields: function(){
112 this.items.each(function(f){
113 if(String(this.values[f.id]) !== String(f.getValue())){
121 startEditing: function(rowIndex, doFocus){
122 if(this.editing && this.isDirty()){
123 this.showTooltip('You need to commit or cancel your changes');
127 if(typeof rowIndex == 'object'){
128 rowIndex = this.grid.getStore().indexOf(rowIndex);
130 if(this.fireEvent('beforeedit', this, rowIndex) !== false){
131 var g = this.grid, view = g.getView();
132 var row = view.getRow(rowIndex);
133 var record = g.store.getAt(rowIndex);
134 this.record = record;
135 this.rowIndex = rowIndex;
138 this.render(view.getEditorParent());
140 var w = Ext.fly(row).getWidth();
142 if(!this.initialized){
145 var cm = g.getColumnModel(), fields = this.items.items, f, val;
146 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
147 val = this.preEditValue(record, cm.getDataIndex(i));
150 this.values[f.id] = val || '';
152 this.verifyLayout(true);
153 if(!this.isVisible()){
154 this.setPagePosition(Ext.fly(row).getXY());
156 this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
158 if(!this.isVisible()){
159 this.show().doLayout();
161 if(doFocus !== false){
162 this.doFocus.defer(this.focusDelay, this);
167 stopEditing : function(saveChanges){
168 this.editing = false;
169 if(!this.isVisible()){
172 if(saveChanges === false || !this.isValid()){
176 var changes = {}, r = this.record, hasChange = false;
177 var cm = this.grid.colModel, fields = this.items.items;
178 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
180 var dindex = cm.getDataIndex(i);
181 if(!Ext.isEmpty(dindex)){
182 var oldValue = r.data[dindex];
183 var value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);
184 if(String(oldValue) !== String(value)){
185 changes[dindex] = value;
191 if(hasChange && this.fireEvent('validateedit', this, changes, r, this.rowIndex) !== false){
193 for(var k in changes){
194 if(changes.hasOwnProperty(k)){
195 r.set(k, changes[k]);
199 this.fireEvent('afteredit', this, changes, r, this.rowIndex);
204 verifyLayout: function(force){
205 if(this.el && (this.isVisible() || force === true)){
206 var row = this.grid.getView().getRow(this.rowIndex);
207 this.setSize(Ext.fly(row).getWidth(), Ext.isIE ? Ext.fly(row).getHeight() + (Ext.isBorderBox ? 9 : 0) : undefined);
208 var cm = this.grid.colModel, fields = this.items.items;
209 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
213 adjust += 0; // outer padding
216 adjust += 3; // outer padding
221 fields[i].setWidth(cm.getColumnWidth(i) - adjust);
227 this.positionButtons();
231 slideHide : function(){
235 initFields: function(){
236 var cm = this.grid.getColumnModel(), pm = Ext.layout.ContainerLayout.prototype.parseMargins;
237 this.removeAll(false);
238 for(var i = 0, len = cm.getColumnCount(); i < len; i++){
239 var c = cm.getColumnAt(i);
240 var ed = c.getEditor();
242 ed = c.displayEditor || new Ext.form.DisplayField();
245 ed.margins = pm('0 1 2 1');
246 } else if(i == len - 1){
247 ed.margins = pm('0 0 2 1');
249 ed.margins = pm('0 1 2');
251 ed.setWidth(cm.getColumnWidth(i));
253 if(ed.ownerCt !== this){
254 ed.on('focus', this.ensureVisible, this);
255 ed.on('specialkey', this.onKey, this);
259 this.initialized = true;
262 onKey: function(f, e){
263 if(e.getKey() === e.ENTER){
264 this.stopEditing(true);
269 onGridKey: function(e){
270 if(e.getKey() === e.ENTER && !this.isVisible()){
271 var r = this.grid.getSelectionModel().getSelected();
273 var index = this.grid.store.indexOf(r);
274 this.startEditing(index);
280 ensureVisible: function(editor){
281 if(this.isVisible()){
282 this.grid.getView().ensureVisible(this.rowIndex, this.grid.colModel.getIndexById(editor.column.id), true);
286 onRowClick: function(g, rowIndex, e){
287 if(this.clicksToEdit == 'auto'){
288 var li = this.lastClickIndex;
289 this.lastClickIndex = rowIndex;
290 if(li != rowIndex && !this.isVisible()){
294 this.startEditing(rowIndex, false);
295 this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
298 onRowDblClick: function(g, rowIndex, e){
299 this.startEditing(rowIndex, false);
300 this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
303 onRender: function(){
304 Ext.ux.grid.RowEditor.superclass.onRender.apply(this, arguments);
305 this.el.swallowEvent(['keydown', 'keyup', 'keypress']);
306 this.btns = new Ext.Panel({
311 width: (this.minButtonWidth * 2) + (this.frameWidth * 2) + (this.buttonPad * 4), // width must be specified for IE
316 text: this.saveText || 'Save',
317 width: this.minButtonWidth,
318 handler: this.stopEditing.createDelegate(this, [true])
321 text: this.cancelText || 'Cancel',
322 width: this.minButtonWidth,
323 handler: this.stopEditing.createDelegate(this, [false])
326 this.btns.render(this.bwrap);
329 afterRender: function(){
330 Ext.ux.grid.RowEditor.superclass.afterRender.apply(this, arguments);
331 this.positionButtons();
332 if(this.monitorValid){
333 this.startMonitoring();
338 if(this.monitorValid){
339 this.startMonitoring();
341 Ext.ux.grid.RowEditor.superclass.onShow.apply(this, arguments);
345 Ext.ux.grid.RowEditor.superclass.onHide.apply(this, arguments);
346 this.stopMonitoring();
347 this.grid.getView().focusRow(this.rowIndex);
350 positionButtons: function(){
352 var h = this.el.dom.clientHeight;
353 var view = this.grid.getView();
354 var scroll = view.scroller.dom.scrollLeft;
355 var width = view.mainBody.getWidth();
356 var bw = this.btns.getWidth();
357 this.btns.el.shift({left: (width/2)-(bw/2)+scroll, top: h - 2, stopFx: true, duration:0.2});
362 preEditValue : function(r, field){
363 var value = r.data[field];
364 return this.autoEncode && typeof value === 'string' ? Ext.util.Format.htmlDecode(value) : value;
368 postEditValue : function(value, originalValue, r, field){
369 return this.autoEncode && typeof value == 'string' ? Ext.util.Format.htmlEncode(value) : value;
372 doFocus: function(pt){
373 if(this.isVisible()){
376 index = this.getTargetColumnIndex(pt);
378 var cm = this.grid.getColumnModel();
379 for(var i = index||0, len = cm.getColumnCount(); i < len; i++){
380 var c = cm.getColumnAt(i);
381 if(!c.hidden && c.getEditor()){
382 c.getEditor().focus();
389 getTargetColumnIndex: function(pt){
390 var grid = this.grid, v = grid.view;
392 var cms = grid.colModel.config;
393 var i = 0, match = false;
394 for(var len = cms.length, c; c = cms[i]; i++){
396 if(Ext.fly(v.getHeaderCell(i)).getRegion().right >= x){
405 startMonitoring : function(){
406 if(!this.bound && this.monitorValid){
409 run : this.bindHandler,
410 interval : this.monitorPoll || 200,
416 stopMonitoring : function(){
425 this.items.each(function(f){
426 if(!f.isValid(true)){
435 bindHandler : function(){
437 return false; // stops binding
439 var valid = this.isValid();
440 if(!valid && this.errorSummary){
441 this.showTooltip(this.getErrorText().join(''));
443 this.btns.saveBtn.setDisabled(!valid);
444 this.fireEvent('validation', this, valid);
447 showTooltip: function(msg){
448 var t = this.tooltip;
450 t = this.tooltip = new Ext.ToolTip({
457 anchorToTarget: true,
461 t.initTarget(this.items.last().getEl());
471 getErrorText: function(){
473 this.items.each(function(f){
474 if(!f.isValid(true)){
475 data.push('<li>', f.activeError, '</li>');
482 Ext.preg('roweditor', Ext.ux.grid.RowEditor);
484 Ext.override(Ext.form.Field, {
485 markInvalid : function(msg){
486 if(!this.rendered || this.preventMark){ // not rendered
489 msg = msg || this.invalidText;
491 var mt = this.getMessageHandler();
494 }else if(this.msgTarget){
495 this.el.addClass(this.invalidClass);
496 var t = Ext.getDom(this.msgTarget);
499 t.style.display = this.msgDisplay;
502 this.activeError = msg;
503 this.fireEvent('invalid', this, msg);
507 Ext.override(Ext.ToolTip, {
508 doAutoWidth : function(){
509 var bw = this.body.getTextWidth();
511 bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));
513 bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + 20;
514 this.setWidth(bw.constrain(this.minWidth, this.maxWidth));
516 // IE7 repaint bug on initial show
517 if(Ext.isIE7 && !this.repainted){
519 this.repainted = true;