RowEditor.js
上传用户:shuoshiled
上传日期:2018-01-28
资源大小:10124k
文件大小:16k
源码类别:

中间件编程

开发平台:

JavaScript

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