define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/html', 'dijit/_WidgetBase', 'dojo/topic', 'dojo/on', 'dojo/query', 'dojo/Deferred', 'dojo/promise/all', 'dojo/debounce', 'require', './MapManager', './utils' ], function(declare, lang, html, _WidgetBase, topic, on, query, Deferred, all, debounce, require, MapManager, utils) { /* global jimuConfig:true */ var instance = null, clazz; /** * This is the general layout manager, and it will deleget the layout manage responsibility to other manager * depends on the config. * What this class does is: * * load and manage theme change * * load and manage map change * * delegate layout manage to other manager * @param {[type]} options [description] * @param {[type]} domId) { this.widgetManager [description] * @return {[type]} [description] */ clazz = declare([_WidgetBase], { constructor: function(options, domId) { /*jshint unused: false*/ this.own(topic.subscribe("appConfigLoaded", lang.hitch(this, this._onAppConfigLoaded))); this.own(topic.subscribe("appConfigChanged", lang.hitch(this, this._onAppConfigChanged))); this.own(topic.subscribe("mapLoaded", lang.hitch(this, this._onMapLoaded))); this.own(topic.subscribe("mapChanged", lang.hitch(this, this._onMapChanged))); this.own(topic.subscribe("beforeMapDestory", lang.hitch(this, this._onBeforeMapDestory))); this.own(topic.subscribe("preloadModulesLoaded", lang.hitch(this, this._onPreloadModulesLoaded))); //If a widget want to open another widget, please publish this message with widgetId as a //parameter this.own(topic.subscribe("openWidget", lang.hitch(this, this._onOpenWidgetRequest))); this.own(topic.subscribe("builder/actionTriggered", lang.hitch(this, this._onActionTriggered))); //avoid mobileKeyboard resize if (!utils.isMobileUa()) { this.own(on(window, 'resize', debounce(lang.hitch(this, this.resize), 200))); } this.id = domId; this.preloadModulesLoadDef = new Deferred(); }, postCreate: function(){ this.containerNode = this.domNode; }, map: null, mapId: 'map', mapDiv: null, hlDiv: null, layoutManager: null, animTime: 500, resize: function() { if(this.layoutManager){ this.layoutManager.resize(); } }, _onAppConfigLoaded: function(config){ this.appConfig = lang.clone(config); this.preloadModulesLoadDef.then(lang.hitch(this, function(){ this._loadLayoutManager(this.appConfig).then(lang.hitch(this, function(layoutManager){ this.layoutManager = layoutManager; this.layoutManager.onEnter(this.appConfig, this.mapId) .then(lang.hitch(this, function(){ this.mapDiv = this.layoutManager.getMapDiv(); this._loadMap(this.mapId); if(this.appConfig.theme){ this._loadTheme(this.appConfig.theme); } })); })); })); }, _loadLayoutManager: function(appConfig){ var managerName; if(appConfig.layoutDefinition){ managerName = appConfig.layoutDefinition.manager; }else{ managerName = 'jimu/layoutManagers/AbsolutePositionLayoutManager'; } var def = new Deferred(); require([managerName], lang.hitch(this, function(ManagerClass){ var instance = ManagerClass.getInstance(); if (this.map) { instance.setMap(this.map); } def.resolve(instance); })); return def; }, _loadMap: function(mapId) { this.mapManager = MapManager.getInstance({ appConfig: this.appConfig, urlParams: this.urlParams }, mapId); this.mapManager.showMap(); }, _onMapLoaded: function(map) { this.map = map; this.layoutManager.setMap(map); this.layoutManager.loadAndLayout(this.appConfig); }, _onPreloadModulesLoaded: function(){ this.preloadModulesLoadDef.resolve(); }, _loadTheme: function(theme) { var def = new Deferred(); require(['themes/' + theme.name + '/main'], lang.hitch(this, function(){ all([this._loadThemeCommonStyle(theme), this._loadThemeCurrentStyle(theme)]) .then(lang.hitch(this, function() { this._addCustomStyle(theme); this.layoutManager.onThemeLoad(); def.resolve(); })); })); return def; }, _loadThemeCommonStyle: function(theme) { // append theme name for better selector definition html.addClass(this.domNode, theme.name); return utils.loadStyleLink(this._getThemeCommonStyleId(theme), 'themes/' + theme.name + '/common.css'); }, _loadThemeCurrentStyle: function(theme) { // append theme style name for better selector definitions html.addClass(this.domNode, theme.styles[0]); return utils.loadStyleLink(this._getThemeCurrentStyleId(theme), 'themes/' + theme.name + '/styles/' + theme.styles[0] + '/style.css'); }, _addCustomStyle: function(theme) { var customStyles = lang.getObject('customStyles', false, theme); if(!customStyles){ return; } var cssText = ".jimu-main-background{background-color: ${mainBackgroundColor} !important;}"; var themeCssText = this._getFixedThemeStyles(theme); if(themeCssText){ cssText += themeCssText; } cssText = lang.replace(cssText, customStyles, /\$\{([^\}]+)\}/g); var style = html.create('style', { type: 'text/css' }); try { style.appendChild(document.createTextNode(cssText)); } catch(err) { style.styleSheet.cssText = cssText; } style.setAttribute('source', 'custom'); document.head.appendChild(style); }, /** * This is a temp fix because the custom color can override one color only. * @param {Object} theme * @return {String} The CSS string */ _getFixedThemeStyles: function(theme){ //fix popup var cssText = '.esriPopup .titlePane {background-color: ${mainBackgroundColor} !important;}'; if(theme.customStyles.mainBackgroundColor && utils.isLightColor(theme.customStyles.mainBackgroundColor)){ var imageUrl = require.toUrl('jimu') + '/css/images/api_popup_light.png'; cssText += '.esriPopup .titleButton {background: url(' + imageUrl + ') no-repeat}'; cssText += '.esriPopup .titlePane {color: black}'; } if(theme.name === 'PlateauTheme'){ cssText += '.jimu-widget-header-controller .jimu-title, .jimu-widget-header-controller .jimu-subtitle' + '{color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-widget-header-controller .links .jimu-link' + '{color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-widget-homebutton .HomeButton .home, .jimu-widget-mylocation,' + ' .jimu-widget-mylocation .place-holder, .jimu-widget-zoomslider.vertical .zoom-in,' + ' .jimu-widget-zoomslider.vertical .zoom-out, .jimu-widget-extent-navigate.vertical .operation' + '{background-color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-preload-widget-icon-panel > .jimu-panel-title,' + ' .jimu-foldable-panel > .jimu-panel-title, .jimu-title-panel > .title' + '{color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-panel{border-color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-widget-header-controller' + '{border-bottom-color: ${mainBackgroundColor} !important;}'; cssText += '.jimu-tab>.control>.tab' + '{color: ${mainBackgroundColor} !important; border-color: ${mainBackgroundColor} !important}'; }else if(theme.name === 'BillboardTheme'){ cssText += '.jimu-widget-homebutton .HomeButton .home,' + ' .jimu-widget-mylocation .place-holder, .jimu-widget-zoomslider.vertical .zoom-in,' + ' .jimu-widget-zoomslider.vertical .zoom-out, .jimu-widget-extent-navigate .operation,' + ' .jimu-widget-fullScreen .fullScreen,' + ' .jimu-widget-mylocation .place-holder.nohttps:hover,' + ' .jimu-widget-extent-navigate .operation.jimu-state-disabled:hover' + '{background-color: ${mainBackgroundColor} !important; opacity: 0.8;}'; cssText += '.jimu-widget-onscreen-icon' + '{background-color: ${mainBackgroundColor} !important; opacity: 0.8;}'; cssText += '.jimu-widget-homebutton .HomeButton .home:hover,' + ' .jimu-widget-mylocation .place-holder:not(.nohttps):hover,' + ' .jimu-widget-zoomslider.vertical .zoom-in:hover,' + ' .jimu-widget-zoomslider.vertical .zoom-out:hover,' + ' .jimu-widget-extent-navigate .operation:not(.jimu-state-disabled):hover,' + ' .jimu-widget-fullScreen .fullScreen:hover,' + ' .jimu-widget-onscreen-icon:hover,' + ' .jimu-widget-onscreen-icon.jimu-state-selected' + '{opacity: 1;}'; }else if(theme.name === 'BoxTheme'){ cssText += '.jimu-widget-homebutton .HomeButton .home,' + ' .jimu-widget-mylocation .place-holder, .jimu-widget-zoomslider.vertical .zoom-in,' + ' .jimu-widget-zoomslider.vertical .zoom-out,' + ' .jimu-widget-extent-navigate .operation,' + ' .jimu-widget-fullScreen .fullScreen' + '{background-color: ${mainBackgroundColor} !important; opacity: 0.8;}'; cssText += '.jimu-main-background.jimu-widget-zoomslider{background-color: transparent !important}'; cssText += '.jimu-widget-homebutton .HomeButton .home:hover,' + ' .jimu-widget-mylocation .place-holder:not(.nohttps):hover,' + ' .jimu-widget-zoomslider.vertical .zoom-in:hover,' + ' .jimu-widget-zoomslider.vertical .zoom-out:hover,' + ' .jimu-widget-zoomslider .zoom:hover,' + ' .jimu-widget-extent-navigate .operation:not(.jimu-state-disabled):hover,' + ' .jimu-widget-fullScreen .fullScreen:hover' + '{background-color: ${mainBackgroundColor} !important; opacity: 1;}'; }else if(theme.name === 'TabTheme'){ cssText += '.tab-widget-frame .title-label{color: ${mainBackgroundColor} !important;}'; }else if(theme.name === 'DashboardTheme'){ cssText += '.jimu-widget-dnd-header{background-color: ${mainBackgroundColor} !important;}'; }else if(theme.name === 'DartTheme'){ cssText += '.jimu-widget-fullScreen .fullScreen{background-color: ${mainBackgroundColor} !important;}'; cssText += '.dart-controller-extent-navigate .jimu-widget-extent-navigate .operation.jimu-state-disabled,' + '.dart-controller-extent-navigate .jimu-widget-extent-navigate .operation.jimu-state-disabled:hover' + '{color: ${mainBackgroundColor} !important; opacity: 0.6;}'; cssText += '.dart-controller-extent-navigate .jimu-widget-extent-navigate .operation,' + '.dart-controller-extent-navigate .jimu-widget-extent-navigate .operation:hover' + '{color: ${mainBackgroundColor} !important; opacity: 1;}'; }else if (theme.name === 'PocketTheme'){ cssText += '.jimu-main-background, .jimu-widget-homebutton,' + ' .jimu-widget-mylocation, .jimu-widget-onscreen-icon,' + ' .jimu-widget-onscreen-icon.jimu-state-selected,' + ' .jimu-widget-zoomslider .zoom, .jimu-widget-homebutton .HomeButton .home,' + ' .jimu-widget-mylocation .place-holder, .jimu-widget-extent-navigate .operation,' + ' .jimu-widget-fullScreen .fullScreen,' + ' .esriPopup .titlePane, .esriPopupMobile .titlePane, .esriPopup .pointer.top' + '{background-color: ${mainBackgroundColor} !important;}'; cssText += '.esriMobileNavigationBar' + '{background-color: ${mainBackgroundColor} !important; background-image: none !important;}'; } return cssText; }, ////////////////////////// handle events for builder _onAppConfigChanged: function(appConfig, reason, changeData){ appConfig = lang.clone(appConfig); //deal with these reasons only switch(reason){ case 'themeChange': this._onThemeChange(appConfig); break; case 'styleChange': this._onStyleChange(appConfig); break; case 'layoutChange': this._onLayoutChange(appConfig); break; case 'widgetChange': this._onWidgetChange(appConfig, changeData); break; case 'groupChange': this._onGroupChange(appConfig, changeData); break; case 'widgetPoolChange': this._onWidgetPoolChange(appConfig, changeData); break; case 'resetConfig': this._onResetConfig(appConfig); break; case 'loadingPageChange': this._onLoadingPageChange(appConfig, changeData); break; case 'layoutDefinitionChange': this._onLayoutDefinitionChange(appConfig, changeData); break; case 'onScreenGroupsChange': this._onOnScreenGroupsChange(appConfig, changeData); break; case 'onScreenOrderChange': this._onOnScreenOrderChange(appConfig, changeData); break; } this.appConfig = appConfig; }, _onMapChanged: function(map){ this.map = map; this.layoutManager.setMap(map); this.layoutManager.loadAndLayout(this.appConfig); }, _onBeforeMapDestory: function(){ //when map changed, use destroy and then create to simplify the widget development //destroy widgets before map, because the widget may use map in thire destory method this.layoutManager.destroyOnScreenWidgetsAndGroups(); }, _onThemeChange: function(appConfig){ this.layoutManager.destroyOnScreenWidgetsAndGroups(); this._removeThemeCommonStyle(this.appConfig.theme); this._removeThemeCurrentStyle(this.appConfig.theme); this._removeCustomStyle(); all([this._loadLayoutManager(appConfig), this._loadTheme(appConfig.theme)]) .then(lang.hitch(this, function(results){ var layoutManager = results[0]; if(this.layoutManager.name !== layoutManager.name){ this.layoutManager.onLeave(); layoutManager.onEnter(appConfig, this.mapId) .then(lang.hitch(this, function(){ this.layoutManager = layoutManager; this.layoutManager.loadAndLayout(appConfig); })); } else { this.layoutManager.loadAndLayout(appConfig); } })); }, _onResetConfig: function(appConfig){ var oldAC = this.appConfig; topic.publish('appConfigChanged', appConfig, 'mapChange', appConfig);//this line will change this.appConfig this.appConfig = oldAC; this._loadLayoutManager(appConfig).then(lang.hitch(this, function(layoutManager){ this.layoutManager = layoutManager; this._removeThemeCommonStyle(this.appConfig.theme); this._removeThemeCurrentStyle(this.appConfig.theme); this._removeCustomStyle(); this._loadTheme(this.appConfig.theme); })); }, _onLoadingPageChange: function(appConfig, changeData){ if('backgroundColor' in changeData){ html.setStyle(jimuConfig.loadingId, 'background-color', appConfig.loadingPage.backgroundColor); }else if('backgroundImage' in changeData){ var bgImage = appConfig.loadingPage.backgroundImage; if(bgImage.visible && bgImage.uri){ html.setStyle(jimuConfig.loadingImageId, 'background-image', 'url(\'' + bgImage.uri + '\')'); html.setStyle(jimuConfig.loadingImageId, 'width', bgImage.width + 'px'); html.setStyle(jimuConfig.loadingImageId, 'height', bgImage.height + 'px'); }else{ html.setStyle(jimuConfig.loadingImageId, 'background-image', 'url(\'\')'); html.setStyle(jimuConfig.loadingImageId, 'width', '0px'); html.setStyle(jimuConfig.loadingImageId, 'height', '0px'); } }else if('loadingGif' in changeData){ var gifImage = appConfig.loadingPage.loadingGif; if(gifImage.visible && gifImage.uri){ html.setStyle(jimuConfig.loadingGifId, 'background-image', 'url(\'' + gifImage.uri + '\')'); html.setStyle(jimuConfig.loadingGifId, 'width', gifImage.width + 'px'); html.setStyle(jimuConfig.loadingGifId, 'height', gifImage.height + 'px'); }else{ html.setStyle(jimuConfig.loadingGifId, 'background-image', 'url(\'\')'); html.setStyle(jimuConfig.loadingGifId, 'width', '0px'); html.setStyle(jimuConfig.loadingGifId, 'height', '0px'); } } }, _onStyleChange: function(appConfig){ var currentTheme = this.appConfig.theme; this._removeThemeCurrentStyle(currentTheme); this._loadThemeCurrentStyle(appConfig.theme); this._removeCustomStyle(); this._addCustomStyle(appConfig.theme); }, _onLayoutChange: function(appConfig){ //layout manager is not allowed changed between layout this.layoutManager.onLayoutChange(appConfig); }, _onWidgetChange: function(appConfig, widgetJson){ this.layoutManager.onWidgetChange(appConfig, widgetJson); }, _onGroupChange: function(appConfig, groupJson){ this.layoutManager.onGroupChange(appConfig, groupJson); }, _onWidgetPoolChange: function(appConfig, changeData){ this.layoutManager.onWidgetPoolChange(appConfig, changeData); }, _onActionTriggered: function(actionInfo){ this.layoutManager.onActionTriggered(actionInfo); }, _onLayoutDefinitionChange: function(appConfig, layoutDefinition){ this.layoutManager.onLayoutDefinitionChange(appConfig, layoutDefinition); }, _onOnScreenGroupsChange: function(appConfig, groups){ this.layoutManager.onOnScreenGroupsChange(appConfig, groups); }, _onOnScreenOrderChange: function(appConfig, onscreenWidgets) { this.layoutManager.onOnScreenOrderChange(appConfig, onscreenWidgets); }, _removeThemeCommonStyle: function(theme){ html.removeClass(this.domNode, theme.name); html.destroy(this._getThemeCommonStyleId(theme)); }, _removeThemeCurrentStyle: function(theme){ html.removeClass(this.domNode, theme.styles[0]); html.destroy(this._getThemeCurrentStyleId(theme)); }, _removeCustomStyle: function() { query('style[source="custom"]', document.head).forEach(function(s) { html.destroy(s); }); }, _getThemeCommonStyleId: function(theme){ return 'theme_' + theme.name + '_style_common'; }, _getThemeCurrentStyleId: function(theme){ return 'theme_' + theme.name + '_style_' + theme.styles[0]; }, _doPostLoad: function(){ require(['dynamic-modules/postload']); }, _onOpenWidgetRequest: function(widgetId){ this.layoutManager.openWidget(widgetId); } }); clazz.getInstance = function(options, domId) { if (instance === null) { instance = new clazz(options, domId); window._layoutManager = instance; } return instance; }; return clazz; });