/////////////////////////////////////////////////////////////////////////// // Copyright © 2014 - 2018 Esri. All Rights Reserved. // // Licensed under the Apache License Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. /////////////////////////////////////////////////////////////////////////// define([ 'dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/_base/html', 'dojo/dom-class', 'dojo/_base/window', 'dojo/window', 'dojo/query', 'dojo/on', //'dojo/topic', 'dojo/Deferred', 'jimu/BaseWidget', 'jimu/WidgetManager', 'jimu/LayoutManager', 'jimu/utils', 'dojo/NodeList-dom', 'dojo/NodeList-manipulate' ], function(declare, lang, array, html, domClass, winBase, win, query, on, Deferred, BaseWidget, WidgetManager, LayoutManager, utils) { /* global jimuConfig */ /*jshint scripturl:true*/ var clazz = declare([BaseWidget], { baseClass: 'jimu-widget-header jimu-main-background', name: 'Header', switchableElements: {}, _boxSizes: null, _searchWidgetId: "", moveTopOnActive: false, constructor: function() { this.height = this.getHeaderHeight() + 'px'; this.widgetManager = WidgetManager.getInstance(); this.LayoutManager = LayoutManager.getInstance(); }, postCreate: function() { this.inherited(arguments); this._boxSizes = {}; this.own(on(this.widgetManager, 'widget-created', lang.hitch(this, function(widget) { if(widget.name === 'Search') { var searchWidget = this._getSearchWidgetInHeader(); if (searchWidget) { html.addClass(searchWidget.domNode, 'has-transition'); // check if the search dijit has been parsed within the search widget // if not, wait until it is ready, and then call resize() if(searchWidget && !searchWidget.searchDijit) { this._searchDijitDomReady(searchWidget).then(lang.hitch(this, function(){ this.resize(); })); }else{ this.resize(); } } } }))); this.own(on(this.widgetManager, 'widget-destroyed', lang.hitch(this, function(widgetId) { if(widgetId && widgetId === this._searchWidgetId) { this._detachSearchWidget(); this.resize(); } }))); var logoW = this.getLogoWidth() + 'px'; if (this.position && this.position.height) { this.height = this.position.height; } this.switchableElements.logo = query('.logo', this.domNode); this.switchableElements.title = query('.jimu-title', this.domNode); //this.switchableElements.links = query('.links', this.domNode); this.switchableElements.subtitle = query('.jimu-subtitle', this.domNode); this._handleTitleColorAndLogoLink(this.appConfig); this.switchableElements.logo.style({ height: logoW }); this._setElementsSize(); }, _attachSearchWidget: function(searchWidget) { if(!searchWidget) { searchWidget = this._getSearchWidgetInHeader(); } if(!searchWidget || html.isDescendant(searchWidget.domNode, this.searchNode)) { return; } searchWidget.domNode.style.position = 'relative'; searchWidget.domNode.style.left = 'auto'; searchWidget.domNode.style.right = 'auto'; searchWidget.domNode.style.top = 'auto'; searchWidget.domNode.style.bottom = 'auto'; searchWidget.domNode.style.width = '280px'; html.place(searchWidget.domNode, this.searchNode); this._boxSizes.searchWidgetBox = {w: 280, h: 30}; }, _detachSearchWidget: function() { html.empty(this.searchNode); this._boxSizes.searchWidgetBox = {w: 0, h: 0}; }, _getSearchWidgetInHeader: function() { var result; var searchWidgets = this.widgetManager.getWidgetsByName('Search'); array.some(searchWidgets, lang.hitch(this, function(widget) { if (!widget.closeable && widget.isOnScreen) { result = widget; this._searchWidgetId = widget.id; return true; } })); return result; }, startup: function() { this.inherited(arguments); // Update UI: // Logo if (this.appConfig && this.appConfig.logo) { this.logoNode.src = this.appConfig.logo; this.own(on(this.logoNode, "load", lang.hitch(this, function () { this._boxSizes.logoBox = html.getMarginSize(this.logoWrapperNode); this.resize(); }))); html.removeClass(this.logoWrapperNode, 'hide-logo'); } else { this.logoNode.src = ""; html.addClass(this.logoWrapperNode, 'hide-logo'); } // Title this.switchableElements.title.innerHTML( utils.sanitizeHTML(this.appConfig.title ? this.appConfig.title : '') ); // Subtitle this.switchableElements.subtitle.innerHTML( utils.sanitizeHTML(this.appConfig.subtitle ? this.appConfig.subtitle : '') ); // Links this._createDynamicLinks(this.appConfig.links); // About if (this.appConfig.about) { html.setStyle(this.aboutNode, 'display', ''); } else { html.setStyle(this.aboutNode, 'display', 'none'); } // Show links placeholder button (if needed) this._determineLinksButtonVisibility(this.appConfig.links); }, _searchDijitDomReady: function(searchWidget) { var timeCounter = 0; var def = new Deferred(); // Check if searchDijit has been initialized within the search widget every 200 ms var checkSearchDijitTimer = setInterval(lang.hitch(this, function(){ if(timeCounter > 5000 || searchWidget.searchDijit) { // stop watching and resize UI clearInterval(checkSearchDijitTimer); def.resolve(); }else { timeCounter += 200; } }), 200); return def; }, onAppConfigChanged: function(appConfig, reason, changedData) { switch (reason) { case 'attributeChange': this._onAttributeChange(appConfig, changedData); this._updateBoxsizes(); this.resize(); break; case 'widgetChange': if(changedData.name === 'Search'){ this.resize(); } break; default: return; } this.appConfig = appConfig; }, _onAttributeChange: function(appConfig, changedData) { /*jshint unused: false*/ if ('title' in changedData && changedData.title !== this.appConfig.title) { this.switchableElements.title.innerHTML(utils.sanitizeHTML(changedData.title)); html.setStyle(this.titleNode, { display: changedData.title ? '' : 'none' }); } if ('subtitle' in changedData && changedData.subtitle !== this.appConfig.subtitle) { this.switchableElements.subtitle.innerHTML(utils.sanitizeHTML(changedData.subtitle)); html.setStyle(this.subtitleNode, { display: changedData.subtitle ? '' : 'none' }); } if (html.getStyle(this.titleNode, 'display') !== 'none' || html.getStyle(this.subtitleNode, 'display') !== 'none') { html.setStyle(this.titlesNode, 'width', '1000px'); } if ('logo' in changedData && changedData.logo !== this.appConfig.logo) { if(changedData.logo){ html.setAttr(this.logoNode, 'src', changedData.logo); html.removeClass(this.logoWrapperNode, 'hide-logo'); }else{ html.removeAttr(this.logoNode, 'src'); html.addClass(this.logoWrapperNode, 'hide-logo'); } } if ('links' in changedData) { this._createDynamicLinks(changedData.links); this._determineLinksButtonVisibility(changedData.links); } this._handleTitleColorAndLogoLink(appConfig); }, _handleTitleColorAndLogoLink: function(appConfig){ if(appConfig.titleColor){ html.setStyle(this.switchableElements.title, 'color', appConfig.titleColor); }else{ html.setStyle(this.switchableElements.title, 'color', ''); } if(appConfig.logoLink){ html.setAttr(this.logoLinkNode, 'href', appConfig.logoLink); html.setStyle(this.logoNode, 'cursor', 'pointer'); }else{ html.setAttr(this.logoLinkNode, 'href', 'javascript:void(0)'); html.setStyle(this.logoNode, 'cursor', 'default'); } }, _setElementsSize: function() { // Logo html.setStyle(this.logoNode, { height: '30px', marginTop: ((this.getLogoWidth() - 30) / 2) + 'px' }); // Title html.setStyle(this.titleNode, { lineHeight: this.height + 'px' }); // Subtitle html.setStyle(this.subtitleNode, { lineHeight: this.height + 'px' }); }, _createDynamicLinks: function(links) { html.empty(this.dynamicLinksNode); array.forEach(links, function(link) { html.create('a', { href: link.url, target: '_blank', rel: "noopener noreferrer", innerHTML: utils.sanitizeHTML(link.label), 'class': "link" }, this.dynamicLinksNode); }, this); }, _determineLinksButtonVisibility: function(links) { if(links.length || this.appConfig.about) { this._showLinksIcon(); }else { this._hideLinksIcon(); } }, _showLinksIcon: function() { html.setAttr(this.linksIconImageNode, 'src', this.folderUrl + 'images/link_icon.png'); html.setStyle(this.linksIconNode, 'display', 'block'); html.addClass(winBase.body(), 'header-has-links'); if(!this.linksIconClicked) { this.linksIconClicked = on(this.linksIconNode, 'click', lang.hitch(this, function() { this._toggleLinksMenu(); })); } }, _hideLinksIcon: function() { html.setStyle(this.linksIconNode, 'display', 'none'); html.removeClass(winBase.body(), 'header-has-links'); }, _toggleLinksMenu: function() { html.toggleClass(this.linksNode, 'hidden'); }, _onAboutClick: function() { var widgetConfig = { id: this.appConfig.about + '_1', uri: this.appConfig.about, label: 'About' }; this.widgetManager.loadWidget(widgetConfig).then(lang.hitch(this, function(widget) { html.place(widget.domNode, jimuConfig.layoutId); widget.startup(); })); }, _updateBoxsizes: function() { var logoBox = this._boxSizes.logoBox; if (html.getStyle(this.logoWrapperNode, 'display') !== 'none') { logoBox = html.getMarginSize(this.logoWrapperNode); } else { logoBox = {w:0, h: 0}; } this._boxSizes.logoBox = logoBox; var titleBox = this._boxSizes.titleBox; if (html.getStyle(this.titleNode, 'display') !== 'none' && this.switchableElements.title.innerHTML()){ titleBox = html.getMarginSize(this.titleNode); } if(!titleBox) { titleBox = {w:0, h: 0}; } this._boxSizes.titleBox = titleBox; var subTitleBox = this._boxSizes.subTitleBox; if(html.getStyle(this.subtitleNode, 'display') !== 'none' && this.switchableElements.subtitle.innerHTML()) { subTitleBox = html.getMarginSize(this.subtitleNode); } if (!subTitleBox) { subTitleBox = {w:0, h: 0}; } this._boxSizes.subTitleBox = subTitleBox; html.setStyle(this.titlesNode, 'width', 'auto'); var LinksIconBox = this._boxSizes.LinksIconBox; // "w:10": leave some space to the edge if(this.linksIconNode.style.display !== 'none') { LinksIconBox = html.getMarginSize(this.linksIconNode); } else { LinksIconBox = {w:0, h: 0}; } this._boxSizes.LinksIconBox = LinksIconBox; if (!this._boxSizes.searchWidgetBox) { this._boxSizes.searchWidgetBox = {w: 0, h: 0}; } }, setPosition: function(position, containerNode){ //For on-screen off-panel widget, layout manager will call this function //to set widget's position after load widget. If your widget will position by itself, //please override this function. this.position = position; var style = utils.getPositionStyle(this.position); style.position = 'absolute'; style.width = 'auto'; if(!containerNode){ if(position.relativeTo === 'map'){ containerNode = window.jimuConfig.mapId; }else{ containerNode = window.jimuConfig.layoutId; } } html.place(this.domNode, containerNode); html.setStyle(this.domNode, style); if(this.started){ setTimeout(lang.hitch(this, this.resize), 200); } }, resize: function() { if(!this._started){ return; } if (!this._boxSizes.logoBox || !this._boxSizes.titleBox || !this._boxSizes.subTitleBox || !this._boxSizes.searchWidgetBox || !this._boxSizes.LinksIconBox) { this._updateBoxsizes(); } var boxSizes = this._boxSizes; // whether the app is in mobile mode if(window.appInfo.isRunInMobile){ html.addClass(winBase.body(), 'is-mobile'); this._detachSearchWidget(); }else { html.removeClass(winBase.body(), 'is-mobile'); this._attachSearchWidget(); // Space reserved to show off screen widget icons to the right of the header var winBox = win.getBox(); var offsetRight = 300, left = 15; // Total width of the content in the header // var contentPadding = 20; var contentWidth = boxSizes.logoBox.w + boxSizes.titleBox.w + boxSizes.subTitleBox.w + boxSizes.searchWidgetBox.w + boxSizes.LinksIconBox.w; if (contentWidth === 0) { html.setStyle(this.domNode, 'visibility', 'hidden'); return; } else { html.setStyle(this.domNode, 'visibility', 'visible'); } if (contentWidth === boxSizes.logoBox.w || contentWidth === boxSizes.LinksIconBox.w) { html.setStyle(this.titlesNode, 'display', 'none'); } else { html.setStyle(this.titlesNode, 'display', 'flex'); } if(left + contentWidth + offsetRight < winBox.w) { // enough space to show everything this.titleNode.style.display = 'block'; this.subtitleNode.style.display = 'block'; } else { if(left + contentWidth - boxSizes.subTitleBox.w + offsetRight < winBox.w) { // not enough space to show subtitle this.titleNode.style.display = 'block'; this.subtitleNode.style.display = 'none'; } else { // not enough space to show tile and subtitle this.titleNode.style.display = 'none'; this.subtitleNode.style.display = 'none'; } } } }, getHeaderHeight: function() { return 44; }, getLogoWidth: function() { return 50; }, getLinksWidth: function() { return 36; }, destroy: function() { this.inherited(arguments); } }); return clazz; });