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

中间件编程

开发平台:

JavaScript

  1.             layoutConfig:{columns:3}
  2.         });
  3.         p.add(this.fromMultiselect);
  4.         var icons = new Ext.Panel({header:false});
  5.         p.add(icons);
  6.         p.add(this.toMultiselect);
  7.         p.render(this.el);
  8.         icons.el.down('.'+icons.bwrapCls).remove();
  9.         // ICON HELL!!!
  10.         if (this.imagePath!="" && this.imagePath.charAt(this.imagePath.length-1)!="/")
  11.             this.imagePath+="/";
  12.         this.iconUp = this.imagePath + (this.iconUp || 'up2.gif');
  13.         this.iconDown = this.imagePath + (this.iconDown || 'down2.gif');
  14.         this.iconLeft = this.imagePath + (this.iconLeft || 'left2.gif');
  15.         this.iconRight = this.imagePath + (this.iconRight || 'right2.gif');
  16.         this.iconTop = this.imagePath + (this.iconTop || 'top2.gif');
  17.         this.iconBottom = this.imagePath + (this.iconBottom || 'bottom2.gif');
  18.         var el=icons.getEl();
  19.         this.toTopIcon = el.createChild({tag:'img', src:this.iconTop, style:{cursor:'pointer', margin:'2px'}});
  20.         el.createChild({tag: 'br'});
  21.         this.upIcon = el.createChild({tag:'img', src:this.iconUp, style:{cursor:'pointer', margin:'2px'}});
  22.         el.createChild({tag: 'br'});
  23.         this.addIcon = el.createChild({tag:'img', src:this.iconRight, style:{cursor:'pointer', margin:'2px'}});
  24.         el.createChild({tag: 'br'});
  25.         this.removeIcon = el.createChild({tag:'img', src:this.iconLeft, style:{cursor:'pointer', margin:'2px'}});
  26.         el.createChild({tag: 'br'});
  27.         this.downIcon = el.createChild({tag:'img', src:this.iconDown, style:{cursor:'pointer', margin:'2px'}});
  28.         el.createChild({tag: 'br'});
  29.         this.toBottomIcon = el.createChild({tag:'img', src:this.iconBottom, style:{cursor:'pointer', margin:'2px'}});
  30.         this.toTopIcon.on('click', this.toTop, this);
  31.         this.upIcon.on('click', this.up, this);
  32.         this.downIcon.on('click', this.down, this);
  33.         this.toBottomIcon.on('click', this.toBottom, this);
  34.         this.addIcon.on('click', this.fromTo, this);
  35.         this.removeIcon.on('click', this.toFrom, this);
  36.         if (!this.drawUpIcon || this.hideNavIcons) { this.upIcon.dom.style.display='none'; }
  37.         if (!this.drawDownIcon || this.hideNavIcons) { this.downIcon.dom.style.display='none'; }
  38.         if (!this.drawLeftIcon || this.hideNavIcons) { this.addIcon.dom.style.display='none'; }
  39.         if (!this.drawRightIcon || this.hideNavIcons) { this.removeIcon.dom.style.display='none'; }
  40.         if (!this.drawTopIcon || this.hideNavIcons) { this.toTopIcon.dom.style.display='none'; }
  41.         if (!this.drawBotIcon || this.hideNavIcons) { this.toBottomIcon.dom.style.display='none'; }
  42.         var tb = p.body.first();
  43.         this.el.setWidth(p.body.first().getWidth());
  44.         p.body.removeClass();
  45.         this.hiddenName = this.name;
  46.         var hiddenTag = {tag: "input", type: "hidden", value: "", name: this.name};
  47.         this.hiddenField = this.el.createChild(hiddenTag);
  48.     },
  49.     
  50.     doLayout: function(){
  51.         if(this.rendered){
  52.             this.fromMultiselect.fs.doLayout();
  53.             this.toMultiselect.fs.doLayout();
  54.         }
  55.     },
  56.     afterRender: function(){
  57.         Ext.ux.form.ItemSelector.superclass.afterRender.call(this);
  58.         this.toStore = this.toMultiselect.store;
  59.         this.toStore.on('add', this.valueChanged, this);
  60.         this.toStore.on('remove', this.valueChanged, this);
  61.         this.toStore.on('load', this.valueChanged, this);
  62.         this.valueChanged(this.toStore);
  63.     },
  64.     toTop : function() {
  65.         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  66.         var records = [];
  67.         if (selectionsArray.length > 0) {
  68.             selectionsArray.sort();
  69.             for (var i=0; i<selectionsArray.length; i++) {
  70.                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  71.                 records.push(record);
  72.             }
  73.             selectionsArray = [];
  74.             for (var i=records.length-1; i>-1; i--) {
  75.                 record = records[i];
  76.                 this.toMultiselect.view.store.remove(record);
  77.                 this.toMultiselect.view.store.insert(0, record);
  78.                 selectionsArray.push(((records.length - 1) - i));
  79.             }
  80.         }
  81.         this.toMultiselect.view.refresh();
  82.         this.toMultiselect.view.select(selectionsArray);
  83.     },
  84.     toBottom : function() {
  85.         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  86.         var records = [];
  87.         if (selectionsArray.length > 0) {
  88.             selectionsArray.sort();
  89.             for (var i=0; i<selectionsArray.length; i++) {
  90.                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  91.                 records.push(record);
  92.             }
  93.             selectionsArray = [];
  94.             for (var i=0; i<records.length; i++) {
  95.                 record = records[i];
  96.                 this.toMultiselect.view.store.remove(record);
  97.                 this.toMultiselect.view.store.add(record);
  98.                 selectionsArray.push((this.toMultiselect.view.store.getCount()) - (records.length - i));
  99.             }
  100.         }
  101.         this.toMultiselect.view.refresh();
  102.         this.toMultiselect.view.select(selectionsArray);
  103.     },
  104.     up : function() {
  105.         var record = null;
  106.         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  107.         selectionsArray.sort();
  108.         var newSelectionsArray = [];
  109.         if (selectionsArray.length > 0) {
  110.             for (var i=0; i<selectionsArray.length; i++) {
  111.                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  112.                 if ((selectionsArray[i] - 1) >= 0) {
  113.                     this.toMultiselect.view.store.remove(record);
  114.                     this.toMultiselect.view.store.insert(selectionsArray[i] - 1, record);
  115.                     newSelectionsArray.push(selectionsArray[i] - 1);
  116.                 }
  117.             }
  118.             this.toMultiselect.view.refresh();
  119.             this.toMultiselect.view.select(newSelectionsArray);
  120.         }
  121.     },
  122.     down : function() {
  123.         var record = null;
  124.         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  125.         selectionsArray.sort();
  126.         selectionsArray.reverse();
  127.         var newSelectionsArray = [];
  128.         if (selectionsArray.length > 0) {
  129.             for (var i=0; i<selectionsArray.length; i++) {
  130.                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  131.                 if ((selectionsArray[i] + 1) < this.toMultiselect.view.store.getCount()) {
  132.                     this.toMultiselect.view.store.remove(record);
  133.                     this.toMultiselect.view.store.insert(selectionsArray[i] + 1, record);
  134.                     newSelectionsArray.push(selectionsArray[i] + 1);
  135.                 }
  136.             }
  137.             this.toMultiselect.view.refresh();
  138.             this.toMultiselect.view.select(newSelectionsArray);
  139.         }
  140.     },
  141.     fromTo : function() {
  142.         var selectionsArray = this.fromMultiselect.view.getSelectedIndexes();
  143.         var records = [];
  144.         if (selectionsArray.length > 0) {
  145.             for (var i=0; i<selectionsArray.length; i++) {
  146.                 record = this.fromMultiselect.view.store.getAt(selectionsArray[i]);
  147.                 records.push(record);
  148.             }
  149.             if(!this.allowDup)selectionsArray = [];
  150.             for (var i=0; i<records.length; i++) {
  151.                 record = records[i];
  152.                 if(this.allowDup){
  153.                     var x=new Ext.data.Record();
  154.                     record.id=x.id;
  155.                     delete x;
  156.                     this.toMultiselect.view.store.add(record);
  157.                 }else{
  158.                     this.fromMultiselect.view.store.remove(record);
  159.                     this.toMultiselect.view.store.add(record);
  160.                     selectionsArray.push((this.toMultiselect.view.store.getCount() - 1));
  161.                 }
  162.             }
  163.         }
  164.         this.toMultiselect.view.refresh();
  165.         this.fromMultiselect.view.refresh();
  166.         var si = this.toMultiselect.store.sortInfo;
  167.         if(si){
  168.             this.toMultiselect.store.sort(si.field, si.direction);
  169.         }
  170.         this.toMultiselect.view.select(selectionsArray);
  171.     },
  172.     toFrom : function() {
  173.         var selectionsArray = this.toMultiselect.view.getSelectedIndexes();
  174.         var records = [];
  175.         if (selectionsArray.length > 0) {
  176.             for (var i=0; i<selectionsArray.length; i++) {
  177.                 record = this.toMultiselect.view.store.getAt(selectionsArray[i]);
  178.                 records.push(record);
  179.             }
  180.             selectionsArray = [];
  181.             for (var i=0; i<records.length; i++) {
  182.                 record = records[i];
  183.                 this.toMultiselect.view.store.remove(record);
  184.                 if(!this.allowDup){
  185.                     this.fromMultiselect.view.store.add(record);
  186.                     selectionsArray.push((this.fromMultiselect.view.store.getCount() - 1));
  187.                 }
  188.             }
  189.         }
  190.         this.fromMultiselect.view.refresh();
  191.         this.toMultiselect.view.refresh();
  192.         var si = this.fromMultiselect.store.sortInfo;
  193.         if (si){
  194.             this.fromMultiselect.store.sort(si.field, si.direction);
  195.         }
  196.         this.fromMultiselect.view.select(selectionsArray);
  197.     },
  198.     valueChanged: function(store) {
  199.         var record = null;
  200.         var values = [];
  201.         for (var i=0; i<store.getCount(); i++) {
  202.             record = store.getAt(i);
  203.             values.push(record.get(this.toMultiselect.valueField));
  204.         }
  205.         this.hiddenField.dom.value = values.join(this.delimiter);
  206.         this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
  207.     },
  208.     getValue : function() {
  209.         return this.hiddenField.dom.value;
  210.     },
  211.     onRowDblClick : function(vw, index, node, e) {
  212.         if (vw == this.toMultiselect.view){
  213.             this.toFrom();
  214.         } else if (vw == this.fromMultiselect.view) {
  215.             this.fromTo();
  216.         }
  217.         return this.fireEvent('rowdblclick', vw, index, node, e);
  218.     },
  219.     reset: function(){
  220.         range = this.toMultiselect.store.getRange();
  221.         this.toMultiselect.store.removeAll();
  222.         this.fromMultiselect.store.add(range);
  223.         var si = this.fromMultiselect.store.sortInfo;
  224.         if (si){
  225.             this.fromMultiselect.store.sort(si.field, si.direction);
  226.         }
  227.         this.valueChanged(this.toMultiselect.store);
  228.     }
  229. });
  230. Ext.reg('itemselector', Ext.ux.form.ItemSelector);
  231. //backwards compat
  232. Ext.ux.ItemSelector = Ext.ux.form.ItemSelector;
  233. Ext.ns('Ext.ux.form');
  234. /**
  235.  * @class Ext.ux.form.MultiSelect
  236.  * @extends Ext.form.Field
  237.  * A control that allows selection and form submission of multiple list items.
  238.  *
  239.  *  @history
  240.  *    2008-06-19 bpm Original code contributed by Toby Stuart (with contributions from Robert Williams)
  241.  *    2008-06-19 bpm Docs and demo code clean up
  242.  *
  243.  * @constructor
  244.  * Create a new MultiSelect
  245.  * @param {Object} config Configuration options
  246.  * @xtype multiselect 
  247.  */
  248. Ext.ux.form.MultiSelect = Ext.extend(Ext.form.Field,  {
  249.     /**
  250.      * @cfg {String} legend Wraps the object with a fieldset and specified legend.
  251.      */
  252.     /**
  253.      * @cfg {Ext.ListView} view The {@link Ext.ListView} used to render the multiselect list.
  254.      */
  255.     /**
  256.      * @cfg {String/Array} dragGroup The ddgroup name(s) for the MultiSelect DragZone (defaults to undefined).
  257.      */
  258.     /**
  259.      * @cfg {String/Array} dropGroup The ddgroup name(s) for the MultiSelect DropZone (defaults to undefined).
  260.      */
  261.     /**
  262.      * @cfg {Boolean} ddReorder Whether the items in the MultiSelect list are drag/drop reorderable (defaults to false).
  263.      */
  264.     ddReorder:false,
  265.     /**
  266.      * @cfg {Object/Array} tbar The top toolbar of the control. This can be a {@link Ext.Toolbar} object, a
  267.      * toolbar config, or an array of buttons/button configs to be added to the toolbar.
  268.      */
  269.     /**
  270.      * @cfg {String} appendOnly True if the list should only allow append drops when drag/drop is enabled
  271.      * (use for lists which are sorted, defaults to false).
  272.      */
  273.     appendOnly:false,
  274.     /**
  275.      * @cfg {Number} width Width in pixels of the control (defaults to 100).
  276.      */
  277.     width:100,
  278.     /**
  279.      * @cfg {Number} height Height in pixels of the control (defaults to 100).
  280.      */
  281.     height:100,
  282.     /**
  283.      * @cfg {String/Number} displayField Name/Index of the desired display field in the dataset (defaults to 0).
  284.      */
  285.     displayField:0,
  286.     /**
  287.      * @cfg {String/Number} valueField Name/Index of the desired value field in the dataset (defaults to 1).
  288.      */
  289.     valueField:1,
  290.     /**
  291.      * @cfg {Boolean} allowBlank False to require at least one item in the list to be selected, true to allow no
  292.      * selection (defaults to true).
  293.      */
  294.     allowBlank:true,
  295.     /**
  296.      * @cfg {Number} minSelections Minimum number of selections allowed (defaults to 0).
  297.      */
  298.     minSelections:0,
  299.     /**
  300.      * @cfg {Number} maxSelections Maximum number of selections allowed (defaults to Number.MAX_VALUE).
  301.      */
  302.     maxSelections:Number.MAX_VALUE,
  303.     /**
  304.      * @cfg {String} blankText Default text displayed when the control contains no items (defaults to the same value as
  305.      * {@link Ext.form.TextField#blankText}.
  306.      */
  307.     blankText:Ext.form.TextField.prototype.blankText,
  308.     /**
  309.      * @cfg {String} minSelectionsText Validation message displayed when {@link #minSelections} is not met (defaults to 'Minimum {0}
  310.      * item(s) required').  The {0} token will be replaced by the value of {@link #minSelections}.
  311.      */
  312.     minSelectionsText:'Minimum {0} item(s) required',
  313.     /**
  314.      * @cfg {String} maxSelectionsText Validation message displayed when {@link #maxSelections} is not met (defaults to 'Maximum {0}
  315.      * item(s) allowed').  The {0} token will be replaced by the value of {@link #maxSelections}.
  316.      */
  317.     maxSelectionsText:'Maximum {0} item(s) allowed',
  318.     /**
  319.      * @cfg {String} delimiter The string used to delimit between items when set or returned as a string of values
  320.      * (defaults to ',').
  321.      */
  322.     delimiter:',',
  323.     /**
  324.      * @cfg {Ext.data.Store/Array} store The data source to which this MultiSelect is bound (defaults to <tt>undefined</tt>).
  325.      * Acceptable values for this property are:
  326.      * <div class="mdetail-params"><ul>
  327.      * <li><b>any {@link Ext.data.Store Store} subclass</b></li>
  328.      * <li><b>an Array</b> : Arrays will be converted to a {@link Ext.data.ArrayStore} internally.
  329.      * <div class="mdetail-params"><ul>
  330.      * <li><b>1-dimensional array</b> : (e.g., <tt>['Foo','Bar']</tt>)<div class="sub-desc">
  331.      * A 1-dimensional array will automatically be expanded (each array item will be the combo
  332.      * {@link #valueField value} and {@link #displayField text})</div></li>
  333.      * <li><b>2-dimensional array</b> : (e.g., <tt>[['f','Foo'],['b','Bar']]</tt>)<div class="sub-desc">
  334.      * For a multi-dimensional array, the value in index 0 of each item will be assumed to be the combo
  335.      * {@link #valueField value}, while the value at index 1 is assumed to be the combo {@link #displayField text}.
  336.      * </div></li></ul></div></li></ul></div>
  337.      */
  338.     // private
  339.     defaultAutoCreate : {tag: "div"},
  340.     // private
  341.     initComponent: function(){
  342.         Ext.ux.form.MultiSelect.superclass.initComponent.call(this);
  343.         if(Ext.isArray(this.store)){
  344.             if (Ext.isArray(this.store[0])){
  345.                 this.store = new Ext.data.ArrayStore({
  346.                     fields: ['value','text'],
  347.                     data: this.store
  348.                 });
  349.                 this.valueField = 'value';
  350.             }else{
  351.                 this.store = new Ext.data.ArrayStore({
  352.                     fields: ['text'],
  353.                     data: this.store,
  354.                     expandData: true
  355.                 });
  356.                 this.valueField = 'text';
  357.             }
  358.             this.displayField = 'text';
  359.         } else {
  360.             this.store = Ext.StoreMgr.lookup(this.store);
  361.         }
  362.         this.addEvents({
  363.             'dblclick' : true,
  364.             'click' : true,
  365.             'change' : true,
  366.             'drop' : true
  367.         });
  368.     },
  369.     // private
  370.     onRender: function(ct, position){
  371.         Ext.ux.form.MultiSelect.superclass.onRender.call(this, ct, position);
  372.         var fs = this.fs = new Ext.form.FieldSet({
  373.             renderTo: this.el,
  374.             title: this.legend,
  375.             height: this.height,
  376.             width: this.width,
  377.             style: "padding:0;",
  378.             tbar: this.tbar,
  379.             bodyStyle: 'overflow: auto;'
  380.         });
  381.         this.view = new Ext.ListView({
  382.             multiSelect: true,
  383.             store: this.store,
  384.             columns: [{ header: 'Value', width: 1, dataIndex: this.displayField }],
  385.             hideHeaders: true
  386.         });
  387.         fs.add(this.view);
  388.         this.view.on('click', this.onViewClick, this);
  389.         this.view.on('beforeclick', this.onViewBeforeClick, this);
  390.         this.view.on('dblclick', this.onViewDblClick, this);
  391.         this.hiddenName = this.name || Ext.id();
  392.         var hiddenTag = { tag: "input", type: "hidden", value: "", name: this.hiddenName };
  393.         this.hiddenField = this.el.createChild(hiddenTag);
  394.         this.hiddenField.dom.disabled = this.hiddenName != this.name;
  395.         fs.doLayout();
  396.     },
  397.     // private
  398.     afterRender: function(){
  399.         Ext.ux.form.MultiSelect.superclass.afterRender.call(this);
  400.         if (this.ddReorder && !this.dragGroup && !this.dropGroup){
  401.             this.dragGroup = this.dropGroup = 'MultiselectDD-' + Ext.id();
  402.         }
  403.         if (this.draggable || this.dragGroup){
  404.             this.dragZone = new Ext.ux.form.MultiSelect.DragZone(this, {
  405.                 ddGroup: this.dragGroup
  406.             });
  407.         }
  408.         if (this.droppable || this.dropGroup){
  409.             this.dropZone = new Ext.ux.form.MultiSelect.DropZone(this, {
  410.                 ddGroup: this.dropGroup
  411.             });
  412.         }
  413.     },
  414.     // private
  415.     onViewClick: function(vw, index, node, e) {
  416.         this.fireEvent('change', this, this.getValue(), this.hiddenField.dom.value);
  417.         this.hiddenField.dom.value = this.getValue();
  418.         this.fireEvent('click', this, e);
  419.         this.validate();
  420.     },
  421.     // private
  422.     onViewBeforeClick: function(vw, index, node, e) {
  423.         if (this.disabled) {return false;}
  424.     },
  425.     // private
  426.     onViewDblClick : function(vw, index, node, e) {
  427.         return this.fireEvent('dblclick', vw, index, node, e);
  428.     },
  429.     /**
  430.      * Returns an array of data values for the selected items in the list. The values will be separated
  431.      * by {@link #delimiter}.
  432.      * @return {Array} value An array of string data values
  433.      */
  434.     getValue: function(valueField){
  435.         var returnArray = [];
  436.         var selectionsArray = this.view.getSelectedIndexes();
  437.         if (selectionsArray.length == 0) {return '';}
  438.         for (var i=0; i<selectionsArray.length; i++) {
  439.             returnArray.push(this.store.getAt(selectionsArray[i]).get((valueField != null) ? valueField : this.valueField));
  440.         }
  441.         return returnArray.join(this.delimiter);
  442.     },
  443.     /**
  444.      * Sets a delimited string (using {@link #delimiter}) or array of data values into the list.
  445.      * @param {String/Array} values The values to set
  446.      */
  447.     setValue: function(values) {
  448.         var index;
  449.         var selections = [];
  450.         this.view.clearSelections();
  451.         this.hiddenField.dom.value = '';
  452.         if (!values || (values == '')) { return; }
  453.         if (!Ext.isArray(values)) { values = values.split(this.delimiter); }
  454.         for (var i=0; i<values.length; i++) {
  455.             index = this.view.store.indexOf(this.view.store.query(this.valueField,
  456.                 new RegExp('^' + values[i] + '$', "i")).itemAt(0));
  457.             selections.push(index);
  458.         }
  459.         this.view.select(selections);
  460.         this.hiddenField.dom.value = this.getValue();
  461.         this.validate();
  462.     },
  463.     // inherit docs
  464.     reset : function() {
  465.         this.setValue('');
  466.     },
  467.     // inherit docs
  468.     getRawValue: function(valueField) {
  469.         var tmp = this.getValue(valueField);
  470.         if (tmp.length) {
  471.             tmp = tmp.split(this.delimiter);
  472.         }
  473.         else {
  474.             tmp = [];
  475.         }
  476.         return tmp;
  477.     },
  478.     // inherit docs
  479.     setRawValue: function(values){
  480.         setValue(values);
  481.     },
  482.     // inherit docs
  483.     validateValue : function(value){
  484.         if (value.length < 1) { // if it has no value
  485.              if (this.allowBlank) {
  486.                  this.clearInvalid();
  487.                  return true;
  488.              } else {
  489.                  this.markInvalid(this.blankText);
  490.                  return false;
  491.              }
  492.         }
  493.         if (value.length < this.minSelections) {
  494.             this.markInvalid(String.format(this.minSelectionsText, this.minSelections));
  495.             return false;
  496.         }
  497.         if (value.length > this.maxSelections) {
  498.             this.markInvalid(String.format(this.maxSelectionsText, this.maxSelections));
  499.             return false;
  500.         }
  501.         return true;
  502.     },
  503.     // inherit docs
  504.     disable: function(){
  505.         this.disabled = true;
  506.         this.hiddenField.dom.disabled = true;
  507.         this.fs.disable();
  508.     },
  509.     // inherit docs
  510.     enable: function(){
  511.         this.disabled = false;
  512.         this.hiddenField.dom.disabled = false;
  513.         this.fs.enable();
  514.     },
  515.     // inherit docs
  516.     destroy: function(){
  517.         Ext.destroy(this.fs, this.dragZone, this.dropZone);
  518.         Ext.ux.form.MultiSelect.superclass.destroy.call(this);
  519.     }
  520. });
  521. Ext.reg('multiselect', Ext.ux.form.MultiSelect);
  522. //backwards compat
  523. Ext.ux.Multiselect = Ext.ux.form.MultiSelect;
  524. Ext.ux.form.MultiSelect.DragZone = function(ms, config){
  525.     this.ms = ms;
  526.     this.view = ms.view;
  527.     var ddGroup = config.ddGroup || 'MultiselectDD';
  528.     var dd;
  529.     if (Ext.isArray(ddGroup)){
  530.         dd = ddGroup.shift();
  531.     } else {
  532.         dd = ddGroup;
  533.         ddGroup = null;
  534.     }
  535.     Ext.ux.form.MultiSelect.DragZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
  536.     this.setDraggable(ddGroup);
  537. };
  538. Ext.extend(Ext.ux.form.MultiSelect.DragZone, Ext.dd.DragZone, {
  539.     onInitDrag : function(x, y){
  540.         var el = Ext.get(this.dragData.ddel.cloneNode(true));
  541.         this.proxy.update(el.dom);
  542.         el.setWidth(el.child('em').getWidth());
  543.         this.onStartDrag(x, y);
  544.         return true;
  545.     },
  546.     
  547.     // private
  548.     collectSelection: function(data) {
  549.         data.repairXY = Ext.fly(this.view.getSelectedNodes()[0]).getXY();
  550.         var i = 0;
  551.         this.view.store.each(function(rec){
  552.             if (this.view.isSelected(i)) {
  553.                 var n = this.view.getNode(i);
  554.                 var dragNode = n.cloneNode(true);
  555.                 dragNode.id = Ext.id();
  556.                 data.ddel.appendChild(dragNode);
  557.                 data.records.push(this.view.store.getAt(i));
  558.                 data.viewNodes.push(n);
  559.             }
  560.             i++;
  561.         }, this);
  562.     },
  563.     // override
  564.     onEndDrag: function(data, e) {
  565.         var d = Ext.get(this.dragData.ddel);
  566.         if (d && d.hasClass("multi-proxy")) {
  567.             d.remove();
  568.         }
  569.     },
  570.     // override
  571.     getDragData: function(e){
  572.         var target = this.view.findItemFromChild(e.getTarget());
  573.         if(target) {
  574.             if (!this.view.isSelected(target) && !e.ctrlKey && !e.shiftKey) {
  575.                 this.view.select(target);
  576.                 this.ms.setValue(this.ms.getValue());
  577.             }
  578.             if (this.view.getSelectionCount() == 0 || e.ctrlKey || e.shiftKey) return false;
  579.             var dragData = {
  580.                 sourceView: this.view,
  581.                 viewNodes: [],
  582.                 records: []
  583.             };
  584.             if (this.view.getSelectionCount() == 1) {
  585.                 var i = this.view.getSelectedIndexes()[0];
  586.                 var n = this.view.getNode(i);
  587.                 dragData.viewNodes.push(dragData.ddel = n);
  588.                 dragData.records.push(this.view.store.getAt(i));
  589.                 dragData.repairXY = Ext.fly(n).getXY();
  590.             } else {
  591.                 dragData.ddel = document.createElement('div');
  592.                 dragData.ddel.className = 'multi-proxy';
  593.                 this.collectSelection(dragData);
  594.             }
  595.             return dragData;
  596.         }
  597.         return false;
  598.     },
  599.     // override the default repairXY.
  600.     getRepairXY : function(e){
  601.         return this.dragData.repairXY;
  602.     },
  603.     // private
  604.     setDraggable: function(ddGroup){
  605.         if (!ddGroup) return;
  606.         if (Ext.isArray(ddGroup)) {
  607.             Ext.each(ddGroup, this.setDraggable, this);
  608.             return;
  609.         }
  610.         this.addToGroup(ddGroup);
  611.     }
  612. });
  613. Ext.ux.form.MultiSelect.DropZone = function(ms, config){
  614.     this.ms = ms;
  615.     this.view = ms.view;
  616.     var ddGroup = config.ddGroup || 'MultiselectDD';
  617.     var dd;
  618.     if (Ext.isArray(ddGroup)){
  619.         dd = ddGroup.shift();
  620.     } else {
  621.         dd = ddGroup;
  622.         ddGroup = null;
  623.     }
  624.     Ext.ux.form.MultiSelect.DropZone.superclass.constructor.call(this, this.ms.fs.body, { containerScroll: true, ddGroup: dd });
  625.     this.setDroppable(ddGroup);
  626. };
  627. Ext.extend(Ext.ux.form.MultiSelect.DropZone, Ext.dd.DropZone, {
  628.     /**
  629.  * Part of the Ext.dd.DropZone interface. If no target node is found, the
  630.  * whole Element becomes the target, and this causes the drop gesture to append.
  631.  */
  632.     getTargetFromEvent : function(e) {
  633.         var target = e.getTarget();
  634.         return target;
  635.     },
  636.     // private
  637.     getDropPoint : function(e, n, dd){
  638.         if (n == this.ms.fs.body.dom) { return "below"; }
  639.         var t = Ext.lib.Dom.getY(n), b = t + n.offsetHeight;
  640.         var c = t + (b - t) / 2;
  641.         var y = Ext.lib.Event.getPageY(e);
  642.         if(y <= c) {
  643.             return "above";
  644.         }else{
  645.             return "below";
  646.         }
  647.     },
  648.     // private
  649.     isValidDropPoint: function(pt, n, data) {
  650.         if (!data.viewNodes || (data.viewNodes.length != 1)) {
  651.             return true;
  652.         }
  653.         var d = data.viewNodes[0];
  654.         if (d == n) {
  655.             return false;
  656.         }
  657.         if ((pt == "below") && (n.nextSibling == d)) {
  658.             return false;
  659.         }
  660.         if ((pt == "above") && (n.previousSibling == d)) {
  661.             return false;
  662.         }
  663.         return true;
  664.     },
  665.     // override
  666.     onNodeEnter : function(n, dd, e, data){
  667.         return false;
  668.     },
  669.     // override
  670.     onNodeOver : function(n, dd, e, data){
  671.         var dragElClass = this.dropNotAllowed;
  672.         var pt = this.getDropPoint(e, n, dd);
  673.         if (this.isValidDropPoint(pt, n, data)) {
  674.             if (this.ms.appendOnly) {
  675.                 return "x-tree-drop-ok-below";
  676.             }
  677.             // set the insert point style on the target node
  678.             if (pt) {
  679.                 var targetElClass;
  680.                 if (pt == "above"){
  681.                     dragElClass = n.previousSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-above";
  682.                     targetElClass = "x-view-drag-insert-above";
  683.                 } else {
  684.                     dragElClass = n.nextSibling ? "x-tree-drop-ok-between" : "x-tree-drop-ok-below";
  685.                     targetElClass = "x-view-drag-insert-below";
  686.                 }
  687.                 if (this.lastInsertClass != targetElClass){
  688.                     Ext.fly(n).replaceClass(this.lastInsertClass, targetElClass);
  689.                     this.lastInsertClass = targetElClass;
  690.                 }
  691.             }
  692.         }
  693.         return dragElClass;
  694.     },
  695.     // private
  696.     onNodeOut : function(n, dd, e, data){
  697.         this.removeDropIndicators(n);
  698.     },
  699.     // private
  700.     onNodeDrop : function(n, dd, e, data){
  701.         if (this.ms.fireEvent("drop", this, n, dd, e, data) === false) {
  702.             return false;
  703.         }
  704.         var pt = this.getDropPoint(e, n, dd);
  705.         if (n != this.ms.fs.body.dom)
  706.             n = this.view.findItemFromChild(n);
  707.         var insertAt = (this.ms.appendOnly || (n == this.ms.fs.body.dom)) ? this.view.store.getCount() : this.view.indexOf(n);
  708.         if (pt == "below") {
  709.             insertAt++;
  710.         }
  711.         var dir = false;
  712.         // Validate if dragging within the same MultiSelect
  713.         if (data.sourceView == this.view) {
  714.             // If the first element to be inserted below is the target node, remove it
  715.             if (pt == "below") {
  716.                 if (data.viewNodes[0] == n) {
  717.                     data.viewNodes.shift();
  718.                 }
  719.             } else {  // If the last element to be inserted above is the target node, remove it
  720.                 if (data.viewNodes[data.viewNodes.length - 1] == n) {
  721.                     data.viewNodes.pop();
  722.                 }
  723.             }
  724.             // Nothing to drop...
  725.             if (!data.viewNodes.length) {
  726.                 return false;
  727.             }
  728.             // If we are moving DOWN, then because a store.remove() takes place first,
  729.             // the insertAt must be decremented.
  730.             if (insertAt > this.view.store.indexOf(data.records[0])) {
  731.                 dir = 'down';
  732.                 insertAt--;
  733.             }
  734.         }
  735.         for (var i = 0; i < data.records.length; i++) {
  736.             var r = data.records[i];
  737.             if (data.sourceView) {
  738.                 data.sourceView.store.remove(r);
  739.             }
  740.             this.view.store.insert(dir == 'down' ? insertAt : insertAt++, r);
  741.             var si = this.view.store.sortInfo;
  742.             if(si){
  743.                 this.view.store.sort(si.field, si.direction);
  744.             }
  745.         }
  746.         return true;
  747.     },
  748.     // private
  749.     removeDropIndicators : function(n){
  750.         if(n){
  751.             Ext.fly(n).removeClass([
  752.                 "x-view-drag-insert-above",
  753.                 "x-view-drag-insert-left",
  754.                 "x-view-drag-insert-right",
  755.                 "x-view-drag-insert-below"]);
  756.             this.lastInsertClass = "_noclass";
  757.         }
  758.     },
  759.     // private
  760.     setDroppable: function(ddGroup){
  761.         if (!ddGroup) return;
  762.         if (Ext.isArray(ddGroup)) {
  763.             Ext.each(ddGroup, this.setDroppable, this);
  764.             return;
  765.         }
  766.         this.addToGroup(ddGroup);
  767.     }
  768. });
  769. /* Fix for Opera, which does not seem to include the map function on Array's */ if (!Array.prototype.map) {     Array.prototype.map = function(fun){         var len = this.length;         if (typeof fun != 'function') {             throw new TypeError();         }         var res = new Array(len);         var thisp = arguments[1];         for (var i = 0; i < len; i++) {             if (i in this) {                 res[i] = fun.call(thisp, this[i], i, this);             }         }         return res;     }; } Ext.ns('Ext.ux.data'); /**  * @class Ext.ux.data.PagingMemoryProxy  * @extends Ext.data.MemoryProxy  * <p>Paging Memory Proxy, allows to use paging grid with in memory dataset</p>  */ Ext.ux.data.PagingMemoryProxy = Ext.extend(Ext.data.MemoryProxy, {     constructor : function(data){         Ext.ux.data.PagingMemoryProxy.superclass.constructor.call(this);         this.data = data;     },     doRequest : function(action, rs, params, reader, callback, scope, options){         params = params ||         {};         var result;         try {             result = reader.readRecords(this.data);         }          catch (e) {             this.fireEvent('loadexception', this, options, null, e);             callback.call(scope, null, options, false);             return;         }                  // filtering         if (params.filter !== undefined) {             result.records = result.records.filter(function(el){                 if (typeof(el) == 'object') {                     var att = params.filterCol || 0;                     return String(el.data[att]).match(params.filter) ? true : false;                 }                 else {                     return String(el).match(params.filter) ? true : false;                 }             });             result.totalRecords = result.records.length;         }                  // sorting         if (params.sort !== undefined) {             // use integer as params.sort to specify column, since arrays are not named             // params.sort=0; would also match a array without columns             var dir = String(params.dir).toUpperCase() == 'DESC' ? -1 : 1;             var fn = function(r1, r2){                 return r1 < r2;             };             result.records.sort(function(a, b){                 var v = 0;                 if (typeof(a) == 'object') {                     v = fn(a.data[params.sort], b.data[params.sort]) * dir;                 }                 else {                     v = fn(a, b) * dir;                 }                 if (v == 0) {                     v = (a.index < b.index ? -1 : 1);                 }                 return v;             });         }         // paging (use undefined cause start can also be 0 (thus false))         if (params.start !== undefined && params.limit !== undefined) {             result.records = result.records.slice(params.start, params.start + params.limit);         }         callback.call(scope, result, options, true);     } }); //backwards compat. Ext.data.PagingMemoryProxy = Ext.ux.data.PagingMemoryProxy; Ext.ux.PanelResizer = Ext.extend(Ext.util.Observable, {
  770.     minHeight: 0,
  771.     maxHeight:10000000,
  772.     constructor: function(config){
  773.         Ext.apply(this, config);
  774.         this.events = {};
  775.         Ext.ux.PanelResizer.superclass.constructor.call(this, config);
  776.     },
  777.     init : function(p){
  778.         this.panel = p;
  779.         if(this.panel.elements.indexOf('footer')==-1){
  780.             p.elements += ',footer';
  781.         }
  782.         p.on('render', this.onRender, this);
  783.     },
  784.     onRender : function(p){
  785.         this.handle = p.footer.createChild({cls:'x-panel-resize'});
  786.         this.tracker = new Ext.dd.DragTracker({
  787.             onStart: this.onDragStart.createDelegate(this),
  788.             onDrag: this.onDrag.createDelegate(this),
  789.             onEnd: this.onDragEnd.createDelegate(this),
  790.             tolerance: 3,
  791.             autoStart: 300
  792.         });
  793.         this.tracker.initEl(this.handle);
  794.         p.on('beforedestroy', this.tracker.destroy, this.tracker);
  795.     },
  796. // private
  797.     onDragStart: function(e){
  798.         this.dragging = true;
  799.         this.startHeight = this.panel.el.getHeight();
  800.         this.fireEvent('dragstart', this, e);
  801.     },
  802. // private
  803.     onDrag: function(e){
  804.         this.panel.setHeight((this.startHeight-this.tracker.getOffset()[1]).constrain(this.minHeight, this.maxHeight));
  805.         this.fireEvent('drag', this, e);
  806.     },
  807. // private
  808.     onDragEnd: function(e){
  809.         this.dragging = false;
  810.         this.fireEvent('dragend', this, e);
  811.     }
  812. });
  813. Ext.preg('panelresizer', Ext.ux.PanelResizer);Ext.ux.Portal = Ext.extend(Ext.Panel, {
  814.     layout : 'column',
  815.     autoScroll : true,
  816.     cls : 'x-portal',
  817.     defaultType : 'portalcolumn',
  818.     
  819.     initComponent : function(){
  820.         Ext.ux.Portal.superclass.initComponent.call(this);
  821.         this.addEvents({
  822.             validatedrop:true,
  823.             beforedragover:true,
  824.             dragover:true,
  825.             beforedrop:true,
  826.             drop:true
  827.         });
  828.     },
  829.     initEvents : function(){
  830.         Ext.ux.Portal.superclass.initEvents.call(this);
  831.         this.dd = new Ext.ux.Portal.DropZone(this, this.dropConfig);
  832.     },
  833.     
  834.     beforeDestroy : function() {
  835.         if(this.dd){
  836.             this.dd.unreg();
  837.         }
  838.         Ext.ux.Portal.superclass.beforeDestroy.call(this);
  839.     }
  840. });
  841. Ext.reg('portal', Ext.ux.Portal);
  842. Ext.ux.Portal.DropZone = function(portal, cfg){
  843.     this.portal = portal;
  844.     Ext.dd.ScrollManager.register(portal.body);
  845.     Ext.ux.Portal.DropZone.superclass.constructor.call(this, portal.bwrap.dom, cfg);
  846.     portal.body.ddScrollConfig = this.ddScrollConfig;
  847. };
  848. Ext.extend(Ext.ux.Portal.DropZone, Ext.dd.DropTarget, {
  849.     ddScrollConfig : {
  850.         vthresh: 50,
  851.         hthresh: -1,
  852.         animate: true,
  853.         increment: 200
  854.     },
  855.     createEvent : function(dd, e, data, col, c, pos){
  856.         return {
  857.             portal: this.portal,
  858.             panel: data.panel,
  859.             columnIndex: col,
  860.             column: c,
  861.             position: pos,
  862.             data: data,
  863.             source: dd,
  864.             rawEvent: e,
  865.             status: this.dropAllowed
  866.         };
  867.     },
  868.     notifyOver : function(dd, e, data){
  869.         var xy = e.getXY(), portal = this.portal, px = dd.proxy;
  870.         // case column widths
  871.         if(!this.grid){
  872.             this.grid = this.getGrid();
  873.         }
  874.         // handle case scroll where scrollbars appear during drag
  875.         var cw = portal.body.dom.clientWidth;
  876.         if(!this.lastCW){
  877.             this.lastCW = cw;
  878.         }else if(this.lastCW != cw){
  879.             this.lastCW = cw;
  880.             portal.doLayout();
  881.             this.grid = this.getGrid();
  882.         }
  883.         // determine column
  884.         var col = 0, xs = this.grid.columnX, cmatch = false;
  885.         for(var len = xs.length; col < len; col++){
  886.             if(xy[0] < (xs[col].x + xs[col].w)){
  887.                 cmatch = true;
  888.                 break;
  889.             }
  890.         }
  891.         // no match, fix last index
  892.         if(!cmatch){
  893.             col--;
  894.         }
  895.         // find insert position
  896.         var p, match = false, pos = 0,
  897.             c = portal.items.itemAt(col),
  898.             items = c.items.items, overSelf = false;
  899.         for(var len = items.length; pos < len; pos++){
  900.             p = items[pos];
  901.             var h = p.el.getHeight();
  902.             if(h === 0){
  903.                 overSelf = true;
  904.             }
  905.             else if((p.el.getY()+(h/2)) > xy[1]){
  906.                 match = true;
  907.                 break;
  908.             }
  909.         }
  910.         pos = (match && p ? pos : c.items.getCount()) + (overSelf ? -1 : 0);
  911.         var overEvent = this.createEvent(dd, e, data, col, c, pos);
  912.         if(portal.fireEvent('validatedrop', overEvent) !== false &&
  913.            portal.fireEvent('beforedragover', overEvent) !== false){
  914.             // make sure proxy width is fluid
  915.             px.getProxy().setWidth('auto');
  916.             if(p){
  917.                 px.moveProxy(p.el.dom.parentNode, match ? p.el.dom : null);
  918.             }else{
  919.                 px.moveProxy(c.el.dom, null);
  920.             }
  921.             this.lastPos = {c: c, col: col, p: overSelf || (match && p) ? pos : false};
  922.             this.scrollPos = portal.body.getScroll();
  923.             portal.fireEvent('dragover', overEvent);
  924.             return overEvent.status;
  925.         }else{
  926.             return overEvent.status;
  927.         }
  928.     },
  929.     notifyOut : function(){
  930.         delete this.grid;
  931.     },
  932.     notifyDrop : function(dd, e, data){
  933.         delete this.grid;
  934.         if(!this.lastPos){
  935.             return;
  936.         }
  937.         var c = this.lastPos.c, col = this.lastPos.col, pos = this.lastPos.p;
  938.         var dropEvent = this.createEvent(dd, e, data, col, c,
  939.             pos !== false ? pos : c.items.getCount());
  940.         if(this.portal.fireEvent('validatedrop', dropEvent) !== false &&
  941.            this.portal.fireEvent('beforedrop', dropEvent) !== false){
  942.             dd.proxy.getProxy().remove();
  943.             dd.panel.el.dom.parentNode.removeChild(dd.panel.el.dom);
  944.             
  945.             if(pos !== false){
  946.                 if(c == dd.panel.ownerCt && (c.items.items.indexOf(dd.panel) <= pos)){
  947.                     pos++;
  948.                 }
  949.                 c.insert(pos, dd.panel);
  950.             }else{
  951.                 c.add(dd.panel);
  952.             }
  953.             
  954.             c.doLayout();
  955.             this.portal.fireEvent('drop', dropEvent);
  956.             // scroll position is lost on drop, fix it
  957.             var st = this.scrollPos.top;
  958.             if(st){
  959.                 var d = this.portal.body.dom;
  960.                 setTimeout(function(){
  961.                     d.scrollTop = st;
  962.                 }, 10);
  963.             }
  964.         }
  965.         delete this.lastPos;
  966.     },
  967.     // internal cache of body and column coords
  968.     getGrid : function(){
  969.         var box = this.portal.bwrap.getBox();
  970.         box.columnX = [];
  971.         this.portal.items.each(function(c){
  972.              box.columnX.push({x: c.el.getX(), w: c.el.getWidth()});
  973.         });
  974.         return box;
  975.     },
  976.     // unregister the dropzone from ScrollManager
  977.     unreg: function() {
  978.         //Ext.dd.ScrollManager.unregister(this.portal.body);
  979.         Ext.ux.Portal.DropZone.superclass.unreg.call(this);
  980.     }
  981. });
  982. Ext.ux.PortalColumn = Ext.extend(Ext.Container, {
  983.     layout : 'anchor',
  984.     //autoEl : 'div',//already defined by Ext.Component
  985.     defaultType : 'portlet',
  986.     cls : 'x-portal-column'
  987. });
  988. Ext.reg('portalcolumn', Ext.ux.PortalColumn);
  989. Ext.ux.Portlet = Ext.extend(Ext.Panel, {
  990.     anchor : '100%',
  991.     frame : true,
  992.     collapsible : true,
  993.     draggable : true,
  994.     cls : 'x-portlet'
  995. });
  996. Ext.reg('portlet', Ext.ux.Portlet);
  997. /** * @class Ext.ux.ProgressBarPager * @extends Object  * Plugin (ptype = 'tabclosemenu') for displaying a progressbar inside of a paging toolbar instead of plain text *  * @ptype progressbarpager  * @constructor * Create a new ItemSelector * @param {Object} config Configuration options * @xtype itemselector  */ Ext.ux.ProgressBarPager  = Ext.extend(Object, { /**   * @cfg {Integer} progBarWidth   * <p>The default progress bar width.  Default is 225.</p> */ progBarWidth   : 225, /**   * @cfg {String} defaultText * <p>The text to display while the store is loading.  Default is 'Loading...'</p>   */ defaultText    : 'Loading...',      /**   * @cfg {Object} defaultAnimCfg    * <p>A {@link Ext.Fx Ext.Fx} configuration object.  Default is  { duration : 1, easing : 'bounceOut' }.</p>   */ defaultAnimCfg : { duration   : 1, easing     : 'bounceOut' },    constructor : function(config) { if (config) { Ext.apply(this, config); } }, //public init : function (parent) { if(parent.displayInfo){ this.parent = parent; var ind  = parent.items.indexOf(parent.displayItem); parent.remove(parent.displayItem, true); this.progressBar = new Ext.ProgressBar({ text    : this.defaultText, width   : this.progBarWidth, animate :  this.defaultAnimCfg });     parent.displayItem = this.progressBar; parent.add(parent.displayItem); parent.doLayout(); Ext.apply(parent, this.parentOverrides); this.progressBar.on('render', function(pb) { pb.el.applyStyles('cursor:pointer'); pb.el.on('click', this.handleProgressBarClick, this); }, this); // Remove the click handler from the  this.progressBar.on({ scope         : this, beforeDestroy : function() { this.progressBar.el.un('click', this.handleProgressBarClick, this); } }); }    }, // private // This method handles the click for the progress bar handleProgressBarClick : function(e){ var parent = this.parent; var displayItem = parent.displayItem; var box = this.progressBar.getBox(); var xy = e.getXY(); var position = xy[0]-box.x; var pages = Math.ceil(parent.store.getTotalCount()/parent.pageSize); var newpage = Math.ceil(position/(displayItem.width/pages)); parent.changePage(newpage); }, // private, overriddes parentOverrides  : { // private // This method updates the information via the progress bar. updateInfo : function(){ if(this.displayItem){ var count   = this.store.getCount(); var pgData  = this.getPageData(); var pageNum = this.readPage(pgData); var msg    = count == 0 ? this.emptyMsg : String.format( this.displayMsg, this.cursor+1, this.cursor+count, this.store.getTotalCount() ); pageNum = pgData.activePage; ; var pct = pageNum / pgData.pages; this.displayItem.updateProgress(pct, msg, this.animate || this.defaultAnimConfig); } } } }); Ext.preg('progressbarpager', Ext.ux.ProgressBarPager); Ext.ns('Ext.ux.grid'); /**  * @class Ext.ux.grid.RowEditor  * @extends Ext.Panel   * Plugin (ptype = 'roweditor') that adds the ability to rapidly edit full rows in a grid.  * A validation mode may be enabled which uses AnchorTips to notify the user of all  * validation errors at once.  *   * @ptype roweditor  */ Ext.ux.grid.RowEditor = Ext.extend(Ext.Panel, {     floating: true,     shadow: false,     layout: 'hbox',     cls: 'x-small-editor',     buttonAlign: 'center',     baseCls: 'x-row-editor',     elements: 'header,footer,body',     frameWidth: 5,     buttonPad: 3,     clicksToEdit: 'auto',     monitorValid: true,     focusDelay: 250,     errorSummary: true,     defaults: {         normalWidth: true     },     initComponent: function(){         Ext.ux.grid.RowEditor.superclass.initComponent.call(this);         this.addEvents(             /**              * @event beforeedit              * Fired before the row editor is activated.              * If the listener returns <tt>false</tt> the editor will not be activated.              * @param {Ext.ux.grid.RowEditor} roweditor This object              * @param {Number} rowIndex The rowIndex of the row just edited              */             'beforeedit',             /**              * @event validateedit              * Fired after a row is edited and passes validation.              * If the listener returns <tt>false</tt> changes to the record will not be set.              * @param {Ext.ux.grid.RowEditor} roweditor This object              * @param {Object} changes Object with changes made to the record.              * @param {Ext.data.Record} r The Record that was edited.              * @param {Number} rowIndex The rowIndex of the row just edited              */             'validateedit',             /**              * @event afteredit              * Fired after a row is edited and passes validation.  This event is fired              * after the store's update event is fired with this edit.              * @param {Ext.ux.grid.RowEditor} roweditor This object              * @param {Object} changes Object with changes made to the record.              * @param {Ext.data.Record} r The Record that was edited.              * @param {Number} rowIndex The rowIndex of the row just edited              */             'afteredit'         );     },     init: function(grid){         this.grid = grid;         this.ownerCt = grid;         if(this.clicksToEdit === 2){             grid.on('rowdblclick', this.onRowDblClick, this);         }else{             grid.on('rowclick', this.onRowClick, this);             if(Ext.isIE){                 grid.on('rowdblclick', this.onRowDblClick, this);             }         }         // stopEditing without saving when a record is removed from Store.         grid.getStore().on('remove', function() {             this.stopEditing(false);         },this);         grid.on({             scope: this,             keydown: this.onGridKey,             columnresize: this.verifyLayout,             columnmove: this.refreshFields,             reconfigure: this.refreshFields,     destroy : this.destroy,             bodyscroll: {                 buffer: 250,                 fn: this.positionButtons             }         });         grid.getColumnModel().on('hiddenchange', this.verifyLayout, this, {delay:1});         grid.getView().on('refresh', this.stopEditing.createDelegate(this, []));     },     refreshFields: function(){         this.initFields();         this.verifyLayout();     },     isDirty: function(){         var dirty;         this.items.each(function(f){             if(String(this.values[f.id]) !== String(f.getValue())){                 dirty = true;                 return false;             }         }, this);         return dirty;     },     startEditing: function(rowIndex, doFocus){         if(this.editing && this.isDirty()){             this.showTooltip('You need to commit or cancel your changes');             return;         }         this.editing = true;         if(typeof rowIndex == 'object'){             rowIndex = this.grid.getStore().indexOf(rowIndex);         }         if(this.fireEvent('beforeedit', this, rowIndex) !== false){             var g = this.grid, view = g.getView();             var row = view.getRow(rowIndex);             var record = g.store.getAt(rowIndex);             this.record = record;             this.rowIndex = rowIndex;             this.values = {};             if(!this.rendered){                 this.render(view.getEditorParent());             }             var w = Ext.fly(row).getWidth();             this.setSize(w);             if(!this.initialized){                 this.initFields();             }             var cm = g.getColumnModel(), fields = this.items.items, f, val;             for(var i = 0, len = cm.getColumnCount(); i < len; i++){                 val = this.preEditValue(record, cm.getDataIndex(i));                 f = fields[i];                 f.setValue(val);                 this.values[f.id] = val || '';             }             this.verifyLayout(true);             if(!this.isVisible()){                 this.setPagePosition(Ext.fly(row).getXY());             } else{                 this.el.setXY(Ext.fly(row).getXY(), {duration:0.15});             }             if(!this.isVisible()){                 this.show().doLayout();             }             if(doFocus !== false){                 this.doFocus.defer(this.focusDelay, this);             }         }     },     stopEditing : function(saveChanges){         this.editing = false;         if(!this.isVisible()){             return;         }         if(saveChanges === false || !this.isValid()){             this.hide();             return;         }         var changes = {}, r = this.record, hasChange = false;         var cm = this.grid.colModel, fields = this.items.items;         for(var i = 0, len = cm.getColumnCount(); i < len; i++){             if(!cm.isHidden(i)){                 var dindex = cm.getDataIndex(i);                 if(!Ext.isEmpty(dindex)){                     var oldValue = r.data[dindex];                     var value = this.postEditValue(fields[i].getValue(), oldValue, r, dindex);                     if(String(oldValue) !== String(value)){                         changes[dindex] = value;                         hasChange = true;                     }                 }             }         }         if(hasChange && this.fireEvent('validateedit', this, changes, r, this.rowIndex) !== false){             r.beginEdit();             for(var k in changes){                 if(changes.hasOwnProperty(k)){                     r.set(k, changes[k]);                 }             }             r.endEdit();             this.fireEvent('afteredit', this, changes, r, this.rowIndex);         }         this.hide();     },     verifyLayout: function(force){         if(this.el && (this.isVisible() || force === true)){             var row = this.grid.getView().getRow(this.rowIndex);             this.setSize(Ext.fly(row).getWidth(), Ext.isIE ? Ext.fly(row).getHeight() + (Ext.isBorderBox ? 9 : 0) : undefined);             var cm = this.grid.colModel, fields = this.items.items;             for(var i = 0, len = cm.getColumnCount(); i < len; i++){                 if(!cm.isHidden(i)){                     var adjust = 0;                     if(i === 0){                         adjust += 0; // outer padding                     }                     if(i === (len - 1)){                         adjust += 3; // outer padding                     } else{                         adjust += 1;                     }                     fields[i].show();                     fields[i].setWidth(cm.getColumnWidth(i) - adjust);                 } else{                     fields[i].hide();                 }             }             this.doLayout();             this.positionButtons();         }     },     slideHide : function(){         this.hide();     },     initFields: function(){         var cm = this.grid.getColumnModel(), pm = Ext.layout.ContainerLayout.prototype.parseMargins;         this.removeAll(false);         for(var i = 0, len = cm.getColumnCount(); i < len; i++){             var c = cm.getColumnAt(i);             var ed = c.getEditor();             if(!ed){                 ed = c.displayEditor || new Ext.form.DisplayField();             }             if(i == 0){                 ed.margins = pm('0 1 2 1');             } else if(i == len - 1){                 ed.margins = pm('0 0 2 1');             } else{                 ed.margins = pm('0 1 2');             }             ed.setWidth(cm.getColumnWidth(i));             ed.column = c;             if(ed.ownerCt !== this){                 ed.on('focus', this.ensureVisible, this);                 ed.on('specialkey', this.onKey, this);             }             this.insert(i, ed);         }         this.initialized = true;     },     onKey: function(f, e){         if(e.getKey() === e.ENTER){             this.stopEditing(true);             e.stopPropagation();         }     },     onGridKey: function(e){         if(e.getKey() === e.ENTER && !this.isVisible()){             var r = this.grid.getSelectionModel().getSelected();             if(r){                 var index = this.grid.store.indexOf(r);                 this.startEditing(index);                 e.stopPropagation();             }         }     },     ensureVisible: function(editor){         if(this.isVisible()){              this.grid.getView().ensureVisible(this.rowIndex, this.grid.colModel.getIndexById(editor.column.id), true);         }     },     onRowClick: function(g, rowIndex, e){         if(this.clicksToEdit == 'auto'){             var li = this.lastClickIndex;             this.lastClickIndex = rowIndex;             if(li != rowIndex && !this.isVisible()){                 return;             }         }         this.startEditing(rowIndex, false);         this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);     },     onRowDblClick: function(g, rowIndex, e){         this.startEditing(rowIndex, false);         this.doFocus.defer(this.focusDelay, this, [e.getPoint()]);     },     onRender: function(){         Ext.ux.grid.RowEditor.superclass.onRender.apply(this, arguments);         this.el.swallowEvent(['keydown', 'keyup', 'keypress']);         this.btns = new Ext.Panel({             baseCls: 'x-plain',             cls: 'x-btns',             elements:'body',             layout: 'table',             width: (this.minButtonWidth * 2) + (this.frameWidth * 2) + (this.buttonPad * 4), // width must be specified for IE             items: [{                 ref: 'saveBtn',                 itemId: 'saveBtn',                 xtype: 'button',                 text: this.saveText || 'Save',                 width: this.minButtonWidth,                 handler: this.stopEditing.createDelegate(this, [true])             }, {                 xtype: 'button',                 text: this.cancelText || 'Cancel',                 width: this.minButtonWidth,                 handler: this.stopEditing.createDelegate(this, [false])             }]         });         this.btns.render(this.bwrap);     },     afterRender: function(){         Ext.ux.grid.RowEditor.superclass.afterRender.apply(this, arguments);         this.positionButtons();         if(this.monitorValid){             this.startMonitoring();         }     },     onShow: function(){         if(this.monitorValid){             this.startMonitoring();         }         Ext.ux.grid.RowEditor.superclass.onShow.apply(this, arguments);     },     onHide: function(){         Ext.ux.grid.RowEditor.superclass.onHide.apply(this, arguments);         this.stopMonitoring();         this.grid.getView().focusRow(this.rowIndex);     },     positionButtons: function(){         if(this.btns){             var h = this.el.dom.clientHeight;             var view = this.grid.getView();             var scroll = view.scroller.dom.scrollLeft;             var width =  view.mainBody.getWidth();             var bw = this.btns.getWidth();             this.btns.el.shift({left: (width/2)-(bw/2)+scroll, top: h - 2, stopFx: true, duration:0.2});         }     },     // private     preEditValue : function(r, field){         var value = r.data[field];         return this.autoEncode && typeof value === 'string' ? Ext.util.Format.htmlDecode(value) : value;     },     // private     postEditValue : function(value, originalValue, r, field){         return this.autoEncode && typeof value == 'string' ? Ext.util.Format.htmlEncode(value) : value;     },     doFocus: function(pt){         if(this.isVisible()){             var index = 0;             if(pt){                 index = this.getTargetColumnIndex(pt);             }             var cm = this.grid.getColumnModel();             for(var i = index||0, len = cm.getColumnCount(); i < len; i++){                 var c = cm.getColumnAt(i);                 if(!c.hidden && c.getEditor()){                     c.getEditor().focus();                     break;                 }             }         }     },     getTargetColumnIndex: function(pt){         var grid = this.grid, v = grid.view;         var x = pt.left;         var cms = grid.colModel.config;         var i = 0, match = false;         for(var len = cms.length, c; c = cms[i]; i++){             if(!c.hidden){                 if(Ext.fly(v.getHeaderCell(i)).getRegion().right >= x){                     match = i;                     break;                 }             }         }         return match;     },     startMonitoring : function(){         if(!this.bound && this.monitorValid){             this.bound = true;             Ext.TaskMgr.start({                 run : this.bindHandler,                 interval : this.monitorPoll || 200,                 scope: this             });         }     },     stopMonitoring : function(){         this.bound = false;         if(this.tooltip){             this.tooltip.hide();         }     },     isValid: function(){         var valid = true;         this.items.each(function(f){             if(!f.isValid(true)){                 valid = false;                 return false;             }         });         return valid;     },     // private     bindHandler : function(){         if(!this.bound){             return false; // stops binding         }         var valid = this.isValid();         if(!valid && this.errorSummary){             this.showTooltip(this.getErrorText().join(''));         }         this.btns.saveBtn.setDisabled(!valid);         this.fireEvent('validation', this, valid);     },     showTooltip: function(msg){         var t = this.tooltip;         if(!t){             t = this.tooltip = new Ext.ToolTip({                 maxWidth: 600,                 cls: 'errorTip',                 width: 300,                 title: 'Errors',                 autoHide: false,                 anchor: 'left',                 anchorToTarget: true,                 mouseOffset: [40,0]             });         }         t.initTarget(this.items.last().getEl());         if(!t.rendered){             t.show();             t.hide();         }         t.body.update(msg);         t.doAutoWidth();         t.show();     },     getErrorText: function(){         var data = ['<ul>'];         this.items.each(function(f){             if(!f.isValid(true)){                 data.push('<li>', f.activeError, '</li>');             }         });         data.push('</ul>');         return data;     } }); Ext.preg('roweditor', Ext.ux.grid.RowEditor); Ext.override(Ext.form.Field, {     markInvalid : function(msg){         if(!this.rendered || this.preventMark){ // not rendered             return;         }         msg = msg || this.invalidText;         var mt = this.getMessageHandler();         if(mt){             mt.mark(this, msg);         }else if(this.msgTarget){             this.el.addClass(this.invalidClass);             var t = Ext.getDom(this.msgTarget);             if(t){                 t.innerHTML = msg;                 t.style.display = this.msgDisplay;             }         }         this.activeError = msg;         this.fireEvent('invalid', this, msg);     } }); Ext.override(Ext.ToolTip, {     doAutoWidth : function(){         var bw = this.body.getTextWidth();         if(this.title){             bw = Math.max(bw, this.header.child('span').getTextWidth(this.title));         }         bw += this.getFrameWidth() + (this.closable ? 20 : 0) + this.body.getPadding("lr") + 20;         this.setWidth(bw.constrain(this.minWidth, this.maxWidth));         // IE7 repaint bug on initial show         if(Ext.isIE7 && !this.repainted){             this.el.repaint();             this.repainted = true;         }     } }); Ext.ns('Ext.ux.grid');
  998. /**
  999.  * @class Ext.ux.grid.RowExpander
  1000.  * @extends Ext.util.Observable
  1001.  * Plugin (ptype = 'rowexpander') that adds the ability to have a Column in a grid which enables
  1002.  * a second row body which expands/contracts.  The expand/contract behavior is configurable to react
  1003.  * on clicking of the column, double click of the row, and/or hitting enter while a row is selected.
  1004.  *
  1005.  * @ptype rowexpander
  1006.  */
  1007. Ext.ux.grid.RowExpander = Ext.extend(Ext.util.Observable, {
  1008.     /**
  1009.      * @cfg {Boolean} expandOnEnter
  1010.      * <tt>true</tt> to toggle selected row(s) between expanded/collapsed when the enter
  1011.      * key is pressed (defaults to <tt>true</tt>).
  1012.      */
  1013.     expandOnEnter : true,
  1014.     /**
  1015.      * @cfg {Boolean} expandOnDblClick
  1016.      * <tt>true</tt> to toggle a row between expanded/collapsed when double clicked
  1017.      * (defaults to <tt>true</tt>).
  1018.      */
  1019.     expandOnDblClick : true,
  1020.     header : '',
  1021.     width : 20,
  1022.     sortable : false,
  1023.     fixed : true,
  1024.     menuDisabled : true,
  1025.     dataIndex : '',
  1026.     id : 'expander',
  1027.     lazyRender : true,
  1028.     enableCaching : true,
  1029.     constructor: function(config){
  1030.         Ext.apply(this, config);
  1031.         this.addEvents({
  1032.             /**
  1033.              * @event beforeexpand
  1034.              * Fires before the row expands. Have the listener return false to prevent the row from expanding.
  1035.              * @param {Object} this RowExpander object.
  1036.              * @param {Object} Ext.data.Record Record for the selected row.
  1037.              * @param {Object} body body element for the secondary row.
  1038.              * @param {Number} rowIndex The current row index.
  1039.              */
  1040.             beforeexpand: true,
  1041.             /**
  1042.              * @event expand
  1043.              * Fires after the row expands.
  1044.              * @param {Object} this RowExpander object.
  1045.              * @param {Object} Ext.data.Record Record for the selected row.
  1046.              * @param {Object} body body element for the secondary row.
  1047.              * @param {Number} rowIndex The current row index.
  1048.              */
  1049.             expand: true,
  1050.             /**
  1051.              * @event beforecollapse
  1052.              * Fires before the row collapses. Have the listener return false to prevent the row from collapsing.
  1053.              * @param {Object} this RowExpander object.
  1054.              * @param {Object} Ext.data.Record Record for the selected row.
  1055.              * @param {Object} body body element for the secondary row.
  1056.              * @param {Number} rowIndex The current row index.
  1057.              */
  1058.             beforecollapse: true,
  1059.             /**
  1060.              * @event collapse
  1061.              * Fires after the row collapses.
  1062.              * @param {Object} this RowExpander object.
  1063.              * @param {Object} Ext.data.Record Record for the selected row.
  1064.              * @param {Object} body body element for the secondary row.
  1065.              * @param {Number} rowIndex The current row index.
  1066.              */
  1067.             collapse: true
  1068.         });
  1069.         Ext.ux.grid.RowExpander.superclass.constructor.call(this);
  1070.         if(this.tpl){
  1071.             if(typeof this.tpl == 'string'){
  1072.                 this.tpl = new Ext.Template(this.tpl);
  1073.             }
  1074.             this.tpl.compile();
  1075.         }
  1076.         this.state = {};
  1077.         this.bodyContent = {};
  1078.     },
  1079.     getRowClass : function(record, rowIndex, p, ds){
  1080.         p.cols = p.cols-1;
  1081.         var content = this.bodyContent[record.id];
  1082.         if(!content && !this.lazyRender){
  1083.             content = this.getBodyContent(record, rowIndex);
  1084.         }
  1085.         if(content){
  1086.             p.body = content;
  1087.         }
  1088.         return this.state[record.id] ? 'x-grid3-row-expanded' : 'x-grid3-row-collapsed';
  1089.     },
  1090.     init : function(grid){
  1091.         this.grid = grid;
  1092.         var view = grid.getView();
  1093.         view.getRowClass = this.getRowClass.createDelegate(this);
  1094.         view.enableRowBody = true;
  1095.         grid.on('render', this.onRender, this);
  1096.         grid.on('destroy', this.onDestroy, this);
  1097.     },
  1098.     // @private
  1099.     onRender: function() {
  1100.         var grid = this.grid;
  1101.         var mainBody = grid.getView().mainBody;
  1102.         mainBody.on('mousedown', this.onMouseDown, this, {delegate: '.x-grid3-row-expander'});
  1103.         if (this.expandOnEnter) {
  1104.             this.keyNav = new Ext.KeyNav(this.grid.getGridEl(), {
  1105.                 'enter' : this.onEnter,
  1106.                 scope: this
  1107.             });
  1108.         }
  1109.         if (this.expandOnDblClick) {
  1110.             grid.on('rowdblclick', this.onRowDblClick, this);
  1111.         }
  1112.     },
  1113.     
  1114.     // @private    
  1115.     onDestroy: function() {
  1116.         this.keyNav.disable();
  1117.         delete this.keyNav;
  1118.         var mainBody = this.grid.getView().mainBody;
  1119.         mainBody.un('mousedown', this.onMouseDown, this);
  1120.     },
  1121.     // @private
  1122.     onRowDblClick: function(grid, rowIdx, e) {
  1123.         this.toggleRow(rowIdx);
  1124.     },
  1125.     onEnter: function(e) {
  1126.         var g = this.grid;
  1127.         var sm = g.getSelectionModel();
  1128.         var sels = sm.getSelections();
  1129.         for (var i = 0, len = sels.length; i < len; i++) {
  1130.             var rowIdx = g.getStore().indexOf(sels[i]);
  1131.             this.toggleRow(rowIdx);
  1132.         }
  1133.     },
  1134.     getBodyContent : function(record, index){
  1135.         if(!this.enableCaching){
  1136.             return this.tpl.apply(record.data);
  1137.         }
  1138.         var content = this.bodyContent[record.id];
  1139.         if(!content){
  1140.             content = this.tpl.apply(record.data);
  1141.             this.bodyContent[record.id] = content;
  1142.         }
  1143.         return content;
  1144.     },
  1145.     onMouseDown : function(e, t){
  1146.         e.stopEvent();
  1147.         var row = e.getTarget('.x-grid3-row');
  1148.         this.toggleRow(row);
  1149.     },
  1150.     renderer : function(v, p, record){
  1151.         p.cellAttr = 'rowspan="2"';
  1152.         return '<div class="x-grid3-row-expander">&#160;</div>';
  1153.     },
  1154.     beforeExpand : function(record, body, rowIndex){
  1155.         if(this.fireEvent('beforeexpand', this, record, body, rowIndex) !== false){
  1156.             if(this.tpl && this.lazyRender){
  1157.                 body.innerHTML = this.getBodyContent(record, rowIndex);
  1158.             }
  1159.             return true;
  1160.         }else{
  1161.             return false;
  1162.         }
  1163.     },
  1164.     toggleRow : function(row){
  1165.         if(typeof row == 'number'){
  1166.             row = this.grid.view.getRow(row);
  1167.         }
  1168.         this[Ext.fly(row).hasClass('x-grid3-row-collapsed') ? 'expandRow' : 'collapseRow'](row);
  1169.     },
  1170.     expandRow : function(row){
  1171.         if(typeof row == 'number'){
  1172.             row = this.grid.view.getRow(row);
  1173.         }
  1174.         var record = this.grid.store.getAt(row.rowIndex);
  1175.         var body = Ext.DomQuery.selectNode('tr:nth(2) div.x-grid3-row-body', row);
  1176.         if(this.beforeExpand(record, body, row.rowIndex)){
  1177.             this.state[record.id] = true;
  1178.             Ext.fly(row).replaceClass('x-grid3-row-collapsed', 'x-grid3-row-expanded');
  1179.             this.fireEvent('expand', this, record, body, row.rowIndex);
  1180.         }
  1181.     },
  1182.     collapseRow : function(row){
  1183.         if(typeof row == 'number'){
  1184.             row = this.grid.view.getRow(row);
  1185.         }
  1186.         var record = this.grid.store.getAt(row.rowIndex);
  1187.         var body = Ext.fly(row).child('tr:nth(1) div.x-grid3-row-body', true);
  1188.         if(this.fireEvent('beforecollapse', this, record, body, row.rowIndex) !== false){
  1189.             this.state[record.id] = false;
  1190.             Ext.fly(row).replaceClass('x-grid3-row-expanded', 'x-grid3-row-collapsed');
  1191.             this.fireEvent('collapse', this, record, body, row.rowIndex);
  1192.         }
  1193.     }
  1194. });
  1195. Ext.preg('rowexpander', Ext.ux.grid.RowExpander);
  1196. //backwards compat
  1197. Ext.grid.RowExpander = Ext.ux.grid.RowExpander;// We are adding these custom layouts to a namespace that does not // exist by default in Ext, so we have to add the namespace first: Ext.ns('Ext.ux.layout'); /**  * @class Ext.ux.layout.RowLayout  * @extends Ext.layout.ContainerLayout  * <p>This is the layout style of choice for creating structural layouts in a multi-row format where the height of  * each row can be specified as a percentage or fixed height.  Row widths can also be fixed, percentage or auto.  * This class is intended to be extended or created via the layout:'ux.row' {@link Ext.Container#layout} config,  * and should generally not need to be created directly via the new keyword.</p>  * <p>RowLayout does not have any direct config options (other than inherited ones), but it does support a  * specific config property of <b><tt>rowHeight</tt></b> that can be included in the config of any panel added to it.  The  * layout will use the rowHeight (if present) or height of each panel during layout to determine how to size each panel.  * If height or rowHeight is not specified for a given panel, its height will default to the panel's height (or auto).</p>  * <p>The height property is always evaluated as pixels, and must be a number greater than or equal to 1.  * The rowHeight property is always evaluated as a percentage, and must be a decimal value greater than 0 and  * less than 1 (e.g., .25).</p>  * <p>The basic rules for specifying row heights are pretty simple.  The logic makes two passes through the  * set of contained panels.  During the first layout pass, all panels that either have a fixed height or none  * specified (auto) are skipped, but their heights are subtracted from the overall container height.  During the second  * pass, all panels with rowHeights are assigned pixel heights in proportion to their percentages based on  * the total <b>remaining</b> container height.  In other words, percentage height panels are designed to fill the space  * left over by all the fixed-height and/or auto-height panels.  Because of this, while you can specify any number of rows  * with different percentages, the rowHeights must always add up to 1 (or 100%) when added together, otherwise your  * layout may not render as expected.  Example usage:</p>  * <pre><code> // All rows are percentages -- they must add up to 1 var p = new Ext.Panel({     title: 'Row Layout - Percentage Only',     layout:'ux.row',     items: [{         title: 'Row 1',         rowHeight: .25     },{         title: 'Row 2',         rowHeight: .6     },{         title: 'Row 3',         rowHeight: .15     }] }); // Mix of height and rowHeight -- all rowHeight values must add // up to 1. The first row will take up exactly 120px, and the last two // rows will fill the remaining container height. var p = new Ext.Panel({     title: 'Row Layout - Mixed',     layout:'ux.row',     items: [{         title: 'Row 1',         height: 120,         // standard panel widths are still supported too:         width: '50%' // or 200     },{         title: 'Row 2',         rowHeight: .8,         width: 300     },{         title: 'Row 3',         rowHeight: .2     }] }); </code></pre>  */ Ext.ux.layout.RowLayout = Ext.extend(Ext.layout.ContainerLayout, {     // private     monitorResize:true,     // private     isValidParent : function(c, target){         return c.getEl().dom.parentNode == this.innerCt.dom;     },     // private     onLayout : function(ct, target){         var rs = ct.items.items, len = rs.length, r, i;         if(!this.innerCt){             target.addClass('ux-row-layout-ct');             this.innerCt = target.createChild({cls:'x-row-inner'});         }         this.renderAll(ct, this.innerCt);         var size = target.getViewSize();         if(size.width < 1 && size.height < 1){ // display none?             return;         }         var h = size.height - target.getPadding('tb'),             ph = h;         this.innerCt.setSize({height:h});         // some rows can be percentages while others are fixed         // so we need to make 2 passes         for(i = 0; i < len; i++){             r = rs[i];             if(!r.rowHeight){                 ph -= (r.getSize().height + r.getEl().getMargins('tb'));             }         }         ph = ph < 0 ? 0 : ph;         for(i = 0; i < len; i++){             r = rs[i];             if(r.rowHeight){                 r.setSize({height: Math.floor(r.rowHeight*ph) - r.getEl().getMargins('tb')});             }         }     }     /**      * @property activeItem      * @hide      */ }); Ext.Container.LAYOUTS['ux.row'] = Ext.ux.layout.RowLayout; Ext.ns('Ext.ux.form');
  1198. Ext.ux.form.SearchField = Ext.extend(Ext.form.TwinTriggerField, {
  1199.     initComponent : function(){
  1200.         Ext.ux.form.SearchField.superclass.initComponent.call(this);
  1201.         this.on('specialkey', function(f, e){
  1202.             if(e.getKey() == e.ENTER){
  1203.                 this.onTrigger2Click();
  1204.             }
  1205.         }, this);
  1206.     },
  1207.     validationEvent:false,
  1208.     validateOnBlur:false,
  1209.     trigger1Class:'x-form-clear-trigger',
  1210.     trigger2Class:'x-form-search-trigger',
  1211.     hideTrigger1:true,
  1212.     width:180,
  1213.     hasSearch : false,
  1214.     paramName : 'query',
  1215.     onTrigger1Click : function(){
  1216.         if(this.hasSearch){
  1217.             this.el.dom.value = '';
  1218.             var o = {start: 0};
  1219.             this.store.baseParams = this.store.baseParams || {};
  1220.             this.store.baseParams[this.paramName] = '';
  1221.             this.store.reload({params:o});
  1222.             this.triggers[0].hide();
  1223.             this.hasSearch = false;
  1224.         }
  1225.     },
  1226.     onTrigger2Click : function(){
  1227.         var v = this.getRawValue();
  1228.         if(v.length < 1){
  1229.             this.onTrigger1Click();
  1230.             return;
  1231.         }
  1232.         var o = {start: 0};
  1233.         this.store.baseParams = this.store.baseParams || {};
  1234.         this.store.baseParams[this.paramName] = v;
  1235.         this.store.reload({params:o});
  1236.         this.hasSearch = true;
  1237.         this.triggers[0].show();
  1238.     }
  1239. });Ext.ns('Ext.ux.form');
  1240. /**
  1241.  * @class Ext.ux.form.SelectBox
  1242.  * @extends Ext.form.ComboBox
  1243.  * <p>Makes a ComboBox more closely mimic an HTML SELECT.  Supports clicking and dragging
  1244.  * through the list, with item selection occurring when the mouse button is released.
  1245.  * When used will automatically set {@link #editable} to false and call {@link Ext.Element#unselectable}
  1246.  * on inner elements.  Re-enabling editable after calling this will NOT work.</p>
  1247.  * @author Corey Gilmore http://extjs.com/forum/showthread.php?t=6392
  1248.  * @history 2007-07-08 jvs
  1249.  * Slight mods for Ext 2.0
  1250.  * @xtype selectbox
  1251.  */
  1252. Ext.ux.form.SelectBox = Ext.extend(Ext.form.ComboBox, {
  1253. constructor: function(config){
  1254. this.searchResetDelay = 1000;
  1255. config = config || {};
  1256. config = Ext.apply(config || {}, {
  1257. editable: false,
  1258. forceSelection: true,
  1259. rowHeight: false,
  1260. lastSearchTerm: false,
  1261. triggerAction: 'all',
  1262. mode: 'local'
  1263. });
  1264. Ext.ux.form.SelectBox.superclass.constructor.apply(this, arguments);
  1265. this.lastSelectedIndex = this.selectedIndex || 0;
  1266. },
  1267. initEvents : function(){
  1268. Ext.ux.form.SelectBox.superclass.initEvents.apply(this, arguments);
  1269. // you need to use keypress to capture upper/lower case and shift+key, but it doesn't work in IE
  1270. this.el.on('keydown', this.keySearch, this, true);
  1271. this.cshTask = new Ext.util.DelayedTask(this.clearSearchHistory, this);
  1272. },
  1273. keySearch : function(e, target, options) {
  1274. var raw = e.getKey();
  1275. var key = String.fromCharCode(raw);
  1276. var startIndex = 0;
  1277. if( !this.store.getCount() ) {
  1278. return;
  1279. }
  1280. switch(raw) {
  1281. case Ext.EventObject.HOME:
  1282. e.stopEvent();
  1283. this.selectFirst();
  1284. return;
  1285. case Ext.EventObject.END:
  1286. e.stopEvent();
  1287. this.selectLast();
  1288. return;
  1289. case Ext.EventObject.PAGEDOWN:
  1290. this.selectNextPage();
  1291. e.stopEvent();
  1292. return;
  1293. case Ext.EventObject.PAGEUP:
  1294. this.selectPrevPage();
  1295. e.stopEvent();
  1296. return;
  1297. }
  1298. // skip special keys other than the shift key
  1299. if( (e.hasModifier() && !e.shiftKey) || e.isNavKeyPress() || e.isSpecialKey() ) {
  1300. return;
  1301. }
  1302. if( this.lastSearchTerm == key ) {
  1303. startIndex = this.lastSelectedIndex;
  1304. }
  1305. this.search(this.displayField, key, startIndex);
  1306. this.cshTask.delay(this.searchResetDelay);
  1307. },
  1308. onRender : function(ct, position) {
  1309. this.store.on('load', this.calcRowsPerPage, this);
  1310. Ext.ux.form.SelectBox.superclass.onRender.apply(this, arguments);
  1311. if( this.mode == 'local' ) {
  1312. this.calcRowsPerPage();
  1313. }
  1314. },
  1315. onSelect : function(record, index, skipCollapse){
  1316. if(this.fireEvent('beforeselect', this, record, index) !== false){
  1317. this.setValue(record.data[this.valueField || this.displayField]);
  1318. if( !skipCollapse ) {
  1319. this.collapse();
  1320. }
  1321. this.lastSelectedIndex = index + 1;
  1322. this.fireEvent('select', this, record, index);
  1323. }
  1324. },
  1325. render : function(ct) {
  1326. Ext.ux.form.SelectBox.superclass.render.apply(this, arguments);
  1327. if( Ext.isSafari ) {
  1328. this.el.swallowEvent('mousedown', true);
  1329. }
  1330. this.el.unselectable();
  1331. this.innerList.unselectable();
  1332. this.trigger.unselectable();
  1333. this.innerList.on('mouseup', function(e, target, options) {
  1334. if( target.id && target.id == this.innerList.id ) {
  1335. return;
  1336. }
  1337. this.onViewClick();
  1338. }, this);
  1339. this.innerList.on('mouseover', function(e, target, options) {
  1340. if( target.id && target.id == this.innerList.id ) {
  1341. return;
  1342. }
  1343. this.lastSelectedIndex = this.view.getSelectedIndexes()[0] + 1;
  1344. this.cshTask.delay(this.searchResetDelay);
  1345. }, this);
  1346. this.trigger.un('click', this.onTriggerClick, this);
  1347. this.trigger.on('mousedown', function(e, target, options) {
  1348. e.preventDefault();
  1349. this.onTriggerClick();
  1350. }, this);
  1351. this.on('collapse', function(e, target, options) {
  1352. Ext.getDoc().un('mouseup', this.collapseIf, this);
  1353. }, this, true);
  1354. this.on('expand', function(e, target, options) {
  1355. Ext.getDoc().on('mouseup', this.collapseIf, this);
  1356. }, this, true);
  1357. },
  1358. clearSearchHistory : function() {
  1359. this.lastSelectedIndex = 0;
  1360. this.lastSearchTerm = false;
  1361. },
  1362. selectFirst : function() {
  1363. this.focusAndSelect(this.store.data.first());
  1364. },
  1365. selectLast : function() {
  1366. this.focusAndSelect(this.store.data.last());
  1367. },
  1368. selectPrevPage : function() {
  1369. if( !this.rowHeight ) {
  1370. return;
  1371. }
  1372. var index = Math.max(this.selectedIndex-this.rowsPerPage, 0);
  1373. this.focusAndSelect(this.store.getAt(index));
  1374. },
  1375. selectNextPage : function() {
  1376. if( !this.rowHeight ) {
  1377. return;
  1378. }
  1379. var index = Math.min(this.selectedIndex+this.rowsPerPage, this.store.getCount() - 1);
  1380. this.focusAndSelect(this.store.getAt(index));
  1381. },
  1382. search : function(field, value, startIndex) {
  1383. field = field || this.displayField;
  1384. this.lastSearchTerm = value;
  1385. var index = this.store.find.apply(this.store, arguments);
  1386. if( index !== -1 ) {
  1387. this.focusAndSelect(index);
  1388. }
  1389. },
  1390. focusAndSelect : function(record) {
  1391. var index = typeof record === 'number' ? record : this.store.indexOf(record);
  1392. this.select(index, this.isExpanded());
  1393. this.onSelect(this.store.getAt(record), index, this.isExpanded());
  1394. },
  1395. calcRowsPerPage : function() {
  1396. if( this.store.getCount() ) {
  1397. this.rowHeight = Ext.fly(this.view.getNode(0)).getHeight();
  1398. this.rowsPerPage = this.maxHeight / this.rowHeight;
  1399. } else {
  1400. this.rowHeight = false;
  1401. }
  1402. }
  1403. });
  1404. Ext.reg('selectbox', Ext.ux.form.SelectBox);
  1405. //backwards compat
  1406. Ext.ux.SelectBox = Ext.ux.form.SelectBox;
  1407. /**
  1408.  * @class Ext.ux.SliderTip
  1409.  * @extends Ext.Tip
  1410.  * Simple plugin for using an Ext.Tip with a slider to show the slider value
  1411.  */
  1412. Ext.ux.SliderTip = Ext.extend(Ext.Tip, {
  1413.     minWidth: 10,
  1414.     offsets : [0, -10],
  1415.     init : function(slider){
  1416.         slider.on('dragstart', this.onSlide, this);
  1417.         slider.on('drag', this.onSlide, this);
  1418.         slider.on('dragend', this.hide, this);
  1419.         slider.on('destroy', this.destroy, this);
  1420.     },
  1421.     onSlide : function(slider){
  1422.         this.show();
  1423.         this.body.update(this.getText(slider));
  1424.         this.doAutoWidth();
  1425.         this.el.alignTo(slider.thumb, 'b-t?', this.offsets);
  1426.     },
  1427.     getText : function(slider){
  1428.         return String(slider.getValue());
  1429.     }
  1430. });
  1431. Ext.ux.SlidingPager = Ext.extend(Object, {
  1432.     init : function(pbar){
  1433.         Ext.each(pbar.items.getRange(2,6), function(c){
  1434.             c.hide();
  1435.         });
  1436.         var slider = new Ext.Slider({
  1437.             width: 114,
  1438.             minValue: 1,
  1439.             maxValue: 1,
  1440.             plugins: new Ext.ux.SliderTip({
  1441.                 getText : function(s){
  1442.                     return String.format('Page <b>{0}</b> of <b>{1}</b>', s.value, s.maxValue);
  1443.                 }
  1444.             }),
  1445.             listeners: {
  1446.                 changecomplete: function(s, v){
  1447.                     pbar.changePage(v);
  1448.                 }
  1449.             }
  1450.         });
  1451.         pbar.insert(5, slider);
  1452.         pbar.on({
  1453.             change: function(pb, data){
  1454.                 slider.maxValue = data.pages;
  1455.                 slider.setValue(data.activePage);
  1456.             },
  1457.             beforedestroy: function(){
  1458.                 slider.destroy();
  1459.             }
  1460.         });
  1461.     }
  1462. });Ext.ns('Ext.ux.form');
  1463. /**
  1464.  * @class Ext.ux.form.SpinnerField
  1465.  * @extends Ext.form.NumberField
  1466.  * Creates a field utilizing Ext.ux.Spinner
  1467.  * @xtype spinnerfield
  1468.  */
  1469. Ext.ux.form.SpinnerField = Ext.extend(Ext.form.NumberField, {
  1470.     deferHeight: true,
  1471.     autoSize: Ext.emptyFn,
  1472.     onBlur: Ext.emptyFn,
  1473.     adjustSize: Ext.BoxComponent.prototype.adjustSize,
  1474. constructor: function(config) {
  1475. var spinnerConfig = Ext.copyTo({}, config, 'incrementValue,alternateIncrementValue,accelerate,defaultValue,triggerClass,splitterClass');
  1476. var spl = this.spinner = new Ext.ux.Spinner(spinnerConfig);
  1477. var plugins = config.plugins
  1478. ? (Ext.isArray(config.plugins)
  1479. ? config.plugins.push(spl)
  1480. : [config.plugins, spl])
  1481. : spl;
  1482. Ext.ux.form.SpinnerField.superclass.constructor.call(this, Ext.apply(config, {plugins: plugins}));
  1483. },
  1484.     onShow: function(){
  1485.         if (this.wrap) {
  1486.             this.wrap.dom.style.display = '';
  1487.             this.wrap.dom.style.visibility = 'visible';
  1488.         }
  1489.     },
  1490.     onHide: function(){
  1491.         this.wrap.dom.style.display = 'none';
  1492.     },
  1493.     // private
  1494.     getResizeEl: function(){
  1495.         return this.wrap;
  1496.     },
  1497.     // private
  1498.     getPositionEl: function(){
  1499.         return this.wrap;
  1500.     },
  1501.     // private
  1502.     alignErrorIcon: function(){
  1503.         if (this.wrap) {
  1504.             this.errorIcon.alignTo(this.wrap, 'tl-tr', [2, 0]);
  1505.         }
  1506.     },
  1507.     validateBlur: function(){
  1508.         return true;
  1509.     }
  1510. });
  1511. Ext.reg('spinnerfield', Ext.ux.form.SpinnerField);
  1512. //backwards compat
  1513. Ext.form.SpinnerField = Ext.ux.form.SpinnerField;
  1514. /**
  1515.  * @class Ext.ux.Spinner
  1516.  * @extends Ext.util.Observable
  1517.  * Creates a Spinner control utilized by Ext.ux.form.SpinnerField
  1518.  */
  1519. Ext.ux.Spinner = Ext.extend(Ext.util.Observable, {
  1520.     incrementValue: 1,
  1521.     alternateIncrementValue: 5,
  1522.     triggerClass: 'x-form-spinner-trigger',
  1523.     splitterClass: 'x-form-spinner-splitter',
  1524.     alternateKey: Ext.EventObject.shiftKey,
  1525.     defaultValue: 0,
  1526.     accelerate: false,
  1527.     constructor: function(config){
  1528.         Ext.ux.Spinner.superclass.constructor.call(this, config);
  1529.         Ext.apply(this, config);
  1530.         this.mimicing = false;
  1531.     },
  1532.     init: function(field){
  1533.         this.field = field;
  1534.         field.afterMethod('onRender', this.doRender, this);
  1535.         field.afterMethod('onEnable', this.doEnable, this);
  1536.         field.afterMethod('onDisable', this.doDisable, this);
  1537.         field.afterMethod('afterRender', this.doAfterRender, this);
  1538.         field.afterMethod('onResize', this.doResize, this);
  1539.         field.afterMethod('onFocus', this.doFocus, this);
  1540.         field.beforeMethod('onDestroy', this.doDestroy, this);
  1541.     },
  1542.     doRender: function(ct, position){
  1543.         var el = this.el = this.field.getEl();
  1544.         var f = this.field;
  1545.         if (!f.wrap) {
  1546.             f.wrap = this.wrap = el.wrap({
  1547.                 cls: "x-form-field-wrap"
  1548.             });
  1549.         }
  1550.         else {
  1551.             this.wrap = f.wrap.addClass('x-form-field-wrap');
  1552.         }
  1553.         this.trigger = this.wrap.createChild({
  1554.             tag: "img",
  1555.             src: Ext.BLANK_IMAGE_URL,
  1556.             cls: "x-form-trigger " + this.triggerClass
  1557.         });
  1558.         if (!f.width) {
  1559.             this.wrap.setWidth(el.getWidth() + this.trigger.getWidth());
  1560.         }
  1561.         this.splitter = this.wrap.createChild({
  1562.             tag: 'div',
  1563.             cls: this.splitterClass,
  1564.             style: 'width:13px; height:2px;'
  1565.         });
  1566.         this.splitter.setRight((Ext.isIE) ? 1 : 2).setTop(10).show();
  1567.         this.proxy = this.trigger.createProxy('', this.splitter, true);
  1568.         this.proxy.addClass("x-form-spinner-proxy");
  1569.         this.proxy.setStyle('left', '0px');
  1570.         this.proxy.setSize(14, 1);
  1571.         this.proxy.hide();
  1572.         this.dd = new Ext.dd.DDProxy(this.splitter.dom.id, "SpinnerDrag", {
  1573.             dragElId: this.proxy.id
  1574.         });
  1575.         this.initTrigger();
  1576.         this.initSpinner();
  1577.     },
  1578.     doAfterRender: function(){
  1579.         var y;
  1580.         if (Ext.isIE && this.el.getY() != (y = this.trigger.getY())) {
  1581.             this.el.position();
  1582.             this.el.setY(y);
  1583.         }
  1584.     },
  1585.     doEnable: function(){
  1586.         if (this.wrap) {
  1587.             this.wrap.removeClass(this.field.disabledClass);
  1588.         }
  1589.     },
  1590.     doDisable: function(){
  1591.         if (this.wrap) {
  1592.             this.wrap.addClass(this.field.disabledClass);
  1593.             this.el.removeClass(this.field.disabledClass);
  1594.         }
  1595.     },
  1596.     doResize: function(w, h){
  1597.         if (typeof w == 'number') {
  1598.             this.el.setWidth(this.field.adjustWidth('input', w - this.trigger.getWidth()));
  1599.         }
  1600.         this.wrap.setWidth(this.el.getWidth() + this.trigger.getWidth());
  1601.     },
  1602.     doFocus: function(){
  1603.         if (!this.mimicing) {
  1604.             this.wrap.addClass('x-trigger-wrap-focus');
  1605.             this.mimicing = true;
  1606.             Ext.get(Ext.isIE ? document.body : document).on("mousedown", this.mimicBlur, this, {
  1607.                 delay: 10
  1608.             });
  1609.             this.el.on('keydown', this.checkTab, this);
  1610.         }
  1611.     },
  1612.     // private
  1613.     checkTab: function(e){
  1614.         if (e.getKey() == e.TAB) {
  1615.             this.triggerBlur();
  1616.         }
  1617.     },
  1618.     // private
  1619.     mimicBlur: function(e){
  1620.         if (!this.wrap.contains(e.target) && this.field.validateBlur(e)) {
  1621.             this.triggerBlur();
  1622.         }
  1623.     },
  1624.     // private
  1625.     triggerBlur: function(){
  1626.         this.mimicing = false;
  1627.         Ext.get(Ext.isIE ? document.body : document).un("mousedown", this.mimicBlur, this);
  1628.         this.el.un("keydown", this.checkTab, this);
  1629.         this.field.beforeBlur();
  1630.         this.wrap.removeClass('x-trigger-wrap-focus');
  1631.         this.field.onBlur.call(this.field);
  1632.     },
  1633.     initTrigger: function(){
  1634.         this.trigger.addClassOnOver('x-form-trigger-over');
  1635.         this.trigger.addClassOnClick('x-form-trigger-click');
  1636.     },
  1637.     initSpinner: function(){
  1638.         this.field.addEvents({
  1639.             'spin': true,
  1640.             'spinup': true,
  1641.             'spindown': true
  1642.         });
  1643.         this.keyNav = new Ext.KeyNav(this.el, {
  1644.             "up": function(e){
  1645.                 e.preventDefault();
  1646.                 this.onSpinUp();
  1647.             },
  1648.             "down": function(e){
  1649.                 e.preventDefault();
  1650.                 this.onSpinDown();
  1651.             },
  1652.             "pageUp": function(e){
  1653.                 e.preventDefault();
  1654.                 this.onSpinUpAlternate();
  1655.             },
  1656.             "pageDown": function(e){
  1657.                 e.preventDefault();
  1658.                 this.onSpinDownAlternate();
  1659.             },
  1660.             scope: this
  1661.         });
  1662.         this.repeater = new Ext.util.ClickRepeater(this.trigger, {
  1663.             accelerate: this.accelerate
  1664.         });
  1665.         this.field.mon(this.repeater, "click", this.onTriggerClick, this, {
  1666.             preventDefault: true
  1667.         });
  1668.         this.field.mon(this.trigger, {
  1669.             mouseover: this.onMouseOver,
  1670.             mouseout: this.onMouseOut,
  1671.             mousemove: this.onMouseMove,
  1672.             mousedown: this.onMouseDown,
  1673.             mouseup: this.onMouseUp,
  1674.             scope: this,
  1675.             preventDefault: true
  1676.         });
  1677.         this.field.mon(this.wrap, "mousewheel", this.handleMouseWheel, this);
  1678.         this.dd.setXConstraint(0, 0, 10)
  1679.         this.dd.setYConstraint(1500, 1500, 10);
  1680.         this.dd.endDrag = this.endDrag.createDelegate(this);
  1681.         this.dd.startDrag = this.startDrag.createDelegate(this);
  1682.         this.dd.onDrag = this.onDrag.createDelegate(this);
  1683.     },
  1684.     onMouseOver: function(){
  1685.         if (this.disabled) {
  1686.             return;
  1687.         }
  1688.         var middle = this.getMiddle();
  1689.         this.tmpHoverClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-overup' : 'x-form-spinner-overdown';
  1690.         this.trigger.addClass(this.tmpHoverClass);
  1691.     },
  1692.     //private
  1693.     onMouseOut: function(){
  1694.         this.trigger.removeClass(this.tmpHoverClass);
  1695.     },
  1696.     //private
  1697.     onMouseMove: function(){
  1698.         if (this.disabled) {
  1699.             return;
  1700.         }
  1701.         var middle = this.getMiddle();
  1702.         if (((Ext.EventObject.getPageY() > middle) && this.tmpHoverClass == "x-form-spinner-overup") ||
  1703.         ((Ext.EventObject.getPageY() < middle) && this.tmpHoverClass == "x-form-spinner-overdown")) {
  1704.         }
  1705.     },
  1706.     //private
  1707.     onMouseDown: function(){
  1708.         if (this.disabled) {
  1709.             return;
  1710.         }
  1711.         var middle = this.getMiddle();
  1712.         this.tmpClickClass = (Ext.EventObject.getPageY() < middle) ? 'x-form-spinner-clickup' : 'x-form-spinner-clickdown';
  1713.         this.trigger.addClass(this.tmpClickClass);
  1714.     },
  1715.     //private
  1716.     onMouseUp: function(){
  1717.         this.trigger.removeClass(this.tmpClickClass);
  1718.     },
  1719.     //private
  1720.     onTriggerClick: function(){
  1721.         if (this.disabled || this.el.dom.readOnly) {
  1722.             return;
  1723.         }
  1724.         var middle = this.getMiddle();
  1725.         var ud = (Ext.EventObject.getPageY() < middle) ? 'Up' : 'Down';
  1726.         this['onSpin' + ud]();
  1727.     },
  1728.     //private
  1729.     getMiddle: function(){
  1730.         var t = this.trigger.getTop();
  1731.         var h = this.trigger.getHeight();
  1732.         var middle = t + (h / 2);
  1733.         return middle;
  1734.     },
  1735.     //private
  1736.     //checks if control is allowed to spin
  1737.     isSpinnable: function(){
  1738.         if (this.disabled || this.el.dom.readOnly) {
  1739.             Ext.EventObject.preventDefault(); //prevent scrolling when disabled/readonly
  1740.             return false;
  1741.         }
  1742.         return true;
  1743.     },
  1744.     handleMouseWheel: function(e){
  1745.         //disable scrolling when not focused
  1746.         if (this.wrap.hasClass('x-trigger-wrap-focus') == false) {
  1747.             return;
  1748.         }
  1749.         var delta = e.getWheelDelta();
  1750.         if (delta > 0) {
  1751.             this.onSpinUp();
  1752.             e.stopEvent();
  1753.         }
  1754.         else
  1755.             if (delta < 0) {
  1756.                 this.onSpinDown();
  1757.                 e.stopEvent();
  1758.             }
  1759.     },
  1760.     //private
  1761.     startDrag: function(){
  1762.         this.proxy.show();
  1763.         this._previousY = Ext.fly(this.dd.getDragEl()).getTop();
  1764.     },
  1765.     //private
  1766.     endDrag: function(){
  1767.         this.proxy.hide();
  1768.     },
  1769.     //private
  1770.     onDrag: function(){
  1771.         if (this.disabled) {
  1772.             return;
  1773.         }
  1774.         var y = Ext.fly(this.dd.getDragEl()).getTop();
  1775.         var ud = '';
  1776.         if (this._previousY > y) {
  1777.             ud = 'Up';
  1778.         } //up
  1779.         if (this._previousY < y) {
  1780.             ud = 'Down';
  1781.         } //down
  1782.         if (ud != '') {
  1783.             this['onSpin' + ud]();
  1784.         }
  1785.         this._previousY = y;
  1786.     },
  1787.     //private
  1788.     onSpinUp: function(){
  1789.         if (this.isSpinnable() == false) {
  1790.             return;
  1791.         }
  1792.         if (Ext.EventObject.shiftKey == true) {
  1793.             this.onSpinUpAlternate();
  1794.             return;
  1795.         }
  1796.         else {
  1797.             this.spin(false, false);
  1798.         }
  1799.         this.field.fireEvent("spin", this);
  1800.         this.field.fireEvent("spinup", this);
  1801.     },
  1802.     //private
  1803.     onSpinDown: function(){
  1804.         if (this.isSpinnable() == false) {
  1805.             return;
  1806.         }
  1807.         if (Ext.EventObject.shiftKey == true) {
  1808.             this.onSpinDownAlternate();
  1809.             return;
  1810.         }
  1811.         else {
  1812.             this.spin(true, false);
  1813.         }
  1814.         this.field.fireEvent("spin", this);
  1815.         this.field.fireEvent("spindown", this);
  1816.     },
  1817.     //private
  1818.     onSpinUpAlternate: function(){
  1819.         if (this.isSpinnable() == false) {
  1820.             return;
  1821.         }
  1822.         this.spin(false, true);
  1823.         this.field.fireEvent("spin", this);
  1824.         this.field.fireEvent("spinup", this);
  1825.     },
  1826.     //private
  1827.     onSpinDownAlternate: function(){
  1828.         if (this.isSpinnable() == false) {
  1829.             return;
  1830.         }
  1831.         this.spin(true, true);
  1832.         this.field.fireEvent("spin", this);
  1833.         this.field.fireEvent("spindown", this);
  1834.     },
  1835.     spin: function(down, alternate){
  1836.         var v = parseFloat(this.field.getValue());
  1837.         var incr = (alternate == true) ? this.alternateIncrementValue : this.incrementValue;
  1838.         (down == true) ? v -= incr : v += incr;
  1839.         v = (isNaN(v)) ? this.defaultValue : v;
  1840.         v = this.fixBoundries(v);
  1841.         this.field.setRawValue(v);
  1842.     },
  1843.     fixBoundries: function(value){
  1844.         var v = value;
  1845.         if (this.field.minValue != undefined && v < this.field.minValue) {
  1846.             v = this.field.minValue;
  1847.         }
  1848.         if (this.field.maxValue != undefined && v > this.field.maxValue) {
  1849.             v = this.field.maxValue;
  1850.         }
  1851.         return this.fixPrecision(v);
  1852.     },
  1853.     // private
  1854.     fixPrecision: function(value){
  1855.         var nan = isNaN(value);
  1856.         if (!this.field.allowDecimals || this.field.decimalPrecision == -1 || nan || !value) {
  1857.             return nan ? '' : value;
  1858.         }
  1859.         return parseFloat(parseFloat(value).toFixed(this.field.decimalPrecision));
  1860.     },
  1861.     doDestroy: function(){
  1862.         if (this.trigger) {
  1863.             this.trigger.remove();
  1864.         }
  1865.         if (this.wrap) {
  1866.             this.wrap.remove();
  1867.             delete this.field.wrap;
  1868.         }
  1869.         if (this.splitter) {
  1870.             this.splitter.remove();
  1871.         }
  1872.         if (this.dd) {
  1873.             this.dd.unreg();
  1874.             this.dd = null;
  1875.         }
  1876.         if (this.proxy) {
  1877.             this.proxy.remove();
  1878.         }
  1879.         if (this.repeater) {
  1880.             this.repeater.purgeListeners();
  1881.         }
  1882.     }
  1883. });
  1884. //backwards compat
  1885. Ext.form.Spinner = Ext.ux.Spinner;Ext.ux.Spotlight = function(config){
  1886.     Ext.apply(this, config);
  1887. }
  1888. Ext.ux.Spotlight.prototype = {
  1889.     active : false,
  1890.     animate : true,
  1891.     duration: .25,
  1892.     easing:'easeNone',
  1893.     // private
  1894.     animated : false,
  1895.     createElements : function(){
  1896.         var bd = Ext.getBody();
  1897.         this.right = bd.createChild({cls:'x-spotlight'});
  1898.         this.left = bd.createChild({cls:'x-spotlight'});
  1899.         this.top = bd.createChild({cls:'x-spotlight'});
  1900.         this.bottom = bd.createChild({cls:'x-spotlight'});
  1901.         this.all = new Ext.CompositeElement([this.right, this.left, this.top, this.bottom]);
  1902.     },
  1903.     show : function(el, callback, scope){
  1904.         if(this.animated){
  1905.             this.show.defer(50, this, [el, callback, scope]);
  1906.             return;
  1907.         }
  1908.         this.el = Ext.get(el);
  1909.         if(!this.right){
  1910.             this.createElements();
  1911.         }
  1912.         if(!this.active){
  1913.             this.all.setDisplayed('');
  1914.             this.applyBounds(true, false);
  1915.             this.active = true;
  1916.             Ext.EventManager.onWindowResize(this.syncSize, this);
  1917.             this.applyBounds(false, this.animate, false, callback, scope);
  1918.         }else{
  1919.             this.applyBounds(false, false, false, callback, scope); // all these booleans look hideous
  1920.         }
  1921.     },
  1922.     hide : function(callback, scope){
  1923.         if(this.animated){
  1924.             this.hide.defer(50, this, [callback, scope]);
  1925.             return;
  1926.         }
  1927.         Ext.EventManager.removeResizeListener(this.syncSize, this);
  1928.         this.applyBounds(true, this.animate, true, callback, scope);
  1929.     },
  1930.     doHide : function(){
  1931.         this.active = false;
  1932.         this.all.setDisplayed(false);
  1933.     },
  1934.     syncSize : function(){
  1935.         this.applyBounds(false, false);
  1936.     },
  1937.     applyBounds : function(basePts, anim, doHide, callback, scope){
  1938.         var rg = this.el.getRegion();
  1939.         var dw = Ext.lib.Dom.getViewWidth(true);
  1940.         var dh = Ext.lib.Dom.getViewHeight(true);
  1941.         var c = 0, cb = false;
  1942.         if(anim){
  1943.             cb = {
  1944.                 callback: function(){
  1945.                     c++;
  1946.                     if(c == 4){
  1947.                         this.animated = false;
  1948.                         if(doHide){
  1949.                             this.doHide();
  1950.                         }
  1951.                         Ext.callback(callback, scope, [this]);
  1952.                     }
  1953.                 },
  1954.                 scope: this,
  1955.                 duration: this.duration,
  1956.                 easing: this.easing
  1957.             };
  1958.             this.animated = true;
  1959.         }
  1960.         this.right.setBounds(
  1961.                 rg.right,
  1962.                 basePts ? dh : rg.top,
  1963.                 dw - rg.right,
  1964.                 basePts ? 0 : (dh - rg.top),
  1965.                 cb);
  1966.         this.left.setBounds(
  1967.                 0,
  1968.                 0,
  1969.                 rg.left,
  1970.                 basePts ? 0 : rg.bottom,
  1971.                 cb);
  1972.         this.top.setBounds(
  1973.                 basePts ? dw : rg.left,
  1974.                 0,
  1975.                 basePts ? 0 : dw - rg.left,
  1976.                 rg.top,
  1977.                 cb);
  1978.         this.bottom.setBounds(
  1979.                 0,
  1980.                 rg.bottom,
  1981.                 basePts ? 0 : rg.right,
  1982.                 dh - rg.bottom,
  1983.                 cb);
  1984.         if(!anim){
  1985.             if(doHide){
  1986.                 this.doHide();
  1987.             }
  1988.             if(callback){
  1989.                 Ext.callback(callback, scope, [this]);
  1990.             }
  1991.         }
  1992.     },
  1993.     destroy : function(){
  1994.         this.doHide();
  1995.         Ext.destroy(
  1996.             this.right,
  1997.             this.left,
  1998.             this.top,
  1999.             this.bottom);
  2000.         delete this.el;
  2001.         delete this.all;
  2002.     }
  2003. };
  2004. //backwards compat
  2005. Ext.Spotlight = Ext.ux.Spotlight;/**
  2006.  * @class Ext.ux.TabCloseMenu
  2007.  * @extends Object 
  2008.  * Plugin (ptype = 'tabclosemenu') for adding a close context menu to tabs.
  2009.  * 
  2010.  * @ptype tabclosemenu
  2011.  */
  2012. Ext.ux.TabCloseMenu = function(){
  2013.     var tabs, menu, ctxItem;
  2014.     this.init = function(tp){
  2015.         tabs = tp;
  2016.         tabs.on('contextmenu', onContextMenu);
  2017.     };
  2018.     function onContextMenu(ts, item, e){
  2019.         if(!menu){ // create context menu on first right click
  2020.             menu = new Ext.menu.Menu({            
  2021.             items: [{
  2022.                 id: tabs.id + '-close',
  2023.                 text: 'Close Tab',
  2024.                 handler : function(){
  2025.                     tabs.remove(ctxItem);
  2026.                 }
  2027.             },{
  2028.                 id: tabs.id + '-close-others',
  2029.                 text: 'Close Other Tabs',
  2030.                 handler : function(){
  2031.                     tabs.items.each(function(item){
  2032.                         if(item.closable && item != ctxItem){
  2033.                             tabs.remove(item);
  2034.                         }
  2035.                     });
  2036.                 }
  2037.             }]});
  2038.         }
  2039.         ctxItem = item;
  2040.         var items = menu.items;
  2041.         items.get(tabs.id + '-close').setDisabled(!item.closable);
  2042.         var disableOthers = true;
  2043.         tabs.items.each(function(){
  2044.             if(this != item && this.closable){
  2045.                 disableOthers = false;
  2046.                 return false;
  2047.             }
  2048.         });
  2049.         items.get(tabs.id + '-close-others').setDisabled(disableOthers);
  2050. e.stopEvent();
  2051.         menu.showAt(e.getPoint());
  2052.     }
  2053. };
  2054. Ext.preg('tabclosemenu', Ext.ux.TabCloseMenu);
  2055. Ext.ns('Ext.ux.grid'); /**  * @class Ext.ux.grid.TableGrid  * @extends Ext.grid.GridPanel  * A Grid which creates itself from an existing HTML table element.  * @history  * 2007-03-01 Original version by Nige "Animal" White  * 2007-03-10 jvs Slightly refactored to reuse existing classes * @constructor  * @param {String/HTMLElement/Ext.Element} table The table element from which this grid will be created -  * The table MUST have some type of size defined for the grid to fill. The container will be  * automatically set to position relative if it isn't already.  * @param {Object} config A config object that sets properties on this grid and has two additional (optional)  * properties: fields and columns which allow for customizing data fields and columns for this grid.  */ Ext.ux.grid.TableGrid = function(table, config){     config = config ||     {};     Ext.apply(this, config);     var cf = config.fields || [], ch = config.columns || [];     table = Ext.get(table);          var ct = table.insertSibling();          var fields = [], cols = [];     var headers = table.query("thead th");     for (var i = 0, h; h = headers[i]; i++) {         var text = h.innerHTML;         var name = 'tcol-' + i;                  fields.push(Ext.applyIf(cf[i] ||         {}, {             name: name,             mapping: 'td:nth(' + (i + 1) + ')/@innerHTML'         }));                  cols.push(Ext.applyIf(ch[i] ||         {}, {             'header': text,             'dataIndex': name,             'width': h.offsetWidth,             'tooltip': h.title,             'sortable': true         }));     }          var ds = new Ext.data.Store({         reader: new Ext.data.XmlReader({             record: 'tbody tr'         }, fields)     });          ds.loadData(table.dom);          var cm = new Ext.grid.ColumnModel(cols);          if (config.width || config.height) {         ct.setSize(config.width || 'auto', config.height || 'auto');     }     else {         ct.setWidth(table.getWidth());     }          if (config.remove !== false) {         table.remove();     }          Ext.applyIf(this, {         'ds': ds,         'cm': cm,         'sm': new Ext.grid.RowSelectionModel(),         autoHeight: true,         autoWidth: false     });     Ext.ux.grid.TableGrid.superclass.constructor.call(this, ct, {}); }; Ext.extend(Ext.ux.grid.TableGrid, Ext.grid.GridPanel); //backwards compat Ext.grid.TableGrid = Ext.ux.grid.TableGrid; Ext.ux.TabScrollerMenu =  Ext.extend(Object, { pageSize       : 10, maxText        : 15, menuPrefixText : 'Items', constructor    : function(config) { config = config || {}; Ext.apply(this, config); }, init : function(tabPanel) { Ext.apply(tabPanel, this.tabPanelMethods); tabPanel.tabScrollerMenu = this; var thisRef = this; tabPanel.on({ render : { scope  : tabPanel, single : true, fn     : function() {  var newFn = tabPanel.createScrollers.createSequence(thisRef.createPanelsMenu, this); tabPanel.createScrollers = newFn; } } }); }, // private && sequeneced createPanelsMenu : function() { var h = this.stripWrap.dom.offsetHeight; //move the right menu item to the left 18px var rtScrBtn = this.header.dom.firstChild; Ext.fly(rtScrBtn).applyStyles({ right : '18px' }); var stripWrap = Ext.get(this.strip.dom.parentNode); stripWrap.applyStyles({  'margin-right' : '36px' }); // Add the new righthand menu var scrollMenu = this.header.insertFirst({ cls:'x-tab-tabmenu-right' }); scrollMenu.setHeight(h); scrollMenu.addClassOnOver('x-tab-tabmenu-over'); scrollMenu.on('click', this.showTabsMenu, this); this.scrollLeft.show = this.scrollLeft.show.createSequence(function() { scrollMenu.show();     }); this.scrollLeft.hide = this.scrollLeft.hide.createSequence(function() { scrollMenu.hide(); }); }, // public getPageSize : function() { return this.pageSize; }, // public setPageSize : function(pageSize) { this.pageSize = pageSize; }, // public getMaxText : function() { return this.maxText; }, // public setMaxText : function(t) { this.maxText = t; }, getMenuPrefixText : function() { return this.menuPrefixText; }, setMenuPrefixText : function(t) { this.menuPrefixText = t; }, // private && applied to the tab panel itself. tabPanelMethods : { // all execute within the scope of the tab panel // private showTabsMenu : function(e) { if (! this.tabsMenu) { this.tabsMenu =  new Ext.menu.Menu(); this.on('beforedestroy', this.tabsMenu.destroy, this.tabsMenu); } this.tabsMenu.removeAll(); this.generateTabMenuItems(); var target = Ext.get(e.getTarget()); var xy     = target.getXY(); //Y param + 24 pixels xy[1] += 24; this.tabsMenu.showAt(xy); }, // private generateTabMenuItems : function() { var curActive  = this.getActiveTab(); var totalItems = this.items.getCount(); var pageSize   = this.tabScrollerMenu.getPageSize(); if (totalItems > pageSize)  { var numSubMenus = Math.floor(totalItems / pageSize); var remainder   = totalItems % pageSize; // Loop through all of the items and create submenus in chunks of 10 for (var i = 0 ; i < numSubMenus; i++) { var curPage = (i + 1) * pageSize; var menuItems = []; for (var x = 0; x < pageSize; x++) { index = x + curPage - pageSize; var item = this.items.get(index); menuItems.push(this.autoGenMenuItem(item)); } this.tabsMenu.add({ text : this.tabScrollerMenu.getMenuPrefixText() + ' '  + (curPage - pageSize + 1) + ' - ' + curPage, menu : menuItems }); } // remaining items if (remainder > 0) { var start = numSubMenus * pageSize; menuItems = []; for (var i = start ; i < totalItems; i ++ ) { var item = this.items.get(i); menuItems.push(this.autoGenMenuItem(item)); } this.tabsMenu.add({ text : this.tabScrollerMenu.menuPrefixText  + ' ' + (start + 1) + ' - ' + (start + menuItems.length), menu : menuItems }); } } else { this.items.each(function(item) { if (item.id != curActive.id && ! item.hidden) { menuItems.push(this.autoGenMenuItem(item)); } }, this); } }, // private autoGenMenuItem : function(item) { var maxText = this.tabScrollerMenu.getMaxText(); var text    = Ext.util.Format.ellipsis(item.title, maxText); return { text      : text, handler   : this.showTabFromMenu, scope     : this, disabled  : item.disabled, tabToShow : item, iconCls   : item.iconCls } }, // private showTabFromMenu : function(menuItem) { this.setActiveTab(menuItem.tabToShow); } } }); Ext.ns('Ext.ux.tree'); /**  * @class Ext.ux.tree.XmlTreeLoader  * @extends Ext.tree.TreeLoader  * <p>A TreeLoader that can convert an XML document into a hierarchy of {@link Ext.tree.TreeNode}s.  * Any text value included as a text node in the XML will be added to the parent node as an attribute  * called <tt>innerText</tt>.  Also, the tag name of each XML node will be added to the tree node as  * an attribute called <tt>tagName</tt>.</p>  * <p>By default, this class expects that your source XML will provide the necessary attributes on each  * node as expected by the {@link Ext.tree.TreePanel} to display and load properly.  However, you can  * provide your own custom processing of node attributes by overriding the {@link #processNode} method  * and modifying the attributes as needed before they are used to create the associated TreeNode.</p>  * @constructor  * Creates a new XmlTreeloader.  * @param {Object} config A config object containing config properties.  */ Ext.ux.tree.XmlTreeLoader = Ext.extend(Ext.tree.TreeLoader, {     /**      * @property  XML_NODE_ELEMENT      * XML element node (value 1, read-only)      * @type Number      */     XML_NODE_ELEMENT : 1,     /**      * @property  XML_NODE_TEXT      * XML text node (value 3, read-only)      * @type Number      */     XML_NODE_TEXT : 3,     // private override     processResponse : function(response, node, callback){         var xmlData = response.responseXML;         var root = xmlData.documentElement || xmlData;         try{             node.beginUpdate();             node.appendChild(this.parseXml(root));             node.endUpdate();             if(typeof callback == "function"){                 callback(this, node);             }         }catch(e){             this.handleFailure(response);         }     },     // private     parseXml : function(node) {         var nodes = [];         Ext.each(node.childNodes, function(n){             if(n.nodeType == this.XML_NODE_ELEMENT){                 var treeNode = this.createNode(n);                 if(n.childNodes.length > 0){                     var child = this.parseXml(n);                     if(typeof child == 'string'){                         treeNode.attributes.innerText = child;                     }else{                         treeNode.appendChild(child);                     }                 }                 nodes.push(treeNode);             }             else if(n.nodeType == this.XML_NODE_TEXT){                 var text = n.nodeValue.trim();                 if(text.length > 0){                     return nodes = text;                 }             }         }, this);         return nodes;     },     // private override     createNode : function(node){         var attr = {             tagName: node.tagName         };         Ext.each(node.attributes, function(a){             attr[a.nodeName] = a.nodeValue;         });         this.processAttributes(attr);         return Ext.ux.tree.XmlTreeLoader.superclass.createNode.call(this, attr);     },     /*      * Template method intended to be overridden by subclasses that need to provide      * custom attribute processing prior to the creation of each TreeNode.  This method      * will be passed a config object containing existing TreeNode attribute name/value      * pairs which can be modified as needed directly (no need to return the object).      */     processAttributes: Ext.emptyFn }); //backwards compat Ext.ux.XmlTreeLoader = Ext.ux.tree.XmlTreeLoader;