PageRenderTime 96ms CodeModel.GetById 29ms app.highlight 54ms RepoModel.GetById 2ms app.codeStats 1ms

/hippo/src/main/webapp/ext/pkgs/pkg-toolbars-debug.js

http://hdbc.googlecode.com/
JavaScript | 1374 lines | 705 code | 94 blank | 575 comment | 131 complexity | d44e9adbaa65786f594ca1e021ac1f46 MD5 | raw file
   1/*!
   2 * Ext JS Library 3.0.0
   3 * Copyright(c) 2006-2009 Ext JS, LLC
   4 * licensing@extjs.com
   5 * http://www.extjs.com/license
   6 */
   7/**
   8 * @class Ext.layout.ToolbarLayout
   9 * @extends Ext.layout.ContainerLayout
  10 * Layout manager implicitly used by Ext.Toolbar.
  11 */
  12Ext.layout.ToolbarLayout = Ext.extend(Ext.layout.ContainerLayout, {
  13    monitorResize : true,
  14    triggerWidth : 18,
  15    lastOverflow : false,
  16
  17    noItemsMenuText : '<div class="x-toolbar-no-items">(None)</div>',
  18    // private
  19    onLayout : function(ct, target){
  20        if(!this.leftTr){
  21            target.addClass('x-toolbar-layout-ct');
  22            target.insertHtml('beforeEnd',
  23                 '<table cellspacing="0" class="x-toolbar-ct"><tbody><tr><td class="x-toolbar-left" align="left"><table cellspacing="0"><tbody><tr class="x-toolbar-left-row"></tr></tbody></table></td><td class="x-toolbar-right" align="right"><table cellspacing="0" class="x-toolbar-right-ct"><tbody><tr><td><table cellspacing="0"><tbody><tr class="x-toolbar-right-row"></tr></tbody></table></td><td><table cellspacing="0"><tbody><tr class="x-toolbar-extras-row"></tr></tbody></table></td></tr></tbody></table></td></tr></tbody></table>');
  24            this.leftTr = target.child('tr.x-toolbar-left-row', true);
  25            this.rightTr = target.child('tr.x-toolbar-right-row', true);
  26            this.extrasTr = target.child('tr.x-toolbar-extras-row', true);
  27        }
  28        var side = this.leftTr;
  29        var pos = 0;
  30
  31        var items = ct.items.items;
  32        for(var i = 0, len = items.length, c; i < len; i++, pos++) {
  33            c = items[i];
  34            if(c.isFill){
  35                side = this.rightTr;
  36                pos = -1;
  37            }else if(!c.rendered){
  38                c.render(this.insertCell(c, side, pos));
  39            }else{
  40                if(!c.xtbHidden && !this.isValidParent(c, side.childNodes[pos])){
  41                    var td = this.insertCell(c, side, pos);
  42                    td.appendChild(c.getDomPositionEl().dom);
  43                    c.container = Ext.get(td);
  44                }
  45            }
  46        }
  47        //strip extra empty cells
  48        this.cleanup(this.leftTr);
  49        this.cleanup(this.rightTr);
  50        this.cleanup(this.extrasTr);
  51        this.fitToSize(target);
  52    },
  53
  54    cleanup : function(row){
  55        var cn = row.childNodes;
  56        for(var i = cn.length-1, c; i >= 0 && (c = cn[i]); i--){
  57            if(!c.firstChild){
  58                row.removeChild(c);
  59            }
  60        }
  61    },
  62
  63    insertCell : function(c, side, pos){
  64        var td = document.createElement('td');
  65        td.className='x-toolbar-cell';
  66        side.insertBefore(td, side.childNodes[pos]||null);
  67        return td;
  68    },
  69
  70    hideItem : function(item){
  71        var h = (this.hiddens = this.hiddens || []);
  72        h.push(item);
  73        item.xtbHidden = true;
  74        item.xtbWidth = item.getDomPositionEl().dom.parentNode.offsetWidth;
  75        item.hide();
  76    },
  77
  78    unhideItem : function(item){
  79        item.show();
  80        item.xtbHidden = false;
  81        this.hiddens.remove(item);
  82        if(this.hiddens.length < 1){
  83            delete this.hiddens;
  84        }
  85    },
  86
  87    getItemWidth : function(c){
  88        return c.hidden ? (c.xtbWidth || 0) : c.getDomPositionEl().dom.parentNode.offsetWidth;
  89    },
  90
  91    fitToSize : function(t){
  92        if(this.container.enableOverflow === false){
  93            return;
  94        }
  95        var w = t.dom.clientWidth;
  96        var lw = this.lastWidth || 0;
  97        this.lastWidth = w;
  98        var iw = t.dom.firstChild.offsetWidth;
  99
 100        var clipWidth = w - this.triggerWidth;
 101        var hideIndex = -1;
 102
 103        if(iw > w || (this.hiddens && w >= lw)){
 104            var i, items = this.container.items.items, len = items.length, c;
 105            var loopWidth = 0;
 106            for(i = 0; i < len; i++) {
 107                c = items[i];
 108                if(!c.isFill){
 109                    loopWidth += this.getItemWidth(c);
 110                    if(loopWidth > clipWidth){
 111                        if(!c.xtbHidden){
 112                            this.hideItem(c);
 113                        }
 114                    }else{
 115                        if(c.xtbHidden){
 116                            this.unhideItem(c);
 117                        }
 118                    }
 119                }
 120            }
 121        }
 122        if(this.hiddens){
 123            this.initMore();
 124            if(!this.lastOverflow){
 125                this.container.fireEvent('overflowchange', this.container, true);
 126                this.lastOverflow = true;
 127            }
 128        }else if(this.more){
 129            this.clearMenu();
 130            this.more.destroy();
 131            delete this.more;
 132            if(this.lastOverflow){
 133                this.container.fireEvent('overflowchange', this.container, false);
 134                this.lastOverflow = false;
 135            }
 136        }
 137    },
 138
 139    createMenuConfig : function(c, hideOnClick){
 140        var cfg = Ext.apply({}, c.initialConfig),
 141            group = c.toggleGroup;
 142
 143        Ext.apply(cfg, {
 144            text: c.overflowText || c.text,
 145            iconCls: c.iconCls,
 146            icon: c.icon,
 147            itemId: c.itemId,
 148            disabled: c.disabled,
 149            handler: c.handler,
 150            scope: c.scope,
 151            menu: c.menu,
 152            hideOnClick: hideOnClick
 153        });
 154        if(group || c.enableToggle){
 155            Ext.apply(cfg, {
 156                group: group,
 157                checked: c.pressed,
 158                listeners: {
 159                    checkchange: function(item, checked){
 160                        c.toggle(checked);
 161                    }
 162                }
 163            });
 164        }
 165        delete cfg.xtype;
 166        delete cfg.id;
 167        return cfg;
 168    },
 169
 170    // private
 171    addComponentToMenu : function(m, c){
 172        if(c instanceof Ext.Toolbar.Separator){
 173            m.add('-');
 174        }else if(Ext.isFunction(c.isXType)){
 175            if(c.isXType('splitbutton')){
 176                m.add(this.createMenuConfig(c, true));
 177            }else if(c.isXType('button')){
 178                m.add(this.createMenuConfig(c, !c.menu));
 179            }else if(c.isXType('buttongroup')){
 180                c.items.each(function(item){
 181                     this.addComponentToMenu(m, item);
 182                }, this);
 183            }
 184        }
 185    },
 186
 187    clearMenu : function(){
 188        var m = this.moreMenu;
 189        if(m && m.items){
 190            this.moreMenu.items.each(function(item){
 191                delete item.menu;
 192            });
 193        }
 194    },
 195
 196    // private
 197    beforeMoreShow : function(m){
 198        var h = this.container.items.items,
 199            len = h.length,
 200            c,
 201            prev,
 202            needsSep = function(group, item){
 203                return group.isXType('buttongroup') && !(item instanceof Ext.Toolbar.Separator);
 204            };
 205
 206        this.clearMenu();
 207        m.removeAll();
 208        for(var i = 0; i < len; i++){
 209            c = h[i];
 210            if(c.xtbHidden){
 211                if(prev && (needsSep(c, prev) || needsSep(prev, c))){
 212                    m.add('-');
 213                }
 214                this.addComponentToMenu(m, c);
 215                prev = c;
 216            }
 217        }
 218        // put something so the menu isn't empty
 219        // if no compatible items found
 220        if(m.items.length < 1){
 221            m.add(this.noItemsMenuText);
 222        }
 223    },
 224
 225    initMore : function(){
 226        if(!this.more){
 227            this.moreMenu = new Ext.menu.Menu({
 228                listeners: {
 229                    beforeshow: this.beforeMoreShow,
 230                    scope: this
 231                }
 232            });
 233            this.more = new Ext.Button({
 234                iconCls: 'x-toolbar-more-icon',
 235                cls: 'x-toolbar-more',
 236                menu: this.moreMenu
 237            });
 238            var td = this.insertCell(this.more, this.extrasTr, 100);
 239            this.more.render(td);
 240        }
 241    },
 242
 243    destroy : function(){
 244        Ext.destroy(this.more, this.moreMenu);
 245        Ext.layout.ToolbarLayout.superclass.destroy.call(this);
 246    }
 247    /**
 248     * @property activeItem
 249     * @hide
 250     */
 251});
 252
 253Ext.Container.LAYOUTS.toolbar = Ext.layout.ToolbarLayout;
 254
 255/**
 256 * @class Ext.Toolbar
 257 * @extends Ext.Container
 258 * <p>Basic Toolbar class. Although the <tt>{@link Ext.Container#defaultType defaultType}</tt> for Toolbar
 259 * is <tt>{@link Ext.Button button}</tt>, Toolbar elements (child items for the Toolbar container) may
 260 * be virtually any type of Component. Toolbar elements can be created explicitly via their constructors,
 261 * or implicitly via their xtypes, and can be <tt>{@link #add}</tt>ed dynamically.</p>
 262 * <p>Some items have shortcut strings for creation:</p>
 263 * <pre>
 264<u>Shortcut</u>  <u>xtype</u>          <u>Class</u>                  <u>Description</u>
 265'->'      'tbfill'       {@link Ext.Toolbar.Fill}       begin using the right-justified button container
 266'-'       'tbseparator'  {@link Ext.Toolbar.Separator}  add a vertical separator bar between toolbar items
 267' '       'tbspacer'     {@link Ext.Toolbar.Spacer}     add horiztonal space between elements
 268 * </pre>
 269 *
 270 * Example usage of various elements:
 271 * <pre><code>
 272var tb = new Ext.Toolbar({
 273    renderTo: document.body,
 274    width: 600,
 275    height: 100,
 276    items: [
 277        {
 278            // xtype: 'button', // default for Toolbars, same as 'tbbutton'
 279            text: 'Button'
 280        },
 281        {
 282            xtype: 'splitbutton', // same as 'tbsplitbutton'
 283            text: 'Split Button'
 284        },
 285        // begin using the right-justified button container
 286        '->', // same as {xtype: 'tbfill'}, // Ext.Toolbar.Fill
 287        {
 288            xtype: 'textfield',
 289            name: 'field1',
 290            emptyText: 'enter search term'
 291        },
 292        // add a vertical separator bar between toolbar items
 293        '-', // same as {xtype: 'tbseparator'} to create Ext.Toolbar.Separator
 294        'text 1', // same as {xtype: 'tbtext', text: 'text1'} to create Ext.Toolbar.TextItem
 295        {xtype: 'tbspacer'},// same as ' ' to create Ext.Toolbar.Spacer
 296        'text 2',
 297        {xtype: 'tbspacer', width: 50}, // add a 50px space
 298        'text 3'
 299    ]
 300});
 301 * </code></pre>
 302 * Example adding a ComboBox within a menu of a button:
 303 * <pre><code>
 304// ComboBox creation
 305var combo = new Ext.form.ComboBox({
 306    store: new Ext.data.ArrayStore({
 307        autoDestroy: true,
 308        fields: ['initials', 'fullname'],
 309        data : [
 310            ['FF', 'Fred Flintstone'],
 311            ['BR', 'Barney Rubble']
 312        ]
 313    }),
 314    displayField: 'fullname',
 315    typeAhead: true,
 316    mode: 'local',
 317    forceSelection: true,
 318    triggerAction: 'all',
 319    emptyText: 'Select a name...',
 320    selectOnFocus: true,
 321    width: 135,
 322    getListParent: function() {
 323        return this.el.up('.x-menu');
 324    },
 325    iconCls: 'no-icon' //use iconCls if placing within menu to shift to right side of menu
 326});
 327
 328// put ComboBox in a Menu
 329var menu = new Ext.menu.Menu({
 330    id: 'mainMenu',
 331    items: [
 332        combo // A Field in a Menu
 333    ]
 334});
 335
 336// add a Button with the menu
 337tb.add({
 338        text:'Button w/ Menu',
 339        menu: menu  // assign menu by instance
 340    });
 341tb.doLayout();
 342 * </code></pre>
 343 * @constructor
 344 * Creates a new Toolbar
 345 * @param {Object/Array} config A config object or an array of buttons to <tt>{@link #add}</tt>
 346 * @xtype toolbar
 347 */
 348Ext.Toolbar = function(config){
 349    if(Ext.isArray(config)){
 350        config = {items: config, layout: 'toolbar'};
 351    } else {
 352        config = Ext.apply({
 353            layout: 'toolbar'
 354        }, config);
 355        if(config.buttons) {
 356            config.items = config.buttons;
 357        }
 358    }
 359    Ext.Toolbar.superclass.constructor.call(this, config);
 360};
 361
 362(function(){
 363
 364var T = Ext.Toolbar;
 365
 366Ext.extend(T, Ext.Container, {
 367
 368    defaultType: 'button',
 369
 370    trackMenus : true,
 371    internalDefaults: {removeMode: 'container', hideParent: true},
 372    toolbarCls: 'x-toolbar',
 373
 374    initComponent : function(){
 375        T.superclass.initComponent.call(this);
 376
 377        /**
 378         * @event overflowchange
 379         * Fires after the overflow state has changed.
 380         * @param {Object} c The Container
 381         * @param {Boolean} lastOverflow overflow state
 382         */
 383        this.addEvents('overflowchange');
 384    },
 385
 386    // private
 387    onRender : function(ct, position){
 388        if(!this.el){
 389            if(!this.autoCreate){
 390                this.autoCreate = {
 391                    cls: this.toolbarCls + ' x-small-editor'
 392                };
 393            }
 394            this.el = ct.createChild(Ext.apply({ id: this.id },this.autoCreate), position);
 395        }
 396    },
 397
 398    /**
 399     * Adds element(s) to the toolbar -- this function takes a variable number of
 400     * arguments of mixed type and adds them to the toolbar.
 401     * @param {Mixed} arg1 The following types of arguments are all valid:<br />
 402     * <ul>
 403     * <li>{@link Ext.Button} config: A valid button config object (equivalent to {@link #addButton})</li>
 404     * <li>HtmlElement: Any standard HTML element (equivalent to {@link #addElement})</li>
 405     * <li>Field: Any form field (equivalent to {@link #addField})</li>
 406     * <li>Item: Any subclass of {@link Ext.Toolbar.Item} (equivalent to {@link #addItem})</li>
 407     * <li>String: Any generic string (gets wrapped in a {@link Ext.Toolbar.TextItem}, equivalent to {@link #addText}).
 408     * Note that there are a few special strings that are treated differently as explained next.</li>
 409     * <li>'-': Creates a separator element (equivalent to {@link #addSeparator})</li>
 410     * <li>' ': Creates a spacer element (equivalent to {@link #addSpacer})</li>
 411     * <li>'->': Creates a fill element (equivalent to {@link #addFill})</li>
 412     * </ul>
 413     * @param {Mixed} arg2
 414     * @param {Mixed} etc.
 415     * @method add
 416     */
 417
 418    // private
 419    lookupComponent : function(c){
 420        if(Ext.isString(c)){
 421            if(c == '-'){
 422                c = new T.Separator();
 423            }else if(c == ' '){
 424                c = new T.Spacer();
 425            }else if(c == '->'){
 426                c = new T.Fill();
 427            }else{
 428                c = new T.TextItem(c);
 429            }
 430            this.applyDefaults(c);
 431        }else{
 432            if(c.isFormField || c.render){ // some kind of form field, some kind of Toolbar.Item
 433                c = this.constructItem(c);
 434            }else if(c.tag){ // DomHelper spec
 435                c = new T.Item({autoEl: c});
 436            }else if(c.tagName){ // element
 437                c = new T.Item({el:c});
 438            }else if(Ext.isObject(c)){ // must be button config?
 439                c = c.xtype ? this.constructItem(c) : this.constructButton(c);
 440            }
 441        }
 442        return c;
 443    },
 444
 445    // private
 446    applyDefaults : function(c){
 447        if(!Ext.isString(c)){
 448            c = Ext.Toolbar.superclass.applyDefaults.call(this, c);
 449            var d = this.internalDefaults;
 450            if(c.events){
 451                Ext.applyIf(c.initialConfig, d);
 452                Ext.apply(c, d);
 453            }else{
 454                Ext.applyIf(c, d);
 455            }
 456        }
 457        return c;
 458    },
 459
 460    // private
 461    constructItem : function(item, type){
 462        return Ext.create(item, type || this.defaultType);
 463    },
 464
 465    /**
 466     * Adds a separator
 467     * @return {Ext.Toolbar.Item} The separator {@link Ext.Toolbar.Item item}
 468     */
 469    addSeparator : function(){
 470        return this.add(new T.Separator());
 471    },
 472
 473    /**
 474     * Adds a spacer element
 475     * @return {Ext.Toolbar.Spacer} The spacer item
 476     */
 477    addSpacer : function(){
 478        return this.add(new T.Spacer());
 479    },
 480
 481    /**
 482     * Forces subsequent additions into the float:right toolbar
 483     */
 484    addFill : function(){
 485        this.add(new T.Fill());
 486    },
 487
 488    /**
 489     * Adds any standard HTML element to the toolbar
 490     * @param {Mixed} el The element or id of the element to add
 491     * @return {Ext.Toolbar.Item} The element's item
 492     */
 493    addElement : function(el){
 494        return this.addItem(new T.Item({el:el}));
 495    },
 496
 497    /**
 498     * Adds any Toolbar.Item or subclass
 499     * @param {Ext.Toolbar.Item} item
 500     * @return {Ext.Toolbar.Item} The item
 501     */
 502    addItem : function(item){
 503        return Ext.Toolbar.superclass.add.apply(this, arguments);
 504    },
 505
 506    /**
 507     * Adds a button (or buttons). See {@link Ext.Button} for more info on the config.
 508     * @param {Object/Array} config A button config or array of configs
 509     * @return {Ext.Button/Array}
 510     */
 511    addButton : function(config){
 512        if(Ext.isArray(config)){
 513            var buttons = [];
 514            for(var i = 0, len = config.length; i < len; i++) {
 515                buttons.push(this.addButton(config[i]));
 516            }
 517            return buttons;
 518        }
 519        return this.add(this.constructButton(config));
 520    },
 521
 522    /**
 523     * Adds text to the toolbar
 524     * @param {String} text The text to add
 525     * @return {Ext.Toolbar.Item} The element's item
 526     */
 527    addText : function(text){
 528        return this.addItem(new T.TextItem(text));
 529    },
 530
 531    /**
 532     * Adds a new element to the toolbar from the passed {@link Ext.DomHelper} config
 533     * @param {Object} config
 534     * @return {Ext.Toolbar.Item} The element's item
 535     */
 536    addDom : function(config){
 537        return this.add(new T.Item({autoEl: config}));
 538    },
 539
 540    /**
 541     * Adds a dynamically rendered Ext.form field (TextField, ComboBox, etc). Note: the field should not have
 542     * been rendered yet. For a field that has already been rendered, use {@link #addElement}.
 543     * @param {Ext.form.Field} field
 544     * @return {Ext.Toolbar.Item}
 545     */
 546    addField : function(field){
 547        return this.add(field);
 548    },
 549
 550    /**
 551     * Inserts any {@link Ext.Toolbar.Item}/{@link Ext.Button} at the specified index.
 552     * @param {Number} index The index where the item is to be inserted
 553     * @param {Object/Ext.Toolbar.Item/Ext.Button/Array} item The button, or button config object to be
 554     * inserted, or an array of buttons/configs.
 555     * @return {Ext.Button/Item}
 556     */
 557    insertButton : function(index, item){
 558        if(Ext.isArray(item)){
 559            var buttons = [];
 560            for(var i = 0, len = item.length; i < len; i++) {
 561               buttons.push(this.insertButton(index + i, item[i]));
 562            }
 563            return buttons;
 564        }
 565        return Ext.Toolbar.superclass.insert.call(this, index, item);
 566    },
 567
 568    // private
 569    initMenuTracking : function(item){
 570        if(this.trackMenus && item.menu){
 571            this.mon(item, {
 572                'menutriggerover' : this.onButtonTriggerOver,
 573                'menushow' : this.onButtonMenuShow,
 574                'menuhide' : this.onButtonMenuHide,
 575                scope: this
 576            });
 577        }
 578    },
 579
 580    // private
 581    constructButton : function(item){
 582        var b = item.events ? item : this.constructItem(item, item.split ? 'splitbutton' : this.defaultType);
 583        this.initMenuTracking(b);
 584        return b;
 585    },
 586
 587    // private
 588    onDisable : function(){
 589        this.items.each(function(item){
 590             if(item.disable){
 591                 item.disable();
 592             }
 593        });
 594    },
 595
 596    // private
 597    onEnable : function(){
 598        this.items.each(function(item){
 599             if(item.enable){
 600                 item.enable();
 601             }
 602        });
 603    },
 604
 605    // private
 606    onButtonTriggerOver : function(btn){
 607        if(this.activeMenuBtn && this.activeMenuBtn != btn){
 608            this.activeMenuBtn.hideMenu();
 609            btn.showMenu();
 610            this.activeMenuBtn = btn;
 611        }
 612    },
 613
 614    // private
 615    onButtonMenuShow : function(btn){
 616        this.activeMenuBtn = btn;
 617    },
 618
 619    // private
 620    onButtonMenuHide : function(btn){
 621        delete this.activeMenuBtn;
 622    }
 623});
 624Ext.reg('toolbar', Ext.Toolbar);
 625
 626/**
 627 * @class Ext.Toolbar.Item
 628 * @extends Ext.BoxComponent
 629 * The base class that other non-interacting Toolbar Item classes should extend in order to
 630 * get some basic common toolbar item functionality.
 631 * @constructor
 632 * Creates a new Item
 633 * @param {HTMLElement} el
 634 * @xtype tbitem
 635 */
 636T.Item = Ext.extend(Ext.BoxComponent, {
 637    hideParent: true, //  Hiding a Toolbar.Item hides its containing TD
 638    enable:Ext.emptyFn,
 639    disable:Ext.emptyFn,
 640    focus:Ext.emptyFn
 641    /**
 642     * @cfg {String} overflowText Text to be used for the menu if the item is overflowed.
 643     */
 644});
 645Ext.reg('tbitem', T.Item);
 646
 647/**
 648 * @class Ext.Toolbar.Separator
 649 * @extends Ext.Toolbar.Item
 650 * A simple class that adds a vertical separator bar between toolbar items
 651 * (css class:<tt>'xtb-sep'</tt>). Example usage:
 652 * <pre><code>
 653new Ext.Panel({
 654    tbar : [
 655        'Item 1',
 656        {xtype: 'tbseparator'}, // or '-'
 657        'Item 2'
 658    ]
 659});
 660</code></pre>
 661 * @constructor
 662 * Creates a new Separator
 663 * @xtype tbseparator
 664 */
 665T.Separator = Ext.extend(T.Item, {
 666    onRender : function(ct, position){
 667        this.el = ct.createChild({tag:'span', cls:'xtb-sep'}, position);
 668    }
 669});
 670Ext.reg('tbseparator', T.Separator);
 671
 672/**
 673 * @class Ext.Toolbar.Spacer
 674 * @extends Ext.Toolbar.Item
 675 * A simple element that adds extra horizontal space between items in a toolbar.
 676 * By default a 2px wide space is added via css specification:<pre><code>
 677.x-toolbar .xtb-spacer {
 678    width:2px;
 679}
 680 * </code></pre>
 681 * <p>Example usage:</p>
 682 * <pre><code>
 683new Ext.Panel({
 684    tbar : [
 685        'Item 1',
 686        {xtype: 'tbspacer'}, // or ' '
 687        'Item 2',
 688        // space width is also configurable via javascript
 689        {xtype: 'tbspacer', width: 50}, // add a 50px space
 690        'Item 3'
 691    ]
 692});
 693</code></pre>
 694 * @constructor
 695 * Creates a new Spacer
 696 * @xtype tbspacer
 697 */
 698T.Spacer = Ext.extend(T.Item, {
 699    /**
 700     * @cfg {Number} width
 701     * The width of the spacer in pixels (defaults to 2px via css style <tt>.x-toolbar .xtb-spacer</tt>).
 702     */
 703
 704    onRender : function(ct, position){
 705        this.el = ct.createChild({tag:'div', cls:'xtb-spacer', style: this.width?'width:'+this.width+'px':''}, position);
 706    }
 707});
 708Ext.reg('tbspacer', T.Spacer);
 709
 710/**
 711 * @class Ext.Toolbar.Fill
 712 * @extends Ext.Toolbar.Spacer
 713 * A non-rendering placeholder item which instructs the Toolbar's Layout to begin using
 714 * the right-justified button container.
 715 * <pre><code>
 716new Ext.Panel({
 717    tbar : [
 718        'Item 1',
 719        {xtype: 'tbfill'}, // or '->'
 720        'Item 2'
 721    ]
 722});
 723</code></pre>
 724 * @constructor
 725 * Creates a new Fill
 726 * @xtype tbfill
 727 */
 728T.Fill = Ext.extend(T.Item, {
 729    // private
 730    render : Ext.emptyFn,
 731    isFill : true
 732});
 733Ext.reg('tbfill', T.Fill);
 734
 735/**
 736 * @class Ext.Toolbar.TextItem
 737 * @extends Ext.Toolbar.Item
 738 * A simple class that renders text directly into a toolbar
 739 * (with css class:<tt>'xtb-text'</tt>). Example usage:
 740 * <pre><code>
 741new Ext.Panel({
 742    tbar : [
 743        {xtype: 'tbtext', text: 'Item 1'} // or simply 'Item 1'
 744    ]
 745});
 746</code></pre>
 747 * @constructor
 748 * Creates a new TextItem
 749 * @param {String/Object} text A text string, or a config object containing a <tt>text</tt> property
 750 * @xtype tbtext
 751 */
 752T.TextItem = Ext.extend(T.Item, {
 753    constructor: function(config){
 754        if (Ext.isString(config)) {
 755            config = { autoEl: {cls: 'xtb-text', html: config }};
 756        } else {
 757            config.autoEl = {cls: 'xtb-text', html: config.text || ''};
 758        }
 759        T.TextItem.superclass.constructor.call(this, config);
 760    },
 761    /**
 762     * Updates this item's text, setting the text to be used as innerHTML.
 763     * @param {String} t The text to display (html accepted).
 764     */
 765    setText : function(t) {
 766        if (this.rendered) {
 767            this.el.dom.innerHTML = t;
 768        } else {
 769            this.autoEl.html = t;
 770        }
 771    }
 772});
 773Ext.reg('tbtext', T.TextItem);
 774
 775// backwards compat
 776T.Button = Ext.extend(Ext.Button, {});
 777T.SplitButton = Ext.extend(Ext.SplitButton, {});
 778Ext.reg('tbbutton', T.Button);
 779Ext.reg('tbsplit', T.SplitButton);
 780
 781})();
 782/**
 783 * @class Ext.ButtonGroup
 784 * @extends Ext.Panel
 785 * Container for a group of buttons. Example usage:
 786 * <pre><code>
 787var p = new Ext.Panel({
 788    title: 'Panel with Button Group',
 789    width: 300,
 790    height:200,
 791    renderTo: document.body,
 792    html: 'whatever',
 793    tbar: [{
 794        xtype: 'buttongroup',
 795        {@link #columns}: 3,
 796        title: 'Clipboard',
 797        items: [{
 798            text: 'Paste',
 799            scale: 'large',
 800            rowspan: 3, iconCls: 'add',
 801            iconAlign: 'top',
 802            cls: 'x-btn-as-arrow'
 803        },{
 804            xtype:'splitbutton',
 805            text: 'Menu Button',
 806            scale: 'large',
 807            rowspan: 3,
 808            iconCls: 'add',
 809            iconAlign: 'top',
 810            arrowAlign:'bottom',
 811            menu: [{text: 'Menu Item 1'}]
 812        },{
 813            xtype:'splitbutton', text: 'Cut', iconCls: 'add16', menu: [{text: 'Cut Menu Item'}]
 814        },{
 815            text: 'Copy', iconCls: 'add16'
 816        },{
 817            text: 'Format', iconCls: 'add16'
 818        }]
 819    }]
 820});
 821 * </code></pre>
 822 * @xtype buttongroup
 823 */
 824Ext.ButtonGroup = Ext.extend(Ext.Panel, {
 825    /**
 826     * @cfg {Number} columns The <tt>columns</tt> configuration property passed to the
 827     * {@link #layout configured layout manager}. See {@link Ext.layout.TableLayout#columns}.
 828     */
 829    /**
 830     * @cfg {String} baseCls  Defaults to <tt>'x-btn-group'</tt>.  See {@link Ext.Panel#baseCls}.
 831     */
 832    baseCls: 'x-btn-group',
 833    /**
 834     * @cfg {String} layout  Defaults to <tt>'table'</tt>.  See {@link Ext.Container#layout}.
 835     */
 836    layout:'table',
 837    defaultType: 'button',
 838    /**
 839     * @cfg {Boolean} frame  Defaults to <tt>true</tt>.  See {@link Ext.Panel#frame}.
 840     */
 841    frame: true,
 842    internalDefaults: {removeMode: 'container', hideParent: true},
 843
 844    initComponent : function(){
 845        this.layoutConfig = this.layoutConfig || {};
 846        Ext.applyIf(this.layoutConfig, {
 847            columns : this.columns
 848        });
 849        if(!this.title){
 850            this.addClass('x-btn-group-notitle');
 851        }
 852        this.on('afterlayout', this.onAfterLayout, this);
 853        Ext.ButtonGroup.superclass.initComponent.call(this);
 854    },
 855
 856    applyDefaults : function(c){
 857        c = Ext.ButtonGroup.superclass.applyDefaults.call(this, c);
 858        var d = this.internalDefaults;
 859        if(c.events){
 860            Ext.applyIf(c.initialConfig, d);
 861            Ext.apply(c, d);
 862        }else{
 863            Ext.applyIf(c, d);
 864        }
 865        return c;
 866    },
 867
 868    onAfterLayout : function(){
 869        var bodyWidth = this.body.getFrameWidth('lr') + this.body.dom.firstChild.offsetWidth;
 870        this.body.setWidth(bodyWidth);
 871        this.el.setWidth(bodyWidth + this.getFrameWidth());
 872    }
 873    /**
 874     * @cfg {Array} tools  @hide
 875     */
 876});
 877
 878Ext.reg('buttongroup', Ext.ButtonGroup);
 879/**
 880 * @class Ext.PagingToolbar
 881 * @extends Ext.Toolbar
 882 * <p>As the amount of records increases, the time required for the browser to render
 883 * them increases. Paging is used to reduce the amount of data exchanged with the client.
 884 * Note: if there are more records/rows than can be viewed in the available screen area, vertical
 885 * scrollbars will be added.</p>
 886 * <p>Paging is typically handled on the server side (see exception below). The client sends
 887 * parameters to the server side, which the server needs to interpret and then respond with the
 888 * approprate data.</p>
 889 * <p><b>Ext.PagingToolbar</b> is a specialized toolbar that is bound to a {@link Ext.data.Store}
 890 * and provides automatic paging control. This Component {@link Ext.data.Store#load load}s blocks
 891 * of data into the <tt>{@link #store}</tt> by passing {@link Ext.data.Store#paramNames paramNames} used for
 892 * paging criteria.</p>
 893 * <p>PagingToolbar is typically used as one of the Grid's toolbars:</p>
 894 * <pre><code>
 895Ext.QuickTips.init(); // to display button quicktips
 896
 897var myStore = new Ext.data.Store({
 898    ...
 899});
 900
 901var myPageSize = 25;  // server script should only send back 25 items
 902
 903var grid = new Ext.grid.GridPanel({
 904    ...
 905    store: myStore,
 906    bbar: new Ext.PagingToolbar({
 907        {@link #store}: myStore,       // grid and PagingToolbar using same store
 908        {@link #displayInfo}: true,
 909        {@link #pageSize}: myPageSize,
 910        {@link #prependButtons}: true,
 911        items: [
 912            'text 1'
 913        ]
 914    })
 915});
 916 * </code></pre>
 917 *
 918 * <p>To use paging, pass the paging requirements to the server when the store is first loaded.</p>
 919 * <pre><code>
 920store.load({
 921    params: {
 922        start: 0,          // specify params for the first page load if using paging
 923        limit: myPageSize,
 924        foo:   'bar'
 925    }
 926});
 927 * </code></pre>
 928 * <p><u>Paging with Local Data</u></p>
 929 * <p>Paging can also be accomplished with local data using extensions:</p>
 930 * <div class="mdetail-params"><ul>
 931 * <li><a href="http://extjs.com/forum/showthread.php?t=57386">Ext.ux.data.PagingStore</a></li>
 932 * <li>Paging Memory Proxy (examples/ux/PagingMemoryProxy.js)</li>
 933 * </ul></div>
 934 * @constructor
 935 * Create a new PagingToolbar
 936 * @param {Object} config The config object
 937 * @xtype paging
 938 */
 939(function() {
 940
 941var T = Ext.Toolbar;
 942
 943Ext.PagingToolbar = Ext.extend(Ext.Toolbar, {
 944    /**
 945     * @cfg {Ext.data.Store} store
 946     * The {@link Ext.data.Store} the paging toolbar should use as its data source (required).
 947     */
 948    /**
 949     * @cfg {Boolean} displayInfo
 950     * <tt>true</tt> to display the displayMsg (defaults to <tt>false</tt>)
 951     */
 952    /**
 953     * @cfg {Number} pageSize
 954     * The number of records to display per page (defaults to <tt>20</tt>)
 955     */
 956    pageSize : 20,
 957    /**
 958     * @cfg {Boolean} prependButtons
 959     * <tt>true</tt> to insert any configured <tt>items</tt> <i>before</i> the paging buttons.
 960     * Defaults to <tt>false</tt>.
 961     */
 962    /**
 963     * @cfg {String} displayMsg
 964     * The paging status message to display (defaults to <tt>'Displaying {0} - {1} of {2}'</tt>).
 965     * Note that this string is formatted using the braced numbers <tt>{0}-{2}</tt> as tokens
 966     * that are replaced by the values for start, end and total respectively. These tokens should
 967     * be preserved when overriding this string if showing those values is desired.
 968     */
 969    displayMsg : 'Displaying {0} - {1} of {2}',
 970    /**
 971     * @cfg {String} emptyMsg
 972     * The message to display when no records are found (defaults to 'No data to display')
 973     */
 974    emptyMsg : 'No data to display',
 975    /**
 976     * @cfg {String} beforePageText
 977     * The text displayed before the input item (defaults to <tt>'Page'</tt>).
 978     */
 979    beforePageText : 'Page',
 980    /**
 981     * @cfg {String} afterPageText
 982     * Customizable piece of the default paging text (defaults to <tt>'of {0}'</tt>). Note that
 983     * this string is formatted using <tt>{0}</tt> as a token that is replaced by the number of
 984     * total pages. This token should be preserved when overriding this string if showing the
 985     * total page count is desired.
 986     */
 987    afterPageText : 'of {0}',
 988    /**
 989     * @cfg {String} firstText
 990     * The quicktip text displayed for the first page button (defaults to <tt>'First Page'</tt>).
 991     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 992     */
 993    firstText : 'First Page',
 994    /**
 995     * @cfg {String} prevText
 996     * The quicktip text displayed for the previous page button (defaults to <tt>'Previous Page'</tt>).
 997     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
 998     */
 999    prevText : 'Previous Page',
1000    /**
1001     * @cfg {String} nextText
1002     * The quicktip text displayed for the next page button (defaults to <tt>'Next Page'</tt>).
1003     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
1004     */
1005    nextText : 'Next Page',
1006    /**
1007     * @cfg {String} lastText
1008     * The quicktip text displayed for the last page button (defaults to <tt>'Last Page'</tt>).
1009     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
1010     */
1011    lastText : 'Last Page',
1012    /**
1013     * @cfg {String} refreshText
1014     * The quicktip text displayed for the Refresh button (defaults to <tt>'Refresh'</tt>).
1015     * <b>Note</b>: quick tips must be initialized for the quicktip to show.
1016     */
1017    refreshText : 'Refresh',
1018
1019    /**
1020     * @deprecated
1021     * <b>The defaults for these should be set in the data store.</b>
1022     * Object mapping of parameter names used for load calls, initially set to:
1023     * <pre>{start: 'start', limit: 'limit'}</pre>
1024     */
1025
1026    /**
1027     * The number of records to display per page.  See also <tt>{@link #cursor}</tt>.
1028     * @type Number
1029     * @property pageSize
1030     */
1031
1032    /**
1033     * Indicator for the record position.  This property might be used to get the active page
1034     * number for example:<pre><code>
1035     * // t is reference to the paging toolbar instance
1036     * var activePage = Math.ceil((t.cursor + t.pageSize) / t.pageSize);
1037     * </code></pre>
1038     * @type Number
1039     * @property cursor
1040     */
1041
1042    initComponent : function(){
1043        var pagingItems = [this.first = new T.Button({
1044            tooltip: this.firstText,
1045            overflowText: this.firstText,
1046            iconCls: 'x-tbar-page-first',
1047            disabled: true,
1048            handler: this.moveFirst,
1049            scope: this
1050        }), this.prev = new T.Button({
1051            tooltip: this.prevText,
1052            overflowText: this.prevText,
1053            iconCls: 'x-tbar-page-prev',
1054            disabled: true,
1055            handler: this.movePrevious,
1056            scope: this
1057        }), '-', this.beforePageText,
1058        this.inputItem = new Ext.form.NumberField({
1059            cls: 'x-tbar-page-number',
1060            allowDecimals: false,
1061            allowNegative: false,
1062            enableKeyEvents: true,
1063            selectOnFocus: true,
1064            listeners: {
1065                scope: this,
1066                keydown: this.onPagingKeyDown,
1067                blur: this.onPagingBlur
1068            }
1069        }), this.afterTextItem = new T.TextItem({
1070            text: String.format(this.afterPageText, 1)
1071        }), '-', this.next = new T.Button({
1072            tooltip: this.nextText,
1073            overflowText: this.nextText,
1074            iconCls: 'x-tbar-page-next',
1075            disabled: true,
1076            handler: this.moveNext,
1077            scope: this
1078        }), this.last = new T.Button({
1079            tooltip: this.lastText,
1080            overflowText: this.lastText,
1081            iconCls: 'x-tbar-page-last',
1082            disabled: true,
1083            handler: this.moveLast,
1084            scope: this
1085        }), '-', this.refresh = new T.Button({
1086            tooltip: this.refreshText,
1087            overflowText: this.refreshText,
1088            iconCls: 'x-tbar-loading',
1089            handler: this.refresh,
1090            scope: this
1091        })];
1092
1093
1094        var userItems = this.items || this.buttons || [];
1095        if (this.prependButtons) {
1096            this.items = userItems.concat(pagingItems);
1097        }else{
1098            this.items = pagingItems.concat(userItems);
1099        }
1100        delete this.buttons;
1101        if(this.displayInfo){
1102            this.items.push('->');
1103            this.items.push(this.displayItem = new T.TextItem({}));
1104        }
1105        Ext.PagingToolbar.superclass.initComponent.call(this);
1106        this.addEvents(
1107            /**
1108             * @event change
1109             * Fires after the active page has been changed.
1110             * @param {Ext.PagingToolbar} this
1111             * @param {Object} pageData An object that has these properties:<ul>
1112             * <li><code>total</code> : Number <div class="sub-desc">The total number of records in the dataset as
1113             * returned by the server</div></li>
1114             * <li><code>activePage</code> : Number <div class="sub-desc">The current page number</div></li>
1115             * <li><code>pages</code> : Number <div class="sub-desc">The total number of pages (calculated from
1116             * the total number of records in the dataset as returned by the server and the current {@link #pageSize})</div></li>
1117             * </ul>
1118             */
1119            'change',
1120            /**
1121             * @event beforechange
1122             * Fires just before the active page is changed.
1123             * Return false to prevent the active page from being changed.
1124             * @param {Ext.PagingToolbar} this
1125             * @param {Object} params An object hash of the parameters which the PagingToolbar will send when
1126             * loading the required page. This will contain:<ul>
1127             * <li><code>start</code> : Number <div class="sub-desc">The starting row number for the next page of records to
1128             * be retrieved from the server</div></li>
1129             * <li><code>limit</code> : Number <div class="sub-desc">The number of records to be retrieved from the server</div></li>
1130             * </ul>
1131             * <p>(note: the names of the <b>start</b> and <b>limit</b> properties are determined
1132             * by the store's {@link Ext.data.Store#paramNames paramNames} property.)</p>
1133             * <p>Parameters may be added as required in the event handler.</p>
1134             */
1135            'beforechange'
1136        );
1137        this.on('afterlayout', this.onFirstLayout, this, {single: true});
1138        this.cursor = 0;
1139        this.bindStore(this.store);
1140    },
1141
1142    // private
1143    onFirstLayout : function(){
1144        if(this.dsLoaded){
1145            this.onLoad.apply(this, this.dsLoaded);
1146        }
1147    },
1148
1149    // private
1150    updateInfo : function(){
1151        if(this.displayItem){
1152            var count = this.store.getCount();
1153            var msg = count == 0 ?
1154                this.emptyMsg :
1155                String.format(
1156                    this.displayMsg,
1157                    this.cursor+1, this.cursor+count, this.store.getTotalCount()
1158                );
1159            this.displayItem.setText(msg);
1160        }
1161    },
1162
1163    // private
1164    onLoad : function(store, r, o){
1165        if(!this.rendered){
1166            this.dsLoaded = [store, r, o];
1167            return;
1168        }
1169        var p = this.getParams();
1170        this.cursor = (o.params && o.params[p.start]) ? o.params[p.start] : 0;
1171        var d = this.getPageData(), ap = d.activePage, ps = d.pages;
1172
1173        this.afterTextItem.setText(String.format(this.afterPageText, d.pages));
1174        this.inputItem.setValue(ap);
1175        this.first.setDisabled(ap == 1);
1176        this.prev.setDisabled(ap == 1);
1177        this.next.setDisabled(ap == ps);
1178        this.last.setDisabled(ap == ps);
1179        this.refresh.enable();
1180        this.updateInfo();
1181        this.fireEvent('change', this, d);
1182    },
1183
1184    // private
1185    getPageData : function(){
1186        var total = this.store.getTotalCount();
1187        return {
1188            total : total,
1189            activePage : Math.ceil((this.cursor+this.pageSize)/this.pageSize),
1190            pages :  total < this.pageSize ? 1 : Math.ceil(total/this.pageSize)
1191        };
1192    },
1193
1194    /**
1195     * Change the active page
1196     * @param {Integer} page The page to display
1197     */
1198    changePage : function(page){
1199        this.doLoad(((page-1) * this.pageSize).constrain(0, this.store.getTotalCount()));
1200    },
1201
1202    // private
1203    onLoadError : function(){
1204        if(!this.rendered){
1205            return;
1206        }
1207        this.refresh.enable();
1208    },
1209
1210    // private
1211    readPage : function(d){
1212        var v = this.inputItem.getValue(), pageNum;
1213        if (!v || isNaN(pageNum = parseInt(v, 10))) {
1214            this.inputItem.setValue(d.activePage);
1215            return false;
1216        }
1217        return pageNum;
1218    },
1219
1220    onPagingFocus : function(){
1221        this.inputItem.select();
1222    },
1223
1224    //private
1225    onPagingBlur : function(e){
1226        this.inputItem.setValue(this.getPageData().activePage);
1227    },
1228
1229    // private
1230    onPagingKeyDown : function(field, e){
1231        var k = e.getKey(), d = this.getPageData(), pageNum;
1232        if (k == e.RETURN) {
1233            e.stopEvent();
1234            pageNum = this.readPage(d);
1235            if(pageNum !== false){
1236                pageNum = Math.min(Math.max(1, pageNum), d.pages) - 1;
1237                this.doLoad(pageNum * this.pageSize);
1238            }
1239        }else if (k == e.HOME || k == e.END){
1240            e.stopEvent();
1241            pageNum = k == e.HOME ? 1 : d.pages;
1242            field.setValue(pageNum);
1243        }else if (k == e.UP || k == e.PAGEUP || k == e.DOWN || k == e.PAGEDOWN){
1244            e.stopEvent();
1245            if((pageNum = this.readPage(d))){
1246                var increment = e.shiftKey ? 10 : 1;
1247                if(k == e.DOWN || k == e.PAGEDOWN){
1248                    increment *= -1;
1249                }
1250                pageNum += increment;
1251                if(pageNum >= 1 & pageNum <= d.pages){
1252                    field.setValue(pageNum);
1253                }
1254            }
1255        }
1256    },
1257
1258    // private
1259    getParams : function(){
1260        //retain backwards compat, allow params on the toolbar itself, if they exist.
1261        return this.paramNames || this.store.paramNames;
1262    },
1263
1264    // private
1265    beforeLoad : function(){
1266        if(this.rendered && this.refresh){
1267            this.refresh.disable();
1268        }
1269    },
1270
1271    // private
1272    doLoad : function(start){
1273        var o = {}, pn = this.getParams();
1274        o[pn.start] = start;
1275        o[pn.limit] = this.pageSize;
1276        if(this.fireEvent('beforechange', this, o) !== false){
1277            this.store.load({params:o});
1278        }
1279    },
1280
1281    /**
1282     * Move to the first page, has the same effect as clicking the 'first' button.
1283     */
1284    moveFirst : function(){
1285        this.doLoad(0);
1286    },
1287
1288    /**
1289     * Move to the previous page, has the same effect as clicking the 'previous' button.
1290     */
1291    movePrevious : function(){
1292        this.doLoad(Math.max(0, this.cursor-this.pageSize));
1293    },
1294
1295    /**
1296     * Move to the next page, has the same effect as clicking the 'next' button.
1297     */
1298    moveNext : function(){
1299        this.doLoad(this.cursor+this.pageSize);
1300    },
1301
1302    /**
1303     * Move to the last page, has the same effect as clicking the 'last' button.
1304     */
1305    moveLast : function(){
1306        var total = this.store.getTotalCount(),
1307            extra = total % this.pageSize;
1308
1309        this.doLoad(extra ? (total - extra) : total - this.pageSize);
1310    },
1311
1312    /**
1313     * Refresh the current page, has the same effect as clicking the 'refresh' button.
1314     */
1315    refresh : function(){
1316        this.doLoad(this.cursor);
1317    },
1318
1319    /**
1320     * Binds the paging toolbar to the specified {@link Ext.data.Store}
1321     * @param {Store} store The store to bind to this toolbar
1322     * @param {Boolean} initial (Optional) true to not remove listeners
1323     */
1324    bindStore : function(store, initial){
1325        var doLoad;
1326        if(!initial && this.store){
1327            this.store.un('beforeload', this.beforeLoad, this);
1328            this.store.un('load', this.onLoad, this);
1329            this.store.un('exception', this.onLoadError, this);
1330            if(store !== this.store && this.store.autoDestroy){
1331                this.store.destroy();
1332            }
1333        }
1334        if(store){
1335            store = Ext.StoreMgr.lookup(store);
1336            store.on({
1337                scope: this,
1338                beforeload: this.beforeLoad,
1339                load: this.onLoad,
1340                exception: this.onLoadError
1341            });
1342            doLoad = store.getCount() > 0;
1343        }
1344        this.store = store;
1345        if(doLoad){
1346            this.onLoad(store, null, {});
1347        }
1348    },
1349
1350    /**
1351     * Unbinds the paging toolbar from the specified {@link Ext.data.Store} <b>(deprecated)</b>
1352     * @param {Ext.data.Store} store The data store to unbind
1353     */
1354    unbind : function(store){
1355        this.bindStore(null);
1356    },
1357
1358    /**
1359     * Binds the paging toolbar to the specified {@link Ext.data.Store} <b>(deprecated)</b>
1360     * @param {Ext.data.Store} store The data store to bind
1361     */
1362    bind : function(store){
1363        this.bindStore(store);
1364    },
1365
1366    // private
1367    onDestroy : function(){
1368        this.bindStore(null);
1369        Ext.PagingToolbar.superclass.onDestroy.call(this);
1370    }
1371});
1372
1373})();
1374Ext.reg('paging', Ext.PagingToolbar);