Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>I suggest to use <a href="http://dev.sencha.com/deploy/ext-4.0.7-gpl/examples/portal/portal.html" rel="nofollow">Sencha Portal</a> feature with some modifications below to achieve this.</p> <p>My source code extended the portal example in latest version (4.0.7) as the following:</p> <ol> <li>portal.html</li> </ol> <pre class="lang-html prettyprint-override"><code>&lt;html&gt; &lt;head&gt; &lt;link rel="stylesheet" type="text/css" href="../../resources/css/ext-all.css" /&gt; &lt;link rel="stylesheet" type="text/css" href="portal.css" /&gt; &lt;script type="text/javascript" src="../../builds/ext-core.js"&gt;&lt;/script&gt; &lt;script type="text/javascript" src="../../ext-all-debug.js"&gt;&lt;/script&gt; &lt;!-- shared example code --&gt; &lt;script type="text/javascript" src="../shared/examples.js"&gt;&lt;/script&gt; &lt;!-- &lt;script type="text/javascript" src="classes.js"&gt;&lt;/script&gt; --&gt; &lt;script type="text/javascript" src="portal.js"&gt;&lt;/script&gt; &lt;script type="text/javascript"&gt; Ext.Loader.setConfig({enabled:true}); Ext.Loader.setPath('Ext.app', 'classes'); Ext.require([ 'Ext.layout.container.*', 'Ext.resizer.Splitter', 'Ext.fx.target.Element', 'Ext.fx.target.Component', 'Ext.window.Window', 'Ext.app.Portlet', 'Ext.app.PortalColumn', 'Ext.app.PortalPanel', 'Ext.app.Portlet', 'Ext.app.PortalDropZone', 'Ext.app.GridPortlet', 'Ext.app.ChartPortlet' ]); Ext.onReady(function(){ Ext.create('Ext.app.Portal'); }); &lt;/script&gt; &lt;/head&gt; &lt;body&gt; &lt;span id="app-msg" style="display:none;"&gt;&lt;/span&gt; &lt;/body&gt; &lt;/html&gt; </code></pre> <ol> <li>portal.js</li> </ol> <pre><code>Ext.define('Ext.app.Portal', { extend: 'Ext.container.Viewport', uses: ['Ext.app.PortalPanel', 'Ext.app.PortalColumn', 'Ext.app.GridPortlet', 'Ext.app.ChartPortlet'], getTools: function(){ return [{ xtype: 'tool', type: 'gear', handler: function(e, target, panelHeader, tool){ var portlet = panelHeader.ownerCt; portlet.setLoading('Working...'); Ext.defer(function() { portlet.setLoading(false); }, 2000); } }]; }, initComponent: function(){ var content = '&lt;div class="portlet-content"&gt;'+Ext.example.shortBogusMarkup+'&lt;/div&gt;'; Ext.apply(this, { id: 'app-viewport', layout: { type: 'border', padding: '0 5 5 5' // pad the layout from the window edges }, items: [{ id: 'app-header', xtype: 'box', region: 'north', height: 40, html: 'Ext Portal' },{ xtype: 'container', region: 'center', layout: 'border', items: [{ id: 'app-options', title: 'Options', region: 'west', animCollapse: true, width: 200, minWidth: 150, maxWidth: 400, split: true, collapsible: true, layout: 'accordion', layoutConfig:{ animate: true }, items: [{ html: content, title:'Navigation', autoScroll: true, border: false, iconCls: 'nav' },{ title:'Settings', html: content, border: false, autoScroll: true, iconCls: 'settings' }] },{ id: 'app-portal', xtype: 'portalpanel', region: 'center', items: [{ id: 'col-1', items: [{ id: 'portlet-1', title: 'Grid Portlet', tools: this.getTools(), items: Ext.create('Ext.app.GridPortlet'), listeners: { 'close': Ext.bind(this.onPortletClose, this) } },{ id: 'portlet-2', title: 'Portlet 2', tools: this.getTools(), html: content, listeners: { 'close': Ext.bind(this.onPortletClose, this) } }] },{ id: 'col-2', items: [{ id: 'portlet-3', title: 'Portlet 3', tools: this.getTools(), html: '&lt;div class="portlet-content"&gt;'+Ext.example.bogusMarkup+'&lt;/div&gt;', listeners: { 'close': Ext.bind(this.onPortletClose, this) } },{ id: 'portlet-4', title: 'Stock Portlet', tools: this.getTools(), items: Ext.create('Ext.app.ChartPortlet'), listeners: { 'close': Ext.bind(this.onPortletClose, this) } }] }] }] }] }); this.callParent(arguments); }, onPortletClose: function(portlet) { this.showMsg('"' + portlet.title + '" was removed'); }, showMsg: function(msg) { var el = Ext.get('app-msg'), msgId = Ext.id(); this.msgId = msgId; el.update(msg).show(); Ext.defer(this.clearMsg, 3000, this, [msgId]); }, clearMsg: function(msgId) { if (msgId === this.msgId) { Ext.get('app-msg').hide(); } } }); </code></pre> <ol> <li>PortalDropZone.js</li> </ol> <pre><code> Ext.define('Ext.app.PortalDropZone', { extend: 'Ext.dd.DropTarget', constructor: function(portal, cfg) { this.portal = portal; Ext.dd.ScrollManager.register(portal.body); Ext.app.PortalDropZone.superclass.constructor.call(this, portal.body, cfg); portal.body.ddScrollConfig = this.ddScrollConfig; }, ddScrollConfig: { vthresh: 50, hthresh: -1, animate: true, increment: 200 }, createEvent: function(dd, e, data, col, c, pos) { return { portal: this.portal, panel: data.panel, columnIndex: col, column: c, position: pos, data: data, source: dd, rawEvent: e, status: this.dropAllowed }; }, notifyOver: function(dd, e, data) { var xy = e.getXY(), portal = this.portal, proxy = dd.proxy; // case column widths if (!this.grid) { this.grid = this.getGrid(); } // handle case scroll where scrollbars appear during drag var cw = portal.body.dom.clientWidth; if (!this.lastCW) { // set initial client width this.lastCW = cw; } else if (this.lastCW != cw) { // client width has changed, so refresh layout &amp; grid calcs this.lastCW = cw; //portal.doLayout(); this.grid = this.getGrid(); } // determine column var colIndex = 0, colRight = 0, cols = this.grid.columnX, len = cols.length, cmatch = false; for (len; colIndex &lt; len; colIndex++) { colRight = cols[colIndex].x + cols[colIndex].w; if (xy[0] &lt; colRight) { cmatch = true; break; } } // no match, fix last index if (!cmatch) { colIndex--; } // find insert position var overPortlet, pos = 0, h = 0, match = false, overColumn = portal.items.getAt(colIndex), portlets = overColumn.items.items, overSelf = false; len = portlets.length; for (len; pos &lt; len; pos++) { overPortlet = portlets[pos]; h = overPortlet.el.getHeight(); if (h === 0) { overSelf = true; } else if ((overPortlet.el.getY() + (h / 2)) &gt; xy[1]) { match = true; break; } } pos = (match &amp;&amp; overPortlet ? pos : overColumn.items.getCount()) + (overSelf ? -1 : 0); var overEvent = this.createEvent(dd, e, data, colIndex, overColumn, pos); if (portal.fireEvent('validatedrop', overEvent) !== false &amp;&amp; portal.fireEvent('beforedragover', overEvent) !== false) { // make sure proxy width is fluid in different width columns proxy.getProxy().setWidth('auto'); if (overPortlet) { proxy.moveProxy(overPortlet.el.dom.parentNode, match ? overPortlet.el.dom : null); } else { proxy.moveProxy(overColumn.el.dom, null); } this.lastPos = { c: overColumn, col: colIndex, p: overSelf || (match &amp;&amp; overPortlet) ? pos : false }; this.scrollPos = portal.body.getScroll(); portal.fireEvent('dragover', overEvent); return overEvent.status; } else { return overEvent.status; } }, notifyOut: function() { delete this.grid; }, notifyDrop: function(dd, e, data) { delete this.grid; if (!this.lastPos) { return; } var c = this.lastPos.c, col = this.lastPos.col, pos = this.lastPos.p, panel = dd.panel, dropEvent = this.createEvent(dd, e, data, col, c, pos !== false ? pos : c.items.getCount()); if (this.portal.fireEvent('validatedrop', dropEvent) !== false &amp;&amp; this.portal.fireEvent('beforedrop', dropEvent) !== false) { // make sure panel is visible prior to inserting so that the layout doesn't ignore it panel.el.dom.style.display = ''; /* * Start customization * Switch position of two panels when drop */ var sourceColumn = panel.ownerCt; var sourceRow = sourceColumn.items.indexOf(panel); if (pos !== false) { var targetPanel = c.items.getAt(pos); sourceColumn.insert(sourceRow, targetPanel); c.insert(pos, panel); } else { c.add(panel); } /* * End of customization */ dd.proxy.hide(); this.portal.fireEvent('drop', dropEvent); // scroll position is lost on drop, fix it var st = this.scrollPos.top; if (st) { var d = this.portal.body.dom; setTimeout(function() { d.scrollTop = st; }, 10); } } delete this.lastPos; return true; }, // internal cache of body and column coords getGrid: function() { var box = this.portal.body.getBox(); box.columnX = []; this.portal.items.each(function(c) { box.columnX.push({ x: c.el.getX(), w: c.el.getWidth() }); }); return box; }, // unregister the dropzone from ScrollManager unreg: function() { Ext.dd.ScrollManager.unregister(this.portal.body); Ext.app.PortalDropZone.superclass.unreg.call(this); } }); </code></pre>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload