Upgrade to ExtJS 3.3.1 - Released 11/30/2010
[extjs.git] / src / widgets / grid / Column.js
index a253c29..81d6dea 100644 (file)
@@ -1,8 +1,8 @@
 /*!
- * Ext JS Library 3.2.0
- * Copyright(c) 2006-2010 Ext JS, Inc.
- * licensing@extjs.com
- * http://www.extjs.com/license
+ * Ext JS Library 3.3.1
+ * Copyright(c) 2006-2010 Sencha Inc.
+ * licensing@sencha.com
+ * http://www.sencha.com/license
  */
 /**
  * @class Ext.grid.Column
@@ -11,7 +11,7 @@
  * <p>While subclasses are provided to render data in different ways, this class renders a passed
  * data field unchanged and is usually used for textual columns.</p>
  */
-Ext.grid.Column = Ext.extend(Object, {
+Ext.grid.Column = Ext.extend(Ext.util.Observable, {
     /**
      * @cfg {Boolean} editable Optional. Defaults to <tt>true</tt>, enabling the configured
      * <tt>{@link #editor}</tt>.  Set to <tt>false</tt> to initially disable editing on this column.
@@ -31,7 +31,7 @@ Ext.grid.Column = Ext.extend(Object, {
     /**
      * @cfg {String} header Optional. The header text to be used as innerHTML
      * (html tags are accepted) to display in the Grid view.  <b>Note</b>: to
-     * have a clickable header with no text displayed use <tt>'&#160;'</tt>.
+     * have a clickable header with no text displayed use <tt>'&amp;#160;'</tt>.
      */
     /**
      * @cfg {Boolean} groupable Optional. If the grid is being rendered by an {@link Ext.grid.GroupingView}, this option
@@ -233,6 +233,65 @@ var grid = new Ext.grid.GridPanel({
         var ed = this.editor;
         delete this.editor;
         this.setEditor(ed);
+        this.addEvents(
+            /**
+             * @event click
+             * Fires when this Column is clicked.
+             * @param {Column} this
+             * @param {Grid} The owning GridPanel
+             * @param {Number} rowIndex
+             * @param {Ext.EventObject} e
+             */
+            'click',
+            /**
+             * @event contextmenu
+             * Fires when this Column is right clicked.
+             * @param {Column} this
+             * @param {Grid} The owning GridPanel
+             * @param {Number} rowIndex
+             * @param {Ext.EventObject} e
+             */
+            'contextmenu',
+            /**
+             * @event dblclick
+             * Fires when this Column is double clicked.
+             * @param {Column} this
+             * @param {Grid} The owning GridPanel
+             * @param {Number} rowIndex
+             * @param {Ext.EventObject} e
+             */
+            'dblclick',
+            /**
+             * @event mousedown
+             * Fires when this Column receives a mousedown event.
+             * @param {Column} this
+             * @param {Grid} The owning GridPanel
+             * @param {Number} rowIndex
+             * @param {Ext.EventObject} e
+             */
+            'mousedown'
+        );
+        Ext.grid.Column.superclass.constructor.call(this);
+    },
+
+    /**
+     * @private
+     * Process and refire events routed from the GridView's processEvent method.
+     * Returns the event handler's status to allow cancelling of GridView's bubbling process.
+     */
+    processEvent : function(name, e, grid, rowIndex, colIndex){
+        return this.fireEvent(name, this, grid, rowIndex, e);
+    },
+
+    /**
+     * @private
+     * Clean up. Remove any Editor. Remove any listeners.
+     */
+    destroy: function() {
+        if(this.setEditor){
+            this.setEditor(null);
+        }
+        this.purgeListeners();
     },
 
     /**
@@ -254,9 +313,6 @@ var grid = new Ext.grid.GridPanel({
      * @type Function
      */
     renderer : function(value){
-        if(Ext.isString(value) && value.length < 1){
-            return '&#160;';
-        }
         return value;
     },
 
@@ -318,18 +374,18 @@ var grid = new Ext.grid.GridPanel({
 Ext.grid.BooleanColumn = Ext.extend(Ext.grid.Column, {
     /**
      * @cfg {String} trueText
-     * The string returned by the renderer when the column value is not falsey (defaults to <tt>'true'</tt>).
+     * The string returned by the renderer when the column value is not falsy (defaults to <tt>'true'</tt>).
      */
     trueText: 'true',
     /**
      * @cfg {String} falseText
-     * The string returned by the renderer when the column value is falsey (but not undefined) (defaults to
+     * The string returned by the renderer when the column value is falsy (but not undefined) (defaults to
      * <tt>'false'</tt>).
      */
     falseText: 'false',
     /**
      * @cfg {String} undefinedText
-     * The string returned by the renderer when the column value is undefined (defaults to <tt>'&#160;'</tt>).
+     * The string returned by the renderer when the column value is undefined (defaults to <tt>'&amp;#160;'</tt>).
      */
     undefinedText: '&#160;',
 
@@ -411,6 +467,188 @@ Ext.grid.TemplateColumn = Ext.extend(Ext.grid.Column, {
     }
 });
 
+/**
+ * @class Ext.grid.ActionColumn
+ * @extends Ext.grid.Column
+ * <p>A Grid column type which renders an icon, or a series of icons in a grid cell, and offers a scoped click
+ * handler for each icon. Example usage:</p>
+<pre><code>
+new Ext.grid.GridPanel({
+    store: myStore,
+    columns: [
+        {
+            xtype: 'actioncolumn',
+            width: 50,
+            items: [
+                {
+                    icon   : 'sell.gif',                // Use a URL in the icon config
+                    tooltip: 'Sell stock',
+                    handler: function(grid, rowIndex, colIndex) {
+                        var rec = store.getAt(rowIndex);
+                        alert("Sell " + rec.get('company'));
+                    }
+                },
+                {
+                    getClass: function(v, meta, rec) {  // Or return a class from a function
+                        if (rec.get('change') < 0) {
+                            this.items[1].tooltip = 'Do not buy!';
+                            return 'alert-col';
+                        } else {
+                            this.items[1].tooltip = 'Buy stock';
+                            return 'buy-col';
+                        }
+                    },
+                    handler: function(grid, rowIndex, colIndex) {
+                        var rec = store.getAt(rowIndex);
+                        alert("Buy " + rec.get('company'));
+                    }
+                }
+            ]
+        }
+        //any other columns here
+    ]
+});
+</pre></code>
+ * <p>The action column can be at any index in the columns array, and a grid can have any number of
+ * action columns. </p>
+ */
+Ext.grid.ActionColumn = Ext.extend(Ext.grid.Column, {
+    /**
+     * @cfg {String} icon
+     * The URL of an image to display as the clickable element in the column. 
+     * Optional - defaults to <code>{@link Ext#BLANK_IMAGE_URL Ext.BLANK_IMAGE_URL}</code>.
+     */
+    /**
+     * @cfg {String} iconCls
+     * A CSS class to apply to the icon image. To determine the class dynamically, configure the Column with a <code>{@link #getClass}</code> function.
+     */
+    /**
+     * @cfg {Function} handler A function called when the icon is clicked.
+     * The handler is passed the following parameters:<div class="mdetail-params"><ul>
+     * <li><code>grid</code> : GridPanel<div class="sub-desc">The owning GridPanel.</div></li>
+     * <li><code>rowIndex</code> : Number<div class="sub-desc">The row index clicked on.</div></li>
+     * <li><code>colIndex</code> : Number<div class="sub-desc">The column index clicked on.</div></li>
+     * <li><code>item</code> : Object<div class="sub-desc">The clicked item (or this Column if multiple 
+     * {@link #items} were not configured).</div></li>
+     * <li><code>e</code> : Event<div class="sub-desc">The click event.</div></li>
+     * </ul></div>
+     */
+    /**
+     * @cfg {Object} scope The scope (<tt><b>this</b></tt> reference) in which the <code>{@link #handler}</code>
+     * and <code>{@link #getClass}</code> fuctions are executed. Defaults to this Column.
+     */
+    /**
+     * @cfg {String} tooltip A tooltip message to be displayed on hover. {@link Ext.QuickTips#init Ext.QuickTips} must have 
+     * been initialized.
+     */
+    /**
+     * @cfg {Boolean} stopSelection Defaults to <code>true</code>. Prevent grid <i>row</i> selection upon mousedown.
+     */
+    /**
+     * @cfg {Function} getClass A function which returns the CSS class to apply to the icon image.
+     * The function is passed the following parameters:<div class="mdetail-params"><ul>
+     *     <li><b>v</b> : Object<p class="sub-desc">The value of the column's configured field (if any).</p></li>
+     *     <li><b>metadata</b> : Object<p class="sub-desc">An object in which you may set the following attributes:<ul>
+     *         <li><b>css</b> : String<p class="sub-desc">A CSS class name to add to the cell's TD element.</p></li>
+     *         <li><b>attr</b> : String<p class="sub-desc">An HTML attribute definition string to apply to the data container element <i>within</i> the table cell
+     *         (e.g. 'style="color:red;"').</p></li>
+     *     </ul></p></li>
+     *     <li><b>r</b> : Ext.data.Record<p class="sub-desc">The Record providing the data.</p></li>
+     *     <li><b>rowIndex</b> : Number<p class="sub-desc">The row index..</p></li>
+     *     <li><b>colIndex</b> : Number<p class="sub-desc">The column index.</p></li>
+     *     <li><b>store</b> : Ext.data.Store<p class="sub-desc">The Store which is providing the data Model.</p></li>
+     * </ul></div>
+     */
+    /**
+     * @cfg {Array} items An Array which may contain multiple icon definitions, each element of which may contain:
+     * <div class="mdetail-params"><ul>
+     * <li><code>icon</code> : String<div class="sub-desc">The url of an image to display as the clickable element 
+     * in the column.</div></li>
+     * <li><code>iconCls</code> : String<div class="sub-desc">A CSS class to apply to the icon image.
+     * To determine the class dynamically, configure the item with a <code>getClass</code> function.</div></li>
+     * <li><code>getClass</code> : Function<div class="sub-desc">A function which returns the CSS class to apply to the icon image.
+     * The function is passed the following parameters:<ul>
+     *     <li><b>v</b> : Object<p class="sub-desc">The value of the column's configured field (if any).</p></li>
+     *     <li><b>metadata</b> : Object<p class="sub-desc">An object in which you may set the following attributes:<ul>
+     *         <li><b>css</b> : String<p class="sub-desc">A CSS class name to add to the cell's TD element.</p></li>
+     *         <li><b>attr</b> : String<p class="sub-desc">An HTML attribute definition string to apply to the data container element <i>within</i> the table cell
+     *         (e.g. 'style="color:red;"').</p></li>
+     *     </ul></p></li>
+     *     <li><b>r</b> : Ext.data.Record<p class="sub-desc">The Record providing the data.</p></li>
+     *     <li><b>rowIndex</b> : Number<p class="sub-desc">The row index..</p></li>
+     *     <li><b>colIndex</b> : Number<p class="sub-desc">The column index.</p></li>
+     *     <li><b>store</b> : Ext.data.Store<p class="sub-desc">The Store which is providing the data Model.</p></li>
+     * </ul></div></li>
+     * <li><code>handler</code> : Function<div class="sub-desc">A function called when the icon is clicked.</div></li>
+     * <li><code>scope</code> : Scope<div class="sub-desc">The scope (<code><b>this</b></code> reference) in which the 
+     * <code>handler</code> and <code>getClass</code> functions are executed. Fallback defaults are this Column's
+     * configured scope, then this Column.</div></li>
+     * <li><code>tooltip</code> : String<div class="sub-desc">A tooltip message to be displayed on hover. 
+     * {@link Ext.QuickTips#init Ext.QuickTips} must have been initialized.</div></li>
+     * </ul></div>
+     */
+    header: '&#160;',
+
+    actionIdRe: /x-action-col-(\d+)/,
+    
+    /**
+     * @cfg {String} altText The alt text to use for the image element. Defaults to <tt>''</tt>.
+     */
+    altText: '',
+
+    constructor: function(cfg) {
+        var me = this,
+            items = cfg.items || (me.items = [me]),
+            l = items.length,
+            i,
+            item;
+
+        Ext.grid.ActionColumn.superclass.constructor.call(me, cfg);
+
+//      Renderer closure iterates through items creating an <img> element for each and tagging with an identifying 
+//      class name x-action-col-{n}
+        me.renderer = function(v, meta) {
+//          Allow a configured renderer to create initial value (And set the other values in the "metadata" argument!)
+            v = Ext.isFunction(cfg.renderer) ? cfg.renderer.apply(this, arguments)||'' : '';
+
+            meta.css += ' x-action-col-cell';
+            for (i = 0; i < l; i++) {
+                item = items[i];
+                v += '<img alt="' + me.altText + '" src="' + (item.icon || Ext.BLANK_IMAGE_URL) +
+                    '" class="x-action-col-icon x-action-col-' + String(i) + ' ' + (item.iconCls || '') +
+                    ' ' + (Ext.isFunction(item.getClass) ? item.getClass.apply(item.scope||this.scope||this, arguments) : '') + '"' +
+                    ((item.tooltip) ? ' ext:qtip="' + item.tooltip + '"' : '') + ' />';
+            }
+            return v;
+        };
+    },
+
+    destroy: function() {
+        delete this.items;
+        delete this.renderer;
+        return Ext.grid.ActionColumn.superclass.destroy.apply(this, arguments);
+    },
+
+    /**
+     * @private
+     * Process and refire events routed from the GridView's processEvent method.
+     * Also fires any configured click handlers. By default, cancels the mousedown event to prevent selection.
+     * Returns the event handler's status to allow cancelling of GridView's bubbling process.
+     */
+    processEvent : function(name, e, grid, rowIndex, colIndex){
+        var m = e.getTarget().className.match(this.actionIdRe),
+            item, fn;
+        if (m && (item = this.items[parseInt(m[1], 10)])) {
+            if (name == 'click') {
+                (fn = item.handler || this.handler) && fn.call(item.scope||this.scope||this, grid, rowIndex, colIndex, item, e);
+            } else if ((name == 'mousedown') && (item.stopSelection !== false)) {
+                return false;
+            }
+        }
+        return Ext.grid.ActionColumn.superclass.processEvent.apply(this, arguments);
+    }
+});
+
 /*
  * @property types
  * @type Object
@@ -431,5 +669,6 @@ Ext.grid.Column.types = {
     booleancolumn: Ext.grid.BooleanColumn,
     numbercolumn: Ext.grid.NumberColumn,
     datecolumn: Ext.grid.DateColumn,
-    templatecolumn: Ext.grid.TemplateColumn
+    templatecolumn: Ext.grid.TemplateColumn,
+    actioncolumn: Ext.grid.ActionColumn
 };
\ No newline at end of file