/////////////////////////////////////////////////////////////////////////// // 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/on', 'dojo/dom-style', 'dojo/dom-class', 'dojo/dom-construct', 'dojo/dom-geometry', 'dojo/mouse', 'dojo/_base/fx', 'dojo/fx', 'dojo/dnd/move', 'dojo/Deferred', 'dojox/layout/ResizeHandle', 'jimu/utils', 'jimu/BaseWidgetPanel', 'dijit/_TemplatedMixin', 'dojo/text!./Panel.html' ], function(declare, lang, on, domStyle, domClass, domConstruct, domGeometry, mouse, baseFx, coreFx, Move, Deferred, ResizeHandle, utils, BaseWidgetPanel, _TemplatedMixin, template) { /* global jimuConfig*/ var DEFAULT_WIDTH = 350, DEFAULT_HEIGHT = 480, MARGIN_LEFT = 50; return declare([BaseWidgetPanel, _TemplatedMixin], { baseClass: 'jimu-panel jimu-launchpad-panel', templateString: template, titleHeight: 33, normalPosition: null, lastWindowState: null, openAnimation: 'fadeIn', closeAnimation: 'fadeOut', animationDuration: 400, _device: 'desktop', // 'desktop' or 'mobile' postCreate: function(){ this.inherited(arguments); this._makeOriginalBox(); domStyle.set(this.colorfulHeader, 'background-color', this.config.backgroundColor || '#FFFFFF'); this.own(on(this.iconNode, mouse.enter, lang.hitch(this, function(){ if (this.windowState === 'minimized') { this.disableMoveable(); } }))); this.own(on(this.iconNode, mouse.leave, lang.hitch(this, function(){ if (this.windowState === 'minimized') { this.makeMoveable(this.domNode, 40, 40); } }))); this.own(on(this.iconNode, 'click', lang.hitch(this, function(){ if (this.windowState === 'minimized') { this.panelManager.normalizePanel(this); domStyle.set(this.domNode, 'overflow', 'visible'); } }))); }, startup: function(){ this.inherited(arguments); this.panelManager.normalizePanel(this); }, _makeOriginalBox: function() { this._originalBox = { w: this.position.width || DEFAULT_WIDTH, h: this.position.height || DEFAULT_HEIGHT, l: this.position.left || 0, t: this.position.top || 0 }; }, makeMoveable: function(handleNode, width, tolerance) { this.disableMoveable(); var containerBox = this._getLayoutBox(); containerBox.l = containerBox.l - width + tolerance; containerBox.w = containerBox.w + 2 * (width - tolerance); this.moveable = new Move.boxConstrainedMoveable(this.domNode, { box: containerBox, handle: handleNode || this.titleNode, within: true }); this.own(on(this.moveable, 'MoveStart', lang.hitch(this, this.onMoveStart))); this.own(on(this.moveable, 'Moving', lang.hitch(this, this.onMoving))); this.own(on(this.moveable, 'MoveStop', lang.hitch(this, this.onMoveStop))); }, disableMoveable: function() { if (this.moveable) { this.moveable.destroy(); this.moveable = null; } }, makeResizable: function() { this.disableResizable(); this.resizeHandle = new ResizeHandle({ targetId: this, minWidth: this._originalBox.w, minHeight: this._originalBox.h, activeResize: false }).placeAt(this.domNode); this.resizeHandle.startup(); }, disableResizable: function() { if (this.resizeHandle) { this.resizeHandle.destroy(); this.resizeHandle = null; } }, onMoveStart: function(mover){ if(window.isRTL){ var containerBox = this._getLayoutBox(), domBox = domGeometry.getMarginBox(this.domNode), rightPx = domStyle.get(mover.node, 'right'); domStyle.set(mover.node, 'left', (containerBox.w - domBox.w - parseInt(rightPx, 10)) + 'px'); domStyle.set(mover.node, 'right', ''); } }, onMoving: function(){ domStyle.set(this.domNode, 'opacity', 0.9); }, onMoveStop: function(){ var panelBox; domStyle.set(this.domNode, 'opacity', 1); panelBox = domGeometry.getMarginBox(this.domNode); this.position.left = panelBox.l; this.position.top = panelBox.t; }, _getLayoutBox: function() { //This panel's position always relates to map. return domGeometry.getMarginBox(jimuConfig.mapId); }, _onMinNodeClick: function(){ this.panelManager.minimizePanel(this); domStyle.set(this.domNode, 'overflow', 'hidden'); }, _onMaxNodeClick: function(){ if(this.windowState === 'normal') { this.panelManager.maximizePanel(this); domClass.add(this.maxNode, 'maximized'); } else if(this.windowState === 'maximized'){ this.panelManager.normalizePanel(this); domClass.remove(this.maxNode, 'maximized'); } }, _onCloseBtnClicked: function(evt) { evt.stopPropagation(); this.panelManager.closePanel(this, 'wipe'); }, _minimize: function(){ this.disableMoveable(); this.disableResizable(); var def = new Deferred(), animArray = []; animArray.push(baseFx.animateProperty({ node: this.domNode, properties: { height: 40, width: 40 }, duration: this.animationDuration, onEnd: lang.hitch(this, function(){ domStyle.set(this.containerNode, 'display', 'none'); domStyle.set(this.domNode, 'border-radius', '50%'); domStyle.set(this.domNode, '-webkit-border-radius', '50%'); this.makeMoveable(this.domNode, 40, 40); }) })); animArray.push(baseFx.animateProperty({ node: this.titleNode, properties: { height: 40, width: 40, 'background-color': this.config.backgroundColor }, duration: this.animationDuration, onEnd: lang.hitch(this, function(){ domClass.remove(this.titleNode, 'jimu-main-background'); }) })); animArray.push(baseFx.animateProperty({ node: this.iconNode, properties: { height: 20, width: 20 }, duration: this.animationDuration, onEnd: function(){ def.resolve(); } })); coreFx.combine(animArray).play(); return def; }, _maximize: function(){ var box = this._getLayoutBox(), def = new Deferred(); baseFx.animateProperty({ node: this.domNode, properties: { top: 0, height: box.h, width: box.w }, duration: this.animationDuration, onEnd: function(){ def.resolve(); } }).play(); return def; }, _normalize: function(){ var box, width, def = new Deferred(), animArray = []; domStyle.set(this.containerNode, 'display', ''); domStyle.set(this.domNode, 'border-radius', ''); domStyle.set(this.domNode, '-webkit-border-radius', ''); if(window.appInfo.isRunInMobile){ box = this._getLayoutBox(); width = box.w; animArray.push(baseFx.animateProperty({ node: this.domNode, properties: { height: box.h / 2, width: width, left: 0, top: box.h / 2 }, duration: this.animationDuration, onEnd: function(){ def.resolve(); } })); }else{ width = this.position.width; animArray.push(baseFx.animateProperty({ node: this.domNode, properties: { height: this.position.height, width: width }, duration: this.animationDuration, onEnd: function(){ def.resolve(); } })); } animArray.push(baseFx.animateProperty({ node: this.titleNode, properties: { height: 30, width: width }, duration: this.animationDuration, onEnd: lang.hitch(this, function(){ domStyle.set(this.titleNode, 'background-color', ''); domStyle.set(this.titleNode, 'width', '100%'); domClass.add(this.titleNode, 'jimu-main-background'); }) })); animArray.push(baseFx.animateProperty({ node: this.iconNode, properties: { height: 16, width: 16 }, duration: this.animationDuration })); coreFx.combine(animArray).play(); return def; }, _setPositionStyle: function(pos){ var style; if(this.position.zIndex){ pos.zIndex = this.position.zIndex; } this.position.left = pos.left; this.position.top = pos.top; this.position.width = pos.width; this.position.height = pos.height; style = utils.getPositionStyle(pos); lang.mixin(style, pos.borderRadiusStyle); domStyle.set(this.domNode, style); }, onWindowResize: function(){ var position = {}, box; if(this.windowState === 'minimized'){ return; //do nothing if panel is minimized. } if(window.appInfo.isRunInMobile){ box = this._getLayoutBox(); if(this.windowState === 'maximized'){ position.top = 0; position.height = box.h; }else{ position.top = box.h / 2; position.height = box.h / 2; } domStyle.set(this.domNode, { left: 0, top: position.top + 'px', right: 0, height: position.height + 'px', width: 'auto' }); this.resize(); if(this._device !== 'mobile'){ this._device = 'mobile'; this._onResponsible(); } }else{ if(this._device !== 'desktop'){ this._device = 'desktop'; position = lang.clone(this.position); this.setWindowState('normal'); domStyle.set(this.domNode, { left: position.left + 'px', top: position.top + 'px', height: position.height + 'px', width: position.width + 'px' }); this.resize(); this._onResponsible(); } } }, /** * @override * @param {Object} position contains these fields: left, top, width, height, * margin and index * @param {[type]} containerNode [description] */ setPosition: function(position){ var style, box, row, col, size; box = this._getLayoutBox(); size = Math.floor(box.w / (position.width + position.margin)); row = Math.floor(position.index / size); col = position.index % size; position.left = (row + 1) * position.margin + col * (position.width + position.margin) + MARGIN_LEFT; position.top -= position.margin * row; this.position = lang.clone(position); if(window.appInfo.isRunInMobile){ position.left = 0; position.top = box.h / 2; position.width = box.w; position.height = box.h / 2; } style = utils.getPositionStyle(position); style.position = 'absolute'; domConstruct.place(this.domNode, jimuConfig.mapId); domStyle.set(this.domNode, style); this._onResponsible(); }, /** * @override * @return {[type]} [description] */ onNormalize: function(){ this._normalize().then(lang.hitch(this, function(){ domStyle.set(this.iconNode, 'cursor', 'default'); domClass.remove(this.domNode, 'minimized'); domClass.remove(this.domNode, 'maximized'); this.resize(); this._onResponsible(); })); }, /** * @override * @return {[type]} [description] */ onMinimize: function(){ this.inherited(arguments); this._minimize().then(lang.hitch(this, function(){ domStyle.set(this.iconNode, 'cursor', 'pointer'); domClass.remove(this.domNode, 'maximized'); domClass.add(this.domNode, 'minimized'); })); }, /** * Restore windowState to "normal" when user closes this panel * @return {[type]} [description] */ onClose: function(){ this.inherited(arguments); this.setWindowState('normal'); this.onNormalize(); }, onMaximize: function(){ this.inherited(arguments); this._maximize().then(lang.hitch(this, function(){ domStyle.set(this.iconNode, 'cursor', 'default'); domClass.remove(this.domNode, 'minimized'); domClass.add(this.domNode, 'maximized'); this.resize(); })); }, /** * @override * @return {[type]} [description] */ resize: function(tmp) { var pos, style; if(!tmp){ this.inherited(arguments); return; } pos = { left: tmp.l ? tmp.l : this.position.left, top: tmp.t ? tmp.t : this.position.top, width: tmp.w ? tmp.w : this.position.width, height: tmp.h ? tmp.h : this.position.height, zIndex: this.position.zIndex }; this.position = pos; style = utils.getPositionStyle(this.position); if(window.isRTL && 'right' in style){ style.left = style.right; style.right = ''; } domStyle.set(this.domNode, style); this.inherited(arguments); }, _onResponsible: function() { if(window.appInfo.isRunInMobile){ if (this.windowState !== 'minimized') { this.disableMoveable(); } this.disableResizable(); domStyle.set(this.maxNode, 'display', ''); domStyle.set(this.minNode, 'margin', '0 10px'); } else { domStyle.set(this.maxNode, 'display', 'none'); domStyle.set(this.minNode, 'margin', ''); this.makeResizable(); this.makeMoveable(this.titleLabelNode, this.position.width, this.position.width * 0.25); } } }); });