define(['dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/_base/html', 'dojo/_base/fx', 'dojo/Deferred', 'dojo/promise/all', 'dojo/on', 'dojo/topic', 'dojo/when', 'require', './utils', './WidgetManager'], function (declare, lang, array, html, baseFx, Deferred, all, on, topic, when, require, utils, WidgetManager) { var clazz, instance = null; clazz = declare(null, { constructor: function(){ //{id, uri, object} this.panels = []; this.widgetManager = WidgetManager.getInstance(); on(window, 'resize', lang.hitch(this, this.onWindowResize)); this.activePanel = null; //because for moveable panel, we can't listen mousedown event of the mover, //and because panel may re-create moveable so we also can't listen moveable's event, //so, we list this topic event. topic.subscribe('/dnd/move/start', lang.hitch(this, this._onMoveStart)); topic.subscribe('widgetActived', lang.hitch(this, this._onWidgetActived)); }, showPanel: function(config){ var def = new Deferred(); var pid = config.id + '_panel', panel = this.getPanelById(pid); if(panel){ if(panel.state === 'closed'){ this.openPanel(panel); } def.resolve(panel); }else{ all({ Panel: this._loadPanelClass(config.panel.uri), nls: this._loadThemeI18N(config.panel.uri) }).then(lang.hitch(this, function(result){ var pid = config.id + '_panel', panel = this.getPanelById(pid); var options = { label: config.label, config: config, uri: config.panel.uri, position: config.panel.position, map: this.map, widgetManager: this.widgetManager, panelManager: this, id: pid, gid: config.gid, nls: result.nls }; lang.mixin(options, config.panel.options); try{ panel = new result.Panel(options); console.log('panel [' + pid + '] created.'); }catch(error){ console.log('create panel error: ' + error + ', panelId: ' + pid); def.reject(error); return; } panel.setPosition(config.panel.position); utils.setVerticalCenter(panel.domNode); this.openPanel(panel); // on(panel.domNode, 'click', lang.hitch(this, this._onPanelClick, panel)); panel.domNode.addEventListener('click', lang.hitch(this, this._onPanelClick, panel), {capture: true}); def.resolve(panel); })); } return def; }, setMap: function(map){ this.map = map; //on(this.map, 'resize', lang.hitch(this, this.onMapResize)); }, closeOtherPanelsInTheSameGroup: function (panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } for(var i = 0; i < this.panels.length; i++){ if(this.panels[i].gid === panel.gid && this.panels[i].id !== panel.id){ this.closePanel(this.panels[i]); } } }, closeAllPanelsInGroup: function (groupId){ for(var i = 0; i < this.panels.length; i++){ if(this.panels[i].gid === groupId){ this.closePanel(this.panels[i]); } } }, openPanel: function(panel){ var def = new Deferred(); if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ def.reject(); return def; } }else{ if(!this.panels.some(function(p){ return p.id === panel.id; })){ this.panels.push(panel); } } if(!panel.started){ try { panel.started = true; panel.startup(); } catch (err) { console.error('fail to startup panel ' + panel.id + '. ' + err.stack); } } if(panel.state === 'opened'){ this._activePanel(panel); def.resolve(panel); return def; } //set state here to avoid openPanel is called twice panel.setState('opened'); return this.playOpenPanelAnimation(panel).then(lang.hitch(this, function(){ html.setStyle(panel.domNode, 'display', ''); panel.onOpen(); this._activePanel(panel); return panel; })); }, closePanel: function(panel){ var def = new Deferred(); if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ def.resolve(); return def; } } if(panel.state === 'closed'){ def.resolve(); return def; } return this.playClosePanelAnimation(panel).then(lang.hitch(this, function(){ if(this.activePanel && this.activePanel.id === panel.id){ this.activePanel.onDeActive(); this.activePanel = null; } panel.setState('closed'); panel.onClose(); if(panel.domNode){ html.setStyle(panel.domNode, 'display', 'none'); } })); }, minimizePanel: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } if(panel.state === 'closed'){ this.openPanel(panel); } panel.setWindowState('minimized'); try{ panel.onMinimize(); }catch(err){ console.log(console.error('fail to minimize panel ' + panel.id + '. ' + err.stack)); } }, maximizePanel: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } if(panel.state === 'closed'){ this.openPanel(panel); } panel.setWindowState('maximized'); try{ panel.onMaximize(); }catch(err){ console.log(console.error('fail to maximize panel ' + panel.id + '. ' + err.stack)); } }, normalizePanel: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } if(panel.state === 'closed'){ this.openPanel(panel); } panel.setWindowState('normal'); try{ panel.onNormalize(); }catch(err){ console.log(console.error('fail to noralize panel ' + panel.id + '. ' + err.stack)); } }, changeWindowStateTo: function(panel, state){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } if(state === 'normal'){ this.normalizePanel(panel); }else if(state === 'minimized'){ this.minimizePanel(panel); }else if(state === 'maximized'){ this.maximizePanel(panel); }else{ console.log('error state: ' + state); } }, getPanelById: function(pid){ for(var i = 0; i < this.panels.length; i++){ if(this.panels[i].id === pid){ return this.panels[i]; } } }, onWindowResize: function(){ for(var i = 0; i < this.panels.length; i++){ if(this.panels[i].state !== 'closed' && this.panels[i].position.relativeTo !== 'map'){ this.panels[i].resize(); } } }, onMapResize: function(){ for(var i = 0; i < this.panels.length; i++){ if(this.panels[i].state !== 'closed' && this.panels[i].position.relativeTo === 'map'){ this.panels[i].resize(); } } }, destroyPanel: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return; } } if(!panel.domNode){ return; } if(panel.state !== 'closed'){ this.closePanel(panel); } this._removePanel(panel); try{ panel.destroy(); }catch(err){ console.log(console.error('fail to destroy panel ' + panel.id + '. ' + err.stack)); } }, destroyAllPanels: function(){ var allPanelIds = array.map(this.panels, function(panel){ return panel.id; }); array.forEach(allPanelIds, function (panelId) { this.destroyPanel(panelId); }, this); this.panels = []; }, playOpenPanelAnimation: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return when(); } } if(!panel.openAnimation || panel.animationDuration === 0){ return when(); } var def = new Deferred(); if(typeof panel.openAnimation === 'string'){ if(panel.openAnimation === 'fadeIn'){ html.setStyle(panel.domNode, { opacity: 0, display: '' }); baseFx.fadeIn({ node: panel.domNode, duration: panel.animationDuration, onEnd: function(){ def.resolve(); } }).play(); }else{ def.resolve(); } }else{ def.resolve(); } return def; }, playClosePanelAnimation: function(panel){ if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return when(); } } if(!panel.closeAnimation || panel.animationDuration === 0){ return when(); } var def = new Deferred(); if(typeof panel.closeAnimation === 'string'){ if(panel.closeAnimation === 'fadeOut'){ baseFx.fadeOut({ node: panel.domNode, duration: panel.animationDuration, onEnd: function(){ def.resolve(); } }).play(); }else{ def.resolve(); } } return def; }, getPositionOnMobile: function(panel){ //the position is minimized as title, half widget/height, full screen if(typeof panel === 'string'){ panel = this.getPanelById(panel); if(!panel){ return {}; } } var box = html.getMarginBox(window.jimuConfig.layoutId); var titleTop = box.h / 2; var borderRadius = '4px'; if(!panel.titleHeight){ panel.titleHeight = 35; } if(panel.windowState === 'maximized'){ return { left: 0, right: 0, top: 0, bottom: 0, width: 'auto', height: 'auto', contentHeight: box.h - panel.titleHeight, borderRadiusStyle: { borderTopLeftRadius: 0, borderTopRightRadius: 0, borderBottomLeftRadius: 0, borderBottomRightRadius: 0 } }; }else if(panel.windowState === 'minimized'){ var minimizedPanels = this.panels.filter(function(p){ return p.windowState === 'minimized' && p.state !== 'closed' && p.id !== panel.id; }); var bottom = 0; if(minimizedPanels.some(function(p){ return p._mobileBottom === 0; })){ bottom = panel.titleHeight; } panel._mobileBottom = bottom; if(box.h > box.w){ //portrait, stay at bottom return { left: 0, right: 0, top: 'auto', bottom: bottom, width: 'auto', height: panel.titleHeight, contentHeight: 0, borderRadiusStyle: { borderTopLeftRadius: borderRadius, borderTopRightRadius: borderRadius, borderBottomLeftRadius: 0, borderBottomRightRadius: 0 } }; }else{//landscape, stay at right, half width return { left: box.w - box.w / 2, right: 0, top: 'auto', bottom: bottom, width: box.w / 2, height: panel.titleHeight, contentHeight: box.h, borderRadiusStyle: window.isRTL? {//stay at left borderTopLeftRadius: 0, borderTopRightRadius: borderRadius, borderBottomLeftRadius: 0, borderBottomRightRadius: borderRadius }: {//stay at left borderTopLeftRadius: borderRadius, borderTopRightRadius: 0, borderBottomLeftRadius: borderRadius, borderBottomRightRadius: 0 } }; } }else{//windowState=normal if(box.h > box.w){ //portrait, stay at bottom return { left: 0, right: 0, top: titleTop, bottom: 0, width: 'auto', height: 'auto', contentHeight: box.h - titleTop - panel.titleHeight, borderRadiusStyle: { borderTopLeftRadius: borderRadius, borderTopRightRadius: borderRadius, borderBottomLeftRadius: 0, borderBottomRightRadius: 0 } }; }else{//landscape, stay at right, half width return { left: box.w - box.w / 2, right: 0, top: 0, bottom: 0, width: box.w / 2, height: 'auto', contentHeight: box.h - titleTop - panel.titleHeight, borderRadiusStyle: window.isRTL? {//stay at left borderTopLeftRadius: 0, borderTopRightRadius: borderRadius, borderBottomLeftRadius: 0, borderBottomRightRadius: borderRadius }: {//stay at left borderTopLeftRadius: borderRadius, borderTopRightRadius: 0, borderBottomLeftRadius: borderRadius, borderBottomRightRadius: 0 } }; } } }, _onPanelClick: function(panel){ this._activePanel(panel); }, activatePanel: function(panel){ if(panel.state !== 'opened'){ return; } this._activePanel(panel); }, _activePanel: function(panel){ if(this.activePanel){ if(this.activePanel.id === panel.id){ //zIndex may be reset by panel self if(this.activePanel.moveTopOnActive){ html.setStyle(this.activePanel.domNode, 'zIndex', 101); } return; } if(this.activePanel.state === 'active'){ this.activePanel.setState('opened'); html.setStyle(this.activePanel.domNode, 'zIndex', typeof this.activePanel.position.zIndex !== 'undefined'? this.activePanel.position.zIndex: 'auto'); this.activePanel.onDeActive(); } } var aw = this.widgetManager.activeWidget; if(aw && aw.state === 'active' && aw.getPanel() !== panel){ aw.setState('opened'); if(aw.inPanel === false){ html.setStyle(aw.domNode, 'zIndex', typeof aw.position.zIndex !== 'undefined'? aw.position.zIndex: 'auto'); } aw.onDeActive(); this.widgetManager.activeWidget = null; } this.activePanel = panel; if(this.activePanel.state === 'active'){ return; } this.activePanel.setState('active'); if(this.activePanel.moveTopOnActive){ html.setStyle(this.activePanel.domNode, 'zIndex', 101); } this.activePanel.onActive(); }, _removePanel: function(panel){ var index = this.panels.indexOf(panel); if(index > -1){ this.panels.splice(index, 1); } if(this.activePanel && this.activePanel.id === panel.id){ this.activePanel = null; } }, _onMoveStart: function(mover){ array.forEach(this.panels, function(panel){ if(panel.domNode === mover.node){ this._activePanel(panel); } }, this); }, _onWidgetActived: function(widget){ if(this.activePanel && this.activePanel.state === 'active' && widget.getPanel() !== this.activePanel){ this.activePanel.setState('opened'); html.setStyle(this.activePanel.domNode, 'zIndex', typeof this.activePanel.position.zIndex !== 'undefined'? this.activePanel.position.zIndex: 'auto'); this.activePanel.onDeActive(); this.activePanel = null; } }, _loadPanelClass: function(panelUri){ var def = new Deferred(); require([panelUri], function(Panel){ def.resolve(Panel); }); return def; }, _loadThemeI18N: function(panelUri){ //panel will use theme's nls file var def = new Deferred(); if(panelUri.startWith('themes')){ var segs = panelUri.split('/'); var nlsFile = segs[0] + '/' + segs[1] + '/nls/strings'; require(['dojo/i18n!' + nlsFile], function(bundle) { def.resolve(bundle); }); }else{ //panel is not in theme def.resolve({}); } return def; } }); clazz.getInstance = function () { if(instance === null) { instance = new clazz(); window._panelManager = instance; } return instance; }; return clazz; });