RowEditor.js
上传用户:dawnssy
上传日期:2022-08-06
资源大小:9345k
文件大小:16k
源码类别:

JavaScript

开发平台:

JavaScript

  1. /*!
  2.  * Ext JS Library 3.1.0
  3.  * Copyright(c) 2006-2009 Ext JS, LLC
  4.  * licensing@extjs.com
  5.  * http://www.extjs.com/license
  6.  */
  7. Ext.ns('Ext.ux.grid');
  8. /**
  9.  * @class Ext.ux.grid.RowEditor
  10.  * @extends Ext.Panel 
  11.  * Plugin (ptype = 'roweditor') that adds the ability to rapidly edit full rows in a grid.
  12.  * A validation mode may be enabled which uses AnchorTips to notify the user of all
  13.  * validation errors at once.
  14.  * 
  15.  * @ptype roweditor
  16.  */
  17. Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {
  18.     floating: true,
  19.     shadow: false,
  20.     layout: 'hbox',
  21.     cls: 'x-small-editor',
  22.     buttonAlign: 'center',
  23.     baseCls: 'x-row-editor',
  24.     elements: 'header,footer,body',
  25.     frameWidth: 5,
  26.     buttonPad: 3,
  27.     clicksToEdit: 'auto',
  28.     monitorValid: true,
  29.     focusDelay: 250,
  30.     errorSummary: true,
  31.     
  32.     saveText: 'Save',
  33.     cancelText: 'Cancel',
  34.     commitChangesText: 'You need to commit or cancel your changes',
  35.     errorText: 'Errors',
  36.     defaults: {
  37.         normalWidth: true
  38.     },
  39.     initComponent: function(){
  40.         Ext.ux.grid.RowEditor.superclass.initComponent.call(this);
  41.         this.addEvents(
  42.             /**
  43.              * @event beforeedit
  44.              * Fired before the row editor is activated.
  45.              * If the listener returns <tt>false</tt> the editor will not be activated.
  46.              * @param {Ext.ux.grid.RowEditor} roweditor This object
  47.              * @param {Number} rowIndex The rowIndex of the row just edited
  48.              */
  49.             'beforeedit',
  50.             /**
  51.              * @event canceledit
  52.              * Fired when the editor is cancelled.
  53.              * @param {Ext.ux.grid.RowEditor} roweditor This object
  54.              * @param {Boolean} forced True if the cancel button is pressed, false is the editor was invalid. 
  55.              */
  56.             'canceledit',
  57.             /**
  58.              * @event validateedit
  59.              * Fired after a row is edited and passes validation.
  60.              * If the listener returns <tt>false</tt> changes to the record will not be set.
  61.              * @param {Ext.ux.grid.RowEditor} roweditor This object
  62.              * @param {Object} changes Object with changes made to the record.
  63.              * @param {Ext.data.Record} r The Record that was edited.
  64.              * @param {Number} rowIndex The rowIndex of the row just edited
  65.              */
  66.             'validateedit',
  67.             /**
  68.              * @event afteredit
  69.              * Fired after a row is edited and passes validation.  This event is fired
  70.              * after the store's update event is fired with this edit.
  71.              * @param {Ext.ux.grid.RowEditor} roweditor This object
  72.              * @param {Object} changes Object with changes made to the record.
  73.              * @param {Ext.data.Record} r The Record that was edited.
  74.              * @param {Number} rowIndex The rowIndex of the row just edited
  75.              */
  76.             'afteredit'
  77.         );
  78.     },
  79.     init: function(grid){
  80.         this.grid = grid;
  81.         this.ownerCt = grid;
  82.         if(this.clicksToEdit === 2){
  83.             grid.on('rowdblclick', this.onRowDblClick, this);
  84.         }else{
  85.             grid.on('rowclick', this.onRowClick, this);
  86.             if(Ext.isIE){
  87.                 grid.on('rowdblclick', this.onRowDblClick, this);
  88.             }
  89.         }
  90.         // stopEditing without saving when a record is removed from Store.
  91.         grid.getStore().on('remove', function() {
  92.             this.stopEditing(false);
  93.         },this);
  94.         grid.on({
  95.             scope: this,
  96.             keydown: this.onGridKey,
  97.             columnresize: this.verifyLayout,
  98.             columnmove: this.refreshFields,
  99.             reconfigure: this.refreshFields,
  100.         beforedestroy : this.beforedestroy,
  101.         destroy : this.destroy,
  102.             bodyscroll: {
  103.                 buffer: 250,
  104.                 fn: this.positionButtons
  105.             }
  106.         });
  107.         grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});
  108.         grid.getView().on('refresh', this.stopEditing.createDelegate(this, []));
  109.     },
  110.     beforedestroy: function() {
  111.         this.grid.getStore().un('remove', this.onStoreRemove, this);
  112.         this.stopEditing(false);
  113.         Ext.destroy(this.btns);
  114.     },
  115.     refreshFields: function(){
  116.         this.initFields();
  117.         this.verifyLayout();
  118.     },
  119.     isDirty: function(){
  120.         var dirty;
  121.         this.items.each(function(f){
  122.             if(String(this.values[f.id]) !== String(f.getValue())){
  123.                 dirty = true;
  124.                 return false;
  125.             }
  126.         }, this);
  127.         return dirty;
  128.     },
  129.     startEditing: function(rowIndex, doFocus){
  130.         if(this.editing && this.isDirty()){
  131.             this.showTooltip(this.commitChangesText);
  132.             return;
  133.         }
  134.         if(Ext.isObject(rowIndex)){
  135.             rowIndex = this.grid.getStore().indexOf(rowIndex);
  136.         }
  137.         if(this.fireEvent('beforeedit', this, rowIndex) !== false){
  138.             this.editing = true;
  139.             var g = this.grid, view = g.getView(),
  140.                 row = view.getRow(rowIndex),
  141.                 record = g.store.getAt(rowIndex);
  142.                 
  143.             this.record = record;
  144.             this.rowIndex = rowIndex;
  145.             this.values = {};
  146.             if(!this.rendered){
  147.                 this.render(view.getEditorParent());
  148.             }
  149.             var w = Ext.fly(row).getWidth();
  150.             this.setSize(w);
  151.             if(!this.initialized){
  152.                 this.initFields();
  153.             }
  154.             var cm = g.getColumnModel(), fields = this.items.items, f, val;
  155.             for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  156.                 val = this.preEditValue(record, cm.getDataIndex(i));
  157.                 f = fields[i];
  158.                 f.setValue(val);
  159.                 this.values[f.id] = Ext.isEmpty(val) ? '' : val;
  160.             }
  161.             this.verifyLayout(true);
  162.             if(!this.isVisible()){
  163.                 this.setPagePosition(Ext.fly(row).getXY());
  164.             } else{
  165.                 this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});
  166.             }
  167.             if(!this.isVisible()){
  168.                 this.show().doLayout();
  169.             }
  170.             if(doFocus !== false){
  171.                 this.doFocus.defer(this.focusDelay, this);
  172.             }
  173.         }
  174.     },
  175.     stopEditing : function(saveChanges){
  176.         this.editing = false;
  177.         if(!this.isVisible()){
  178.             return;
  179.         }
  180.         if(saveChanges === false || !this.isValid()){
  181.             this.hide();
  182.             this.fireEvent('canceledit', this, saveChanges === false);
  183.             return;
  184.         }
  185.         var changes = {}, 
  186.             r = this.record, 
  187.             hasChange = false,
  188.             cm = this.grid.colModel, 
  189.             fields = this.items.items;
  190.         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  191.             if(!cm.isHidden(i)){
  192.                 var dindex = cm.getDataIndex(i);
  193.                 if(!Ext.isEmpty(dindex)){
  194.                     var oldValue = r.data[dindex],
  195.                         value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);
  196.                     if(String(oldValue) !== String(value)){
  197.                         changes[dindex] = value;
  198.                         hasChange = true;
  199.                     }
  200.                 }
  201.             }
  202.         }
  203.         if(hasChange && this.fireEvent('validateedit', this, changes, r, this.rowIndex) !== false){
  204.             r.beginEdit();
  205.             Ext.iterate(changes, function(name, value){
  206.                 r.set(name, value);
  207.             });
  208.             r.endEdit();
  209.             this.fireEvent('afteredit', this, changes, r, this.rowIndex);
  210.         }
  211.         this.hide();
  212.     },
  213.     verifyLayout: function(force){
  214.         if(this.el && (this.isVisible() || force === true)){
  215.             var row = this.grid.getView().getRow(this.rowIndex);
  216.             this.setSize(Ext.fly(row).getWidth(), Ext.fly(row).getHeight() + 9);
  217.             var cm = this.grid.colModel, fields = this.items.items;
  218.             for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  219.                 if(!cm.isHidden(i)){
  220.                     var adjust = 0;
  221.                     if(i === (len - 1)){
  222.                         adjust += 3; // outer padding
  223.                     } else{
  224.                         adjust += 1;
  225.                     }
  226.                     fields[i].show();
  227.                     fields[i].setWidth(cm.getColumnWidth(i) - adjust);
  228.                 } else{
  229.                     fields[i].hide();
  230.                 }
  231.             }
  232.             this.doLayout();
  233.             this.positionButtons();
  234.         }
  235.     },
  236.     slideHide : function(){
  237.         this.hide();
  238.     },
  239.     initFields: function(){
  240.         var cm = this.grid.getColumnModel(), pm = Ext.layout.ContainerLayout.prototype.parseMargins;
  241.         this.removeAll(false);
  242.         for(var i = 0, len = cm.getColumnCount(); i < len; i++){
  243.             var c = cm.getColumnAt(i),
  244.                 ed = c.getEditor();
  245.             if(!ed){
  246.                 ed = c.displayEditor || new Ext.form.DisplayField();
  247.             }
  248.             if(i == 0){
  249.                 ed.margins = pm('0 1 2 1');
  250.             } else if(i == len - 1){
  251.                 ed.margins = pm('0 0 2 1');
  252.             } else{
  253.                 ed.margins = pm('0 1 2');
  254.             }
  255.             ed.setWidth(cm.getColumnWidth(i));
  256.             ed.column = c;
  257.             if(ed.ownerCt !== this){
  258.                 ed.on('focus', this.ensureVisible, this);
  259.                 ed.on('specialkey', this.onKey, this);
  260.             }
  261.             this.insert(i, ed);
  262.         }
  263.         this.initialized = true;
  264.     },
  265.     onKey: function(f, e){
  266.         if(e.getKey() === e.ENTER){
  267.             this.stopEditing(true);
  268.             e.stopPropagation();
  269.         }
  270.     },
  271.     onGridKey: function(e){
  272.         if(e.getKey() === e.ENTER && !this.isVisible()){
  273.             var r = this.grid.getSelectionModel().getSelected();
  274.             if(r){
  275.                 var index = this.grid.store.indexOf(r);
  276.                 this.startEditing(index);
  277.                 e.stopPropagation();
  278.             }
  279.         }
  280.     },
  281.     ensureVisible: function(editor){
  282.         if(this.isVisible()){
  283.              this.grid.getView().ensureVisible(this.rowIndex, this.grid.colModel.getIndexById(editor.column.id), true);
  284.         }
  285.     },
  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()){
  291.                 return;
  292.             }
  293.         }
  294.         this.startEditing(rowIndex, false);
  295.         this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
  296.     },
  297.     onRowDblClick: function(g, rowIndex, e){
  298.         this.startEditing(rowIndex, false);
  299.         this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);
  300.     },
  301.     onRender: function(){
  302.         Ext.ux.grid.RowEditor.superclass.onRender.apply(this, arguments);
  303.         this.el.swallowEvent(['keydown', 'keyup', 'keypress']);
  304.         this.btns = new Ext.Panel({
  305.             baseCls: 'x-plain',
  306.             cls: 'x-btns',
  307.             elements:'body',
  308.             layout: 'table',
  309.             width: (this.minButtonWidth * 2) + (this.frameWidth * 2) + (this.buttonPad * 4), // width must be specified for IE
  310.             items: [{
  311.                 ref: 'saveBtn',
  312.                 itemId: 'saveBtn',
  313.                 xtype: 'button',
  314.                 text: this.saveText,
  315.                 width: this.minButtonWidth,
  316.                 handler: this.stopEditing.createDelegate(this, [true])
  317.             }, {
  318.                 xtype: 'button',
  319.                 text: this.cancelText,
  320.                 width: this.minButtonWidth,
  321.                 handler: this.stopEditing.createDelegate(this, [false])
  322.             }]
  323.         });
  324.         this.btns.render(this.bwrap);
  325.     },
  326.     afterRender: function(){
  327.         Ext.ux.grid.RowEditor.superclass.afterRender.apply(this, arguments);
  328.         this.positionButtons();
  329.         if(this.monitorValid){
  330.             this.startMonitoring();
  331.         }
  332.     },
  333.     onShow: function(){
  334.         if(this.monitorValid){
  335.             this.startMonitoring();
  336.         }
  337.         Ext.ux.grid.RowEditor.superclass.onShow.apply(this, arguments);
  338.     },
  339.     onHide: function(){
  340.         Ext.ux.grid.RowEditor.superclass.onHide.apply(this, arguments);
  341.         this.stopMonitoring();
  342.         this.grid.getView().focusRow(this.rowIndex);
  343.     },
  344.     positionButtons: function(){
  345.         if(this.btns){
  346.             var g = this.grid,
  347.                 h = this.el.dom.clientHeight,
  348.                 view = g.getView(),
  349.                 scroll = view.scroller.dom.scrollLeft,
  350.                 bw = this.btns.getWidth(),
  351.                 width = Math.min(g.getWidth(), g.getColumnModel().getTotalWidth());
  352.                 
  353.             this.btns.el.shift({left: (width/2)-(bw/2)+scroll, top: h - 2, stopFx: true, duration:0.2});
  354.         }
  355.     },
  356.     // private
  357.     preEditValue : function(r, field){
  358.         var value = r.data[field];
  359.         return this.autoEncode && typeof value === 'string' ? Ext.util.Format.htmlDecode(value) : value;
  360.     },
  361.     // private
  362.     postEditValue : function(value, originalValue, r, field){
  363.         return this.autoEncode && typeof value == 'string' ? Ext.util.Format.htmlEncode(value) : value;
  364.     },
  365.     doFocus: function(pt){
  366.         if(this.isVisible()){
  367.             var index = 0,
  368.                 cm = this.grid.getColumnModel(),
  369.                 c;
  370.             if(pt){
  371.                 index = this.getTargetColumnIndex(pt);
  372.             }
  373.             for(var i = index||0, len = cm.getColumnCount(); i < len; i++){
  374.                 c = cm.getColumnAt(i);
  375.                 if(!c.hidden && c.getEditor()){
  376.                     c.getEditor().focus();
  377.                     break;
  378.                 }
  379.             }
  380.         }
  381.     },
  382.     getTargetColumnIndex: function(pt){
  383.         var grid = this.grid, 
  384.             v = grid.view,
  385.             x = pt.left,
  386.             cms = grid.colModel.config,
  387.             i = 0, 
  388.             match = false;
  389.         for(var len = cms.length, c; c = cms[i]; i++){
  390.             if(!c.hidden){
  391.                 if(Ext.fly(v.getHeaderCell(i)).getRegion().right >= x){
  392.                     match = i;
  393.                     break;
  394.                 }
  395.             }
  396.         }
  397.         return match;
  398.     },
  399.     startMonitoring : function(){
  400.         if(!this.bound && this.monitorValid){
  401.             this.bound = true;
  402.             Ext.TaskMgr.start({
  403.                 run : this.bindHandler,
  404.                 interval : this.monitorPoll || 200,
  405.                 scope: this
  406.             });
  407.         }
  408.     },
  409.     stopMonitoring : function(){
  410.         this.bound = false;
  411.         if(this.tooltip){
  412.             this.tooltip.hide();
  413.         }
  414.     },
  415.     isValid: function(){
  416.         var valid = true;
  417.         this.items.each(function(f){
  418.             if(!f.isValid(true)){
  419.                 valid = false;
  420.                 return false;
  421.             }
  422.         });
  423.         return valid;
  424.     },
  425.     // private
  426.     bindHandler : function(){
  427.         if(!this.bound){
  428.             return false; // stops binding
  429.         }
  430.         var valid = this.isValid();
  431.         if(!valid && this.errorSummary){
  432.             this.showTooltip(this.getErrorText().join(''));
  433.         }
  434.         this.btns.saveBtn.setDisabled(!valid);
  435.         this.fireEvent('validation', this, valid);
  436.     },
  437.     showTooltip: function(msg){
  438.         var t = this.tooltip;
  439.         if(!t){
  440.             t = this.tooltip = new Ext.ToolTip({
  441.                 maxWidth: 600,
  442.                 cls: 'errorTip',
  443.                 width: 300,
  444.                 title: this.errorText,
  445.                 autoHide: false,
  446.                 anchor: 'left',
  447.                 anchorToTarget: true,
  448.                 mouseOffset: [40,0]
  449.             });
  450.         }
  451.         var v = this.grid.getView(),
  452.             top = parseInt(this.el.dom.style.top, 10),
  453.             scroll = v.scroller.dom.scrollTop,
  454.             h = this.el.getHeight();
  455.                 
  456.         if(top + h >= scroll){
  457.             t.initTarget(this.items.last().getEl());
  458.             if(!t.rendered){
  459.                 t.show();
  460.                 t.hide();
  461.             }
  462.             t.body.update(msg);
  463.             t.doAutoWidth(20);
  464.             t.show();
  465.         }else if(t.rendered){
  466.             t.hide();
  467.         }
  468.     },
  469.     getErrorText: function(){
  470.         var data = ['<ul>'];
  471.         this.items.each(function(f){
  472.             if(!f.isValid(true)){
  473.                 data.push('<li>', f.getActiveError(), '</li>');
  474.             }
  475.         });
  476.         data.push('</ul>');
  477.         return data;
  478.     }
  479. });
  480. Ext.preg('roweditor', Ext.ux.grid.RowEditor);