partkeepr

fork of partkeepr
git clone https://git.e1e0.net/partkeepr.git
Log | Files | Refs | Submodules | README | LICENSE

Ext.ux.Wizard.js (17071B)


      1 Ext.define('Ext.ux.Wizard', {
      2     extend: 'Ext.window.Window',
      3     // layout: 'Ext.ux.wizard.CardLayout',
      4     layout: 'fit',
      5     loadMaskConfig: {
      6         'default': '',
      7         'saving': 'Saving...',
      8         'checking': 'Checking...'
      9     },
     10     autoRender: true,
     11 
     12     /**
     13     * @cfg {Number} height The height of the dialog. Defaults to "400".
     14     */
     15     height: 650,
     16 
     17     /**
     18     * @cfg {Number} width The width of the dialog. Defaults to "540".
     19     */
     20     width: 800,
     21 
     22     /**
     23     * @cfg {Boolean} closable Wether the dialog is closable. Defaults to "true".
     24     * This property will be changed by the "switchDialogState"-method, which will
     25     * enable/disable controls based on the passed argument. Thus, this config property
     26     * serves two purposes: Tell the init config to render a "close"-tool, and create a
     27     * "beforeclose"-listener which will either return true or false, indicating if the
     28     * dialog may be closed.
     29     */
     30     closable: true,
     31 
     32     /**
     33     * @cfg {Boolean} resizable Wether the dialog is resizable. Defaults to "false".
     34     */
     35     resizable: false,
     36 
     37     /**
     38     * @cfg {Boolean} resizable Wether the dialog is modal. Defaults to "true".
     39     */
     40     modal: true,
     41 
     42     /**
     43     * @cfg {Array} cards A numeric array with the configured {@link Ext.ux.Wiz.Card}s.
     44     * The index of the cards in the array represent the order in which they get displayed
     45     * in the wizard (i.e. card at index 0 gets displayed in the first step, card at index 1 gets
     46     * displayed in the second step and so on).
     47     */
     48     cards: [],
     49 
     50     /**
     51     * @cfg {String} previousButtonText The text to render the previous-button with.
     52     * Defaults to "&lt; Back" (< Back)
     53     */
     54     previousButtonText: '&lt; Previous',
     55 
     56     /**
     57     * @cfg {String} nextButtonText The text to render the next-button with.
     58     * Defaults to "Next &gt;" (Next >)
     59     */
     60     nextButtonText: 'Next &gt;',
     61 
     62     /**
     63     * @cfg {String} cancelButtonText The text to render the cancel-button with.
     64     * Defaults to "Cancel"
     65     */
     66     cancelButtonText: 'Cancel',
     67 
     68     /**
     69     * @cfg {String} finishButtonText The text to render the next-button with when the last
     70     * step of the wizard is reached. Defaults to "Finish"
     71     */
     72     finishButtonText: 'Finish',
     73 
     74     /**
     75     * @cfg {Object} headerConfig A config-object to use with {@link Ext.ux.Wiz.Header}.
     76     * If not present, it defaults to an empty object.
     77     */
     78     headConfig: null,
     79 
     80     /**
     81     * @cfg {Object} sideConfig A config-object to use with {@link Ext.ux.Wizard}.
     82     * If not present, it defaults to an empty object.
     83     */
     84     sideConfig: null,
     85 
     86     /**
     87     * @cfg {Object} cardPanelConfig A config-object to use with {@link Ext.Panel}, which
     88     * represents the card-panel in this dialog.
     89     * If not present, it defaults to an empty object
     90     */
     91     cardPanelConfig: {},
     92 
     93     /**
     94     * @param {Ext.Button} The window-button for paging to the previous card.
     95     * @private
     96     */
     97     previousButton: null,
     98 
     99     /**
    100     * @param {Ext.Button} The window-button for paging to the next card. When the
    101     * last card is reached, the event fired by and the text rendered to this button
    102     * will change.
    103     * @private
    104     */
    105     nextButton: null,
    106 
    107     /**
    108     * @param {Ext.Button} The window-button for canceling the wizard. The event
    109     * fired by this button will usually close the dialog.
    110     * @private
    111     */
    112     cancelButton: null,
    113 
    114     /**
    115     * @param {Ex.Panel} The card-panel that holds the various wizard cards
    116     * ({@link Ext.ux.Wiz.Card}). The card-panel itself uses the custom
    117     * {@link Ext.ux.layout.CardLayout}, which needs to be accessible by this class.
    118     * You can get it at {@link http://www.siteartwork.de/cardlayout}.
    119     * @private
    120     */
    121     cardPanel: null,
    122 
    123     /**
    124     * @param {Number} currentCard The current {@link Ext.ux.Wiz.Card} displayed.
    125     * Defaults to 0.
    126     * @private
    127     */
    128     currentCard: 0,
    129 
    130     /**
    131     * @param {Ext.ux.Wiz.Header} The header-panel of the wizard.
    132     * @private
    133     */
    134     headPanel: null,
    135 
    136     /**
    137     * @param {Number} cardCount Helper for storing the number of cards used
    138     * by this wizard. Defaults to 0 (inherits "cards.length" later on).
    139     * @private
    140     */
    141     cardCount: 0,
    142 
    143     /**
    144     * Inits this component with the specified config-properties and automatically
    145     * creates its components.
    146     */
    147     initComponent: function () {
    148 
    149         var c = this.initialConfig, sregion, hregion;
    150 
    151         if (!this.sideConfig) this.sideConfig = {};
    152         if (!this.headConfig) this.headConfig = {};
    153 
    154         if (c.sideConfig && c.sideConfig.position == 'right') { sregion = 'east'; } else { sregion = 'west'; }
    155         if (c.headConfig && c.headConfig.position == 'bottom') { hregion = 'south'; } else { hregion = 'north'; }
    156 
    157         Ext.applyIf(this.cardPanelConfig, { region: 'center', items: (this.cards || [{}]), layout: new Ext.ux.wizard.CardLayout(), border: false, activeItem: 0, baseCls: 'ux-wizard-cardpanel' });
    158         Ext.applyIf(this.sideConfig, { region: sregion, width: 150, layout: 'fit', xtype: 'wizardheader', headerPosition: 'side', steps: this.cards.length, hidden: !(c.sideConfig) });
    159         Ext.applyIf(this.headConfig, { region: hregion, height: 150, layout: 'fit', xtype: 'wizardheader', headerPosition: 'top', steps: this.cards.length, hidden: !(c.headConfig) });
    160 
    161         this.initButtons();
    162         this.initPanels();
    163 
    164         var title = this.title || this.headConfig.title;
    165         title = title || "";
    166 
    167         var items = [];
    168 
    169         items.push(this.sidePanel);
    170         items.push(this.headPanel);
    171         items.push(this.cardPanel);
    172 
    173         Ext.apply(this, {
    174             title: title,
    175             layout: 'border',
    176             cardCount: this.cards.length,
    177             dockedItems: [{
    178                 xtype: 'toolbar',
    179                 dock: 'bottom',
    180                 ui: 'footer',
    181                 defaults: { minWidth: 60 },
    182                 items: [
    183                     { xtype: 'component', flex: 1 },
    184                     this.previousButton,
    185                     this.nextButton,
    186                     this.cancelButton
    187                 ]
    188             }],
    189             items: items
    190         });
    191 
    192         this.callParent();
    193     },
    194 
    195     // -------- helper
    196     /**
    197     * Returns the form-data of all cards in this wizard. The first index is the
    198     * id of the card in this wizard,
    199     * and the values are objects containing key/value pairs in the form of
    200     * fieldName : fieldValue.
    201     *
    202     * @return {Array}
    203     */
    204     getWizardData: function () {
    205         var formValues = {};
    206         var cards = this.cards;
    207         for (var i = 0, len = cards.length; i < len; i++) {
    208             if (cards[i].form) {
    209                 formValues[cards[i].id] = cards[i].form.getValues(false);
    210             } else {
    211                 formValues[cards[i].id] = {};
    212             }
    213         }
    214 
    215         return formValues;
    216     },
    217 
    218     /**
    219     * Switches the state of this wizard between disabled/enabled.
    220     * A disabled dialog will have a {@link Ext.LoadMask} covering the card-panel
    221     * to prevent user input, and the buttons will be rendered disabled/enabled.
    222     * If the dialog is closable, the close-tool will be masked, too, and the dialog will not
    223     * be closable by clicking the "close" tool.
    224     *
    225     * @param {Boolean} enabled "false" to prevent user input and mask the elements,
    226     * otherwise true.
    227     * @param {String} type The type of msg for the {@Ext.LoadMask} covering
    228     * the cardPanel, as defined in the cfg property "loadMaskConfig"
    229     */
    230     switchDialogState: function (enabled, type) {
    231         this.showLoadMask(!enabled, type);
    232 
    233         this.previousButton.setDisabled(!enabled);
    234         this.nextButton.setDisabled(!enabled);
    235         this.cancelButton.setDisabled(!enabled);
    236 
    237         var ct = this.tools['close'];
    238 
    239         if (ct) {
    240             switch (enabled) {
    241                 case true:
    242                     this.tools['close'].unmask();
    243                     break;
    244 
    245                 default:
    246                     this.tools['close'].mask();
    247                     break;
    248             }
    249         }
    250 
    251         this.closable = enabled;
    252     },
    253 
    254     /**
    255     * Shows the load mask for this wizard. By default, the cardPanel's body
    256     * will be masked.
    257     *
    258     * @param {Boolean} show true to show the load mask, otherwise false.
    259     * @param {String} type The type of message for the {@Ext.LoadMask} covering
    260     * the cardPanel, as defined in the cfg property "loadMaskConfig"
    261     */
    262     showLoadMask: function (show, type) {
    263         if (!type) {
    264             type = 'default';
    265         }
    266 
    267         if (show) {
    268             if (this.loadMask == null) {
    269                 this.loadMask = new Ext.LoadMask(this.body);
    270             }
    271             this.loadMask.msg = this.loadMaskConfig[type];
    272             this.loadMask.show();
    273         } else {
    274             if (this.loadMask) {
    275                 this.loadMask.hide();
    276             }
    277         }
    278     },
    279 
    280 
    281     /**
    282     * show the side panel
    283     * 
    284     */
    285     showSidePanel: function () {
    286         this.sidePanel.show();
    287     },
    288 
    289 
    290     /**
    291     * show the side panel
    292     * 
    293     */
    294     showHeadPanel: function () {
    295         this.headPanel.show();
    296     },
    297 
    298 
    299     /**
    300     * hide the side panel
    301     * 
    302     */
    303     showSidePanel: function () {
    304         this.sidePanel.hide();
    305     },
    306 
    307 
    308     /**
    309     * hide the head panel
    310     * 
    311     */
    312     hideHeadPanel: function () {
    313         this.headPanel.hide();
    314     },
    315 
    316 
    317 
    318 
    319     /**
    320     * Inits the listener for the various {@link Ext.ux.Wiz.Card}s used
    321     * by this component.
    322     */
    323     initEvents: function () {
    324         this.callParent();
    325 
    326         this.on('beforeclose', this.onBeforeClose, this);
    327     },
    328 
    329     /**
    330     * Creates the head- and the card-panel.
    331     * Be sure to have the custom {@link Ext.ux.layout.CardLayout} available
    332     * in order to make the card-panel work as expected by this component
    333     * ({@link http://www.siteartwork.de/cardlayout}).
    334     */
    335     initPanels: function () {
    336         var cards = this.cards;
    337         var cardPanelConfig = this.cardPanelConfig;
    338 
    339         Ext.apply(this.headConfig, {
    340             steps: this.cards.length
    341         });
    342 
    343         this.headPanel = Ext.create('Ext.ux.wizard.Header', this.headConfig);
    344 
    345         this.sidePanel = Ext.create('Ext.ux.wizard.Header', this.sideConfig);
    346 
    347         Ext.apply(cardPanelConfig, {
    348             layout: 'card', // new Ext.ux.wizard.CardLayout(),
    349             items: cards
    350         });
    351 
    352         Ext.applyIf(cardPanelConfig, {
    353             region: 'center',
    354             border: false,
    355             activeItem: 0
    356         });
    357 
    358         // var cards = this.cards;
    359 
    360         for (var i = 0, len = cards.length; i < len; i++) {
    361             cards[i].on('beforeactivate', this.onCardShow, this);
    362             cards[i].on('clientvalidation', this.onClientValidation, this);
    363         }
    364 
    365         this.cardPanel = Ext.create('Ext.panel.Panel', cardPanelConfig);
    366     },
    367 
    368     /**
    369     * Creates the instances for the the window buttons.
    370     */
    371     initButtons: function () {
    372         this.previousButton = new Ext.Button({
    373             text: this.previousButtonText,
    374             id: 'wizard-move-prev',
    375             disabled: true,
    376             minWidth: 75,
    377             handler: this.onPreviousClick,
    378             scope: this
    379         });
    380 
    381         this.nextButton = new Ext.Button({
    382             text: this.nextButtonText,
    383             id: 'wizard-move-next',
    384             minWidth: 75,
    385             handler: this.onNextClick,
    386             scope: this
    387         });
    388 
    389         this.cancelButton = new Ext.Button({
    390             text: this.cancelButtonText,
    391             handler: this.onCancelClick,
    392             scope: this,
    393             minWidth: 75
    394         });
    395     },
    396 
    397     // -------- listeners
    398 
    399     /**
    400     * Listener for the beforeclose event.
    401     * This listener will return true or false based on the "closable"
    402     * property by this component. This property will be changed by the "switchDialogState"
    403     * method, indicating if there is currently any process running that should prevent
    404     * this dialog from being closed.
    405     *
    406     * @param {Ext.Panel} panel The panel being closed
    407     *
    408     * @return {Boolean}
    409     */
    410     onBeforeClose: function (panel) {
    411         return this.closable;
    412     },
    413 
    414     /**
    415     * By default, the card firing this event monitors user input in a frequent
    416     * interval and fires the 'clientvalidation'-event along with it. This listener
    417     * will enable/disable the next/finish-button in accordance with it, based upon
    418     * the parameter isValid. isValid" will be set by the form validation and depends
    419     * on the validators you are using for the different input-elemnts in your form.
    420     * If the card does not contain any forms, this listener will never be called by the
    421     * card itself.
    422     *
    423     * @param {Ext.ux.Wiz.Card} The card that triggered the event.
    424     * @param {Boolean} isValid "true", if the user input was valid, otherwise
    425     * "false"
    426     */
    427     onClientValidation: function (card, isValid) {
    428         if (!isValid) {
    429             console.log("setting disabled in onClientValidation");
    430             this.nextButton.setDisabled(true);
    431         } else {
    432             this.nextButton.setDisabled(false);
    433         }
    434     },
    435 
    436     /**
    437     * Listener for the "show" event of the card that gets shown in the card-panel.
    438     * Renders the next/previous buttons based on the position of the card in the wizard
    439     * and updates the head-panel accordingly.
    440     *
    441     * @param {Ext.ux.Wiz.Card} The card being shown.
    442     */
    443     onCardShow: function (card) {
    444         var parent = card.ownerCt;
    445 
    446         var items = parent.items;
    447 
    448         for (var i = 0, len = items.length; i < len; i++) {
    449             if (items.get(i).id == card.id) {
    450                 break;
    451             }
    452         }
    453 
    454         this.currentCard = i;
    455         this.headPanel.updateStep(i, card.carTitle);
    456         this.sidePanel.updateStep(i, card.carTitle);
    457 
    458         if (i == len - 1) {
    459             this.nextButton.setText(this.finishButtonText);
    460         } else {
    461             this.nextButton.setText(this.nextButtonText);
    462         }
    463 
    464         if (card.isValid()) {
    465             this.nextButton.setDisabled(false);
    466         }
    467 
    468         if (i == 0) {
    469             this.previousButton.setDisabled(true);
    470         } else {
    471             this.previousButton.setDisabled(false);
    472         }
    473 
    474     },
    475 
    476 
    477     /**
    478     * Fires the 'cancel'-event. Closes this dialog if the return value of the
    479     * listeners does not equal to "false".
    480     */
    481     onCancelClick: function () {
    482         if (this.fireEvent('cancel', this, this.getWizardData()) !== false) {
    483             this.closable = true;
    484             this.close();
    485         }
    486     },
    487 
    488     /**
    489     * Fires the 'finish'-event. Closes this dialog if the return value of the
    490     * listeners does not equal to "false".
    491     */
    492     onFinish: function () {
    493         if (this.fireEvent('finish', this, this.getWizardData()) !== false) {
    494             this.closable = true;
    495             this.close();
    496         }
    497     },
    498 
    499     /**
    500     * Listener for the previous-button.
    501     * Switches to the previous displayed {@link Ext.ux.Wiz.Card}.
    502     */
    503     onPreviousClick: function (btn) {
    504         if (this.currentCard > 0) {
    505             // this.cardPanel.getLayout().setActiveItem(this.currentCard - 1);
    506             var mywiz = btn.up('panel').cardPanel;
    507             this.navigate(mywiz, 'prev');
    508         }
    509     },
    510 
    511     /**
    512     * Listener for the next-button. Switches to the next {@link Ext.ux.Wiz.Card}
    513     * if the 'beforehide'-method of it did not return false. The functionality
    514     * for this is implemented in {@link Ext.ux.layout.CardLayout}, which is needed
    515     * as the layout for the card-panel of this component.
    516     */
    517     onNextClick: function (btn) {
    518         if (this.currentCard == this.cardCount - 1) {
    519             this.onFinish();
    520         } else {
    521             // this.cardPanel.getLayout().setActiveItem(this.currentCard + 1);
    522             var p = this.cardPanel.items.items[this.currentCard];
    523 
    524             if (p) {
    525                 f = p.getForm();
    526                 if (f.isValid()) {
    527                     this.navigate(btn.up('panel').cardPanel, "next");
    528                 } else {
    529                     p.items.items[0].el.frame("#ff0000");
    530                 }
    531             }
    532         }
    533     },
    534     navigate: function (panel, direction) {
    535         // This routine could contain business logic required to manage the navigation steps.
    536         // It would call setActiveItem as needed, manage navigation button state, handle any
    537         // branching logic that might be required, handle alternate actions like cancellation
    538         // or finalization, etc.  A complete wizard implementation could get pretty
    539         // sophisticated depending on the complexity required, and should probably be
    540         // done as a subclass of CardLayout in a real-world implementation.
    541         var layout = panel.getLayout();
    542         layout[direction]();
    543         Ext.getCmp('wizard-move-prev').setDisabled(!layout.getPrev());
    544         // Ext.getCmp('wizard-move-next').setDisabled(!layout.getNext());
    545     },
    546     afterRender: function () {
    547         this.callParent();
    548 
    549         var ly = this.cardPanel.getLayout();
    550     }
    551 });