官术网_书友最值得收藏!

A three-panel application layout with a single line of code

This recipe explains how you can build a reusable Ext JS component that encapsulates one of the most popular GUI styles—a three-panel layout. Using the component will produce a layout like the one shown in the following screenshot:

A three-panel application layout with a single line of code

This layout consists of a Navigation panel, a Master panel, and a Details panel as shown in the following screenshot:

A three-panel application layout with a single line of code

The Master panel has a toolbar with a button that switches the Details panel's location from bottom to right, or hides it altogether:

A three-panel application layout with a single line of code

Besides being able to add components to any of the layout's panels via configuration objects, you can also reconfigure any of the panels by the same means.

How to do it...

  1. Create the skeleton code of our component:
    Ext.ns('Ext.ux');
    Ext.ux.ThreePanelApp=function(conf) {
    // Master Panel
    // Details Panel
    // Nav Panel
    // MasterDetailsCnt
    }
    
  2. Create the Master panel:
    MasterPanel=function(conf) {
    config={ title: 'Master',
    region: 'center',
    tbar: [{
    split: true,
    text: 'Details Panel',
    id: 'details-panel-button',
    handler: this.toggleDetails.createDelegate(this, []),
    menu: {
    id: 'details-menu',
    cls: 'details-menu',
    width: 100,
    items: [{
    text: 'Bottom',
    checked: true,
    group: 'rp-group',
    checkHandler: this.toggleDetails,
    scope: this,
    iconCls: 'details-bottom'
    }, {
    text: 'Right',
    checked: false,
    group: 'rp-group',
    checkHandler: this.toggleDetails,
    scope: this,
    iconCls: 'details-right'
    }, {
    text: 'Hide',
    checked: false,
    group: 'rp-group',
    checkHandler: this.toggleDetails,
    scope: this,
    iconCls: 'details-hide'
    }]
    }
    }]
    };
    Ext.apply(config, conf || {});
    MasterPanel.superclass.constructor.call(this, config);
    }
    
  3. Specify that the Master panel extends the Ext.Panel class and implements the toggleDetails() function:
    Ext.extend(MasterPanel, Ext.Panel, {
    toggleDetails: function(m, pressed) {
    if (!m) {
    var readMenu=Ext.menu.MenuMgr.get('details-menu');
    readMenu.render();
    var items=readMenu.items.items;
    var b=items[0], r=items[1], h=items[2];
    if (b.checked) {
    r.setChecked(true);
    } else if (r.checked) {
    h.setChecked(true);
    } else if (h.checked) {
    b.setChecked(true);
    }
    return;
    }
    if (pressed) {
    var details=Ext.getCmp('details-panel');
    var right=Ext.getCmp('right-details');
    var bot=Ext.getCmp('bottom-details');
    switch (m.text) {
    case 'Bottom':
    right.hide(); right.remove(details, false);
    bot.add(details);
    bot.show();
    bot.ownerCt.doLayout();
    break;
    case 'Right':
    bot.hide(); bot.remove(details, false);
    right.add(details);
    right.show();
    right.ownerCt.doLayout();
    break;
    case 'Hide':
    bot.hide();
    right.hide(); right.remove(details, false); bot.remove(details, false);
    right.ownerCt.doLayout();
    break;
    }
    }
    }
    });
    
  4. Check if a configuration object for the Master panel was specified and create the Master panel instance:
    var masterPanelConf={};
    if (conf && conf.masterPanelConf) {
    masterPanelConf=conf.masterPanelConf;
    }
    var masterPanel=new MasterPanel(masterPanelConf);
    
  5. Similar to the Master panel, create the Details panel:
    DetailsPanel=function(conf) {
    config={
    id: 'details-panel',
    layout: 'fit',
    title: 'Details',
    id: 'details-panel'
    };
    Ext.apply(config, conf || {});
    DetailsPanel.superclass.constructor.call(this, config);
    }
    Ext.extend(DetailsPanel, Ext.Panel);
    var detailsPanelConf={};
    if (conf && conf.detailsPanelConf) {
    detailsPanelConf=conf.detailsPanelConf;
    }
    var detailsPanel=new DetailsPanel(detailsPanelConf);
    
  6. Repeat the process with the Navigation panel:
    NavPanel=function(conf) {
    config={
    title: 'Navigation',
    region: 'west',
    margins: '5 0 5 5',
    cmargins: '5 5 5 5',
    width: 200,
    minSize: 100,
    maxSize: 300
    };
    Ext.apply(config, conf || {});
    NavPanel.superclass.constructor.call(this, config);
    }
    Ext.extend(NavPanel, Ext.Panel);
    var navPanelConf={};
    if (conf && conf.navPanelConf) {
    navPanelConf=conf.navPanelConf;
    }
    var navPanel=new NavPanel(navPanelConf);
    
  7. Define a container for the Master and Details panels:
    MasterDetailsCnt=function(conf) {
    config={
    layout: 'border',
    region: 'center',
    collapsible: false,
    border: false,
    margins: '5 5 5 0',
    id: 'main-view',
    hideMode: 'offsets',
    items: [masterPanel
    , {
    id: 'bottom-details',
    layout: 'fit',
    height: 300,
    split: true,
    border: false,
    region: 'south',
    items: detailsPanel
    }, {
    id: 'right-details',
    layout: 'fit',
    border: false,
    region: 'east',
    width: 350,
    split: true,
    hidden: true
    }]
    };
    Ext.apply(config, conf || {});
    MasterDetailsCnt.superclass.constructor.call(this, config);
    }
    
  8. Check if a configuration object for the Master/Details container panel was specified, and create the object's instance:
    Ext.extend(MasterDetailsCnt, Ext.Panel);
    var masterDetailsCntConfig={};
    if (conf && conf.masterDetailsCntConfig) {
    masterDetailsCntConfig=conf.masterDetailsCntConfig;
    }
    var masterDetailsCnt=new MasterDetailsCnt(masterDetailsCntConfig);
    
  9. Now that the panels have been created, define the layout:
    Ext.ux.ThreePanelApp=function(conf) {
    // Master Panel
    // Details Panel
    // Nav Panel
    // MasterDetailsCnt
    config={
    layout: 'border',
    defaults: {
    collapsible: true,
    split: true
    },
    items: [{ xtype: 'box', el: 'app-header', height: 40, region: 'north' },
    navPanel, masterDetailsCnt]
    };
    if (conf) {
    Ext.apply(config, conf);
    }
    Ext.ux.ThreePanelApp.superclass.constructor.call(this, config);
    }
    Ext.extend(Ext.ux.ThreePanelApp, Ext.Viewport)
    
  10. Your custom layout is ready to be used and you can create it with only one line of code:
    Ext.onReady(function() {
    var container=new Ext.ux.ThreePanelApp();
    });
    
  11. Add a tree view to the Navigation panel and change the panels' titles:
    Ext.onReady(function() {
    var navPanel={ title: 'MyInbox',
    collapsible: true,
    layout: 'fit',
    items: {
    xtype: 'treepanel',
    id: 'inbox-tree',
    autoScroll: true,
    animate: true,
    enableDD: true,
    containerScroll: true,
    border: false,
    dataUrl: 'mail-folders.php',
    root: {
    nodeType: 'async',
    text: 'MailBox',
    draggable: false,
    id: 'mailbox'
    }
    }
    }
    var detailsPanel={ title: 'Re: Join us for happy hour' }
    var masterPanel={ title: 'Messages List' }
    var container=new Ext.ux.ThreePanelApp({
    detailsPanelConf: detailsPanel, navPanelConf: navPanel, masterPanelConf: masterPanel
    });
    });
    

In the following screenshot, you will see what the finished layout looks like:

How to do it...

How it works...

The ThreePanelApp layout is essentially a custom Ext JS component based on the Ext.Viewport class. Creating the layout starts with a basic code template. This template has placeholders for each of the panels in the layout.

Ext.ns('Ext.ux');
Ext.ux.ThreePanelApp=function(conf) {
// Master panel
// Details panel
// Nav panel
// MasterDetailsCnt panel
}

Notice that in addition to the placeholders for the Navigation, Master, and Details panels, there is a place for a fourth panel—MasterDetailsCnt. This panel will be a container for the Master panel and two additional panels that will host the Details panel when it is positioned below or to the right of the Master panel respectively. ThreePanelApp will use a border layout that will contain the Navigation panel (which will take the west region) and the MasterDetailsCnt panel (which will take the center region). MasterDetailsCnt will use a BorderLayout to position the Master and Details panels' hosts.

Moving on, the Master panel is an Ext.Panel extension that contains the cycle button for repositioning the Details panel:

tbar: [{
handler: this.toggleDetails.createDelegate(this, []),
}]

The Master Panel uses a default config object that gets overridden by the masterPanelConf object passed during the construction of a ThreePanelApp instance:

MasterPanel=function(conf) {
Ext.apply(config, conf || {});
MasterPanel.superclass.constructor.call(this, config);
}

This pattern of overriding the default configuration (also used with the rest of the panels), allows you to add your application's components to ThreePanelApp.

Another interesting area in the Master panel is the toggleDetails() function. This function achieves the repositioning of the Details panel by switching the panel's container or hiding it altogether as shown here:

toggleDetails: function(m, pressed) {
var details=Ext.getCmp('details-panel');
var right=Ext.getCmp('right-details');
var bot=Ext.getCmp('bottom-details');
switch (m.text) {
case 'Bottom':
right.hide(); 
right.remove(details, false);
bot.add(details);
bot.show();
bot.ownerCt.doLayout();
break;
case 'Right':
bot.hide(); 
bot.remove(details, false);
right.add(details);
right.show();
right.ownerCt.doLayout();
break;
case 'Hide':
bot.hide();
right.hide(); 
right.remove(details, false); 
bot.remove(details, false);
right.ownerCt.doLayout();
break;
}
}

After defining the Master panel, the layout creates a working instance of this panel and applies any supplied configuration for it.

var masterPanelConf={};
if (conf && conf.masterPanelConf) {
masterPanelConf=conf.masterPanelConf;
}
var masterPanel=new MasterPanel

The Details and Navigation panels do not have any out-of-the-box extra functionality and hence their creation is less involved. As with the Master panel, you can add components to these panels when building the layout by overriding their default configurations.

MasterDetailsCnt is a container panel for the Master and Details panels hosts. Notice how one host uses the south region of the MasterDetailsCnt layout, whereas the other uses the east region:

MasterDetailsCnt=function(conf) {
config={
items: [
masterPanel,
{
id: 'bottom-details',
layout: 'fit',
height: 300,
split: true,
border: false,
region: 'south',
items: detailsPanel
}, {
id: 'right-details',
layout: 'fit',
border: false,
region: 'east',
width: 350,
split: true,
hidden: true
}]
}
}

When all of the panels needed by the ThreePanelApp component are created, what's left is defining the custom layout for the component. Notice the inclusion of a north region where you can put a logo and other components:

Ext.ux.ThreePanelApp=function(conf) {
config={
layout: 'border',
defaults: {
collapsible: true,
split: true
},
items: [{ xtype: 'box', el: 'app-header', height: 40, region: 'north' },
navPanel, masterDetailsCnt]
};
if (conf) {
Ext.apply(config, conf);
}
Ext.ux.ThreePanelApp.superclass.constructor.call(this, config);
}

Now the custom layout can be put into action:

var navPanel={ ... }
var detailsPanel={ ... }
var masterPanel={ ... }
var container=new Ext.ux.ThreePanelApp({
detailsPanelConf: detailsPanel,
navPanelConf: navPanel,
masterPanelConf: masterPanel
});

There's more...

Use this layout when you need a simple three-panel GUI without having to worry about all its plumbing. More importantly, the extension model used in ThreePanelApp can be used as a reference for creating even more complex reusable layouts and custom components.

See also...

  • The recipe, Creating a modern application layout with collapsible region (seen earlier in this chapter), explains how to create one of the most popular UI layouts
主站蜘蛛池模板: 陕西省| 搜索| 兴安县| 徐州市| 牙克石市| 呼玛县| 泸水县| 和平区| 三都| 阿鲁科尔沁旗| 长岭县| 庆云县| 库车县| 阿坝| 六枝特区| 永济市| 长宁区| 盘锦市| 吉隆县| 泾川县| 浦北县| 石景山区| 千阳县| 白水县| 芜湖县| 宣汉县| 肃宁县| 龙山县| 图片| 金川县| 双桥区| 磐石市| 涪陵区| 临夏县| 嘉黎县| 临夏县| 新巴尔虎右旗| 印江| 五台县| 东丽区| 盐亭县|