define(['dojo/_base/declare', 'dojo/_base/lang', 'dojo/_base/array', 'dojo/dom-geometry', 'dojo/dom-style', 'dojo/dom-class', 'dojo/dom-construct', 'dojo/fx', 'dojo/on', 'dojo/query', 'dojo/aspect', 'jimu/BaseWidget', 'jimu/PoolControllerMixin', './DockableItem', './GroupItems', './PopupMoreNodes' ], function(declare, lang, array, domGeometry, domStyle, domClass, domConstruct, coreFx, on, query, aspect, BaseWidget, PoolControllerMixin, DockableItem, GroupItems, PopupMoreNodes){ /* global jimuConfig*/ var MIN_MARGIN = 8, ICON_SIZE = 40, ICON_IMG_SIZE = 20, BUTTON_SIZE = 60, NORMAL_MODE = 1, MOBILE_MODE = 2; /** * @exports themes/LaunchpadTheme/widgets/AnchorBarController/Widget */ var clazz = declare([BaseWidget, PoolControllerMixin], { baseClass: 'jimu-anchorbar-controller', visibleIcons: 0, iconList: [], enableNext: false, enablePrevious: false, currentMode: NORMAL_MODE, iconMargin: MIN_MARGIN, groupList: [], openedIds: [], currentStyle: 'default', postCreate: function(){ this.inherited(arguments); this.iconList = []; this.groupList = []; this.openedIds = []; this.currentStyle = this.appConfig.theme.styles[0]; this.allConfigs = this.getAllConfigs(); array.forEach(this.allConfigs, function(configItem, index){ this._createItem(configItem, index); }, this); }, _createItem: function(configItem, index){ var item, itemGroup, containerNode; item = new DockableItem({ config: configItem, backgroundIndex: index }); item.placeAt(this.iconGroupNode); this.iconList.push(item); if(item.isGroup()){ //create widget group icon itemGroup = new GroupItems({ config: configItem, dockableItem: item }); if(window.appInfo.isRunInMobile){ containerNode = jimuConfig.layoutId; }else{ containerNode = jimuConfig.mapId; } itemGroup.placeAt(containerNode); domStyle.set(itemGroup.domNode, 'display', 'none'); this.own(on(itemGroup, 'groupItemClicked', lang.hitch(this, function(data){ this._onDockableNodeClick(data.target); }))); this.own(on(item, 'nodeClick', lang.hitch(this, function(data){ this._onGroupNodeClick(data.target, itemGroup); }))); this.groupList.push(itemGroup); }else{ this.own(on(item, 'nodeClick', lang.hitch(this, function(data){ this._onDockableNodeClick(data.target); }))); } return item; }, startup: function() { this.inherited(arguments); this.resize(); // handle open at start widget, only one is allowed to open at start array.some(this.iconList, function(iconItem, index){ if(iconItem.isOpenAtStart()){ if(!window.appInfo.isRunInMobile){ this._makeIconVisible(index); } iconItem._onNodeClick(); return true; } }, this); }, destroy: function(){ this.inherited(arguments); array.forEach(this.groupList, function(widgetGroup){ widgetGroup.destroy(); }); }, onAction: function(action, data) { /*jshint unused: false*/ if (action === 'highLight' && data) { var node = query('div[settingid="' + data.widgetId + '"]', this.domNode)[0]; this._highLight(node); } if (action === 'removeHighLight') { this._removeHighLight(); } }, onOpen: function(){ if(this.iconList.length === 0 && this.appConfig.mode !== 'config'){ this.widgetManager.closeWidget(this); } }, onAppConfigChanged: function(appConfig){ this.currentStyle = appConfig.theme.styles[0]; }, /** * @override * @param {[type]} ids [description] */ setOpenedIds: function(ids) { var item; if (ids.length === 0) { return; } array.forEach(ids, function(id){ item = this._getIconItemById(id); if(item !== null){ item._onNodeClick(); } }, this); }, getOpenedIds: function() { this.inherited(arguments); return array.filter(this.openedIds, function(item){ return typeof item !== 'undefined'; }); }, _highLight: function(node) { if (this.hlDiv) { this._removeHighLight(); } if (!node || domStyle.get(node, 'display') === 'none') { return; } var marginLeft = domStyle.get(node, 'margin-left'); var position = domGeometry.getMarginBox(node); var hlStyle = { position: 'absolute', left: (position.l + marginLeft) + 'px', top: (position.t) + 'px', width: ICON_SIZE + 'px', height: ICON_SIZE + 'px' }; if(this.currentStyle !== 'style2'){ hlStyle['margin-top'] = (-ICON_SIZE / 2) + 'px'; } this.hlDiv = domConstruct.create('div', { "style": hlStyle, "class": 'icon-highlight' }, node, 'before'); }, _removeHighLight: function() { if (this.hlDiv) { domConstruct.destroy(this.hlDiv); this.hlDiv = null; } }, clearIconGroupNode: function(){ while(this.iconGroupNode.firstChild) { this.iconGroupNode.removeChild(this.iconGroupNode.firstChild); } }, resize: function(){ if(window.appInfo.isRunInMobile){ if(this.currentMode === NORMAL_MODE){ //mode changed this.currentMode = MOBILE_MODE; domClass.add(this.domNode, 'mobile'); this.clearIconGroupNode(); this.lastVisibleIcons = 0; } if(this.popupMore){ this.popupMore.hide(); } this.switchToMobileStyle(); }else{ if(this.currentMode === MOBILE_MODE){ //mode changed this.currentMode = NORMAL_MODE; domClass.remove(this.domNode, 'mobile'); this.clearIconGroupNode(); this.lastVisibleIcons = 0; //set width of iconGroupNode large enough to hold all the icons domStyle.set(this.iconGroupNode, 'width', this.allConfigs.length * 2 * ICON_SIZE + 'px'); array.forEach(this.iconList, function(iconItem){// recreate icon list once iconItem.placeAt(this.iconGroupNode); }, this); } this.switchToNormalStyle(); } this._resizeOpenedPanel(); }, switchToMobileStyle: function(){ var mapBox, containerSize, iconGroupWidth; mapBox = domGeometry.getContentBox(jimuConfig.mapId); containerSize = mapBox.w; iconGroupWidth = Math.max(containerSize, this.allConfigs.length * 2 * ICON_SIZE); //set width of iconGroupNode large enough to hold all the icons domStyle.set(this.iconGroupNode, 'width', iconGroupWidth + 'px'); //calculate widgets this.visibleIcons = Math.floor(containerSize / (ICON_SIZE + MIN_MARGIN)); if(this.visibleIcons >= this.iconList.length){ this.visibleIcons = this.iconList.length; } if(this.visibleIcons !== this.lastVisibleIcons){ this.lastVisibleIcons = this.visibleIcons; this.clearIconGroupNode(); this._reArrangeIconItems(containerSize); }else{ this._adjustIconMargin(containerSize); } }, _reArrangeIconItems: function(currentWidth){ var showMore, normalIconNumber, moreIconItem, moreItemArray = [], args; showMore = this.visibleIcons < this.iconList.length; normalIconNumber = showMore ? (this.visibleIcons - 1) : this.visibleIcons; this.iconMargin = Math.floor((currentWidth - (this.visibleIcons * ICON_SIZE)) / (this.visibleIcons + 1)); array.forEach(this.iconList, function(item, index){ //clear styles set in PopupMoreNodes.js args = { display: '', position: '', left: '', top: '' }; //reset the size of iconItem and image domStyle.set(item.iconItemNode, { width: ICON_SIZE + 'px', height: ICON_SIZE + 'px' }); domStyle.set(item.imgNode, { width: ICON_IMG_SIZE + 'px', height: ICON_IMG_SIZE + 'px' }); if(index < normalIconNumber){ if(window.isRTL){ args['margin-right'] = this.iconMargin + 'px'; }else{ args['margin-left'] = this.iconMargin + 'px'; } domStyle.set(item.domNode, args); item.placeAt(this.iconGroupNode); }else{ domStyle.set(item.domNode, args); moreItemArray.push(item); } }, this); if(showMore){ moreIconItem = this._createIconItemForMore(); args = {}; if(window.isRTL){ args['margin-right'] = this.iconMargin + 'px'; }else{ args['margin-left'] = this.iconMargin + 'px'; } domStyle.set(moreIconItem.domNode, args); moreIconItem.placeAt(this.iconGroupNode); this.own(on(moreIconItem, 'nodeClick', lang.hitch(this, function(data){ this._onShowMoreNodeClick(data.target, moreItemArray); }))); } }, _createIconItemForMore: function(){ var moreIconItem = new DockableItem({ config: { id: 'show_more_widget_icons', label: this.nls.more, icon: this.folderUrl + 'images/more_icon.png' }, backgroundIndex: this.visibleIcons }); return moreIconItem; }, _adjustIconMargin: function(currentWidth){ var args = {}; this.iconMargin = Math.floor((currentWidth - (this.visibleIcons * ICON_SIZE)) / (this.visibleIcons + 1)); if(window.isRTL){ args['margin-right'] = this.iconMargin + 'px'; }else{ args['margin-left'] = this.iconMargin + 'px'; } query('div.jimu-anchorbar-iconitem', this.iconGroupNode).forEach(function(node){ domStyle.set(node, args); }, this); }, switchToNormalStyle: function(){ var mapBox, widgetWidth, left, containerSize, firstVisible = 0, lastVisible; mapBox = domGeometry.getContentBox(jimuConfig.mapId); widgetWidth = Math.floor(mapBox.w / 2); if(widgetWidth > this.allConfigs.length * (ICON_SIZE + MIN_MARGIN) + BUTTON_SIZE){ widgetWidth = this.allConfigs.length * (ICON_SIZE + MIN_MARGIN) + BUTTON_SIZE; } left = Math.floor((mapBox.w - widgetWidth) / 2); domStyle.set(this.domNode, { width: widgetWidth + 'px', left: left + 'px' }); //calculate widgets containerSize = widgetWidth - BUTTON_SIZE; this.visibleIcons = Math.floor(containerSize / (ICON_SIZE + MIN_MARGIN)); if(this.visibleIcons > this.iconList.length){ this.visibleIcons = this.iconList.length; } //calculate the visible range array.some(this.iconList, function(item, index){ if(item.visible){ firstVisible = index; return true; } }); lastVisible = firstVisible + this.visibleIcons - 1; if(lastVisible >= this.iconList.length){ lastVisible = this.iconList.length - 1; firstVisible = lastVisible - this.visibleIcons + 1; } this.iconMargin = Math.floor((containerSize - (this.visibleIcons * ICON_SIZE)) / (this.visibleIcons + 1)); this._adjustIconStyle(firstVisible, lastVisible); }, _previous: function(){ var idxFirst = -1, idxLast = -1, animArray = []; if(this.enablePrevious){ //find the first visible iconItem array.some(this.iconList, function(iconItem, index){ if(iconItem.visible){ idxFirst = index - 1;//get the previous item index return true; } }, this); if(idxFirst >= 0){ idxLast = idxFirst + this.visibleIcons; animArray = animArray.concat(this.iconList[idxLast].hideAnim(this.iconMargin), this.iconList[idxFirst].showAnim(this.iconMargin)); coreFx.combine(animArray).play(); this.enableNext = true; domClass.add(this.nextButton, 'enabled'); if(idxFirst === 0){ this.enablePrevious = false; domClass.remove(this.previousButton, 'enabled'); } } } }, _next: function(){ var idxFirst = -1, idxLast = -1, animArray = []; if(this.enableNext){ //find the first visible iconItem array.some(this.iconList, function(iconItem, index){ if(iconItem.visible){ idxFirst = index; return true; } }, this); if(idxFirst >= 0){ idxLast = idxFirst + this.visibleIcons; animArray = animArray.concat(this.iconList[idxFirst].hideAnim(this.iconMargin), this.iconList[idxLast].showAnim(this.iconMargin)); coreFx.combine(animArray).play(); this.enablePrevious = true; domClass.add(this.previousButton, 'enabled'); if(idxLast === this.iconList.length - 1){ this.enableNext = false; domClass.remove(this.nextButton, 'enabled'); } } } }, _getGroupPanelPosition: function(dockableItem, widgetBox){ var position = {}, iconBox = domGeometry.position(dockableItem.iconItemNode), mapBox = domGeometry.getContentBox(jimuConfig.mapId); position.top = iconBox.y - widgetBox.h - MIN_MARGIN; if (window.isRTL) { if(iconBox.x < widgetBox.w + MIN_MARGIN){ position.left = MIN_MARGIN; }else{ position.left = iconBox.x - widgetBox.w + iconBox.w; } } else { if(iconBox.x + widgetBox.w + MIN_MARGIN > mapBox.w){ position.left = mapBox.w - widgetBox.w - MIN_MARGIN; }else{ position.left = iconBox.x; } } return position; }, //off panel widget position _getOffPanelPosition: function(dockableItem, widgetBox){ var position = {}, iconBox = domGeometry.position(dockableItem.iconItemNode), mapBox = domGeometry.getContentBox(jimuConfig.mapId); position.bottom = mapBox.h - (iconBox.y + MIN_MARGIN) + ICON_SIZE / 2; if (window.isRTL) { if(iconBox.x < widgetBox.w + MIN_MARGIN){ position.right = mapBox.w - widgetBox.w - MIN_MARGIN; }else{ position.right = iconBox.x - widgetBox.w; } } else { if(iconBox.x + widgetBox.w + MIN_MARGIN > mapBox.w){ position.left = mapBox.w - widgetBox.w - MIN_MARGIN; }else{ position.left = iconBox.x; } } if(dockableItem.config.position) { position.relativeTo = dockableItem.config.position.relativeTo; } return position; }, _createPopupMoreNodes: function(){ if(!this.popupMore){ this._createCoverNode(); this.popupMore = new PopupMoreNodes(); this.popupMore.placeAt(jimuConfig.mapId); aspect.after(this.popupMore, 'show', lang.hitch(this, function() { domStyle.set(this.moreIconPaneCoverNode, 'display', ''); }), true); aspect.after(this.popupMore, 'hide', lang.hitch(this, function() { domStyle.set(this.moreIconPaneCoverNode, 'display', 'none'); }), true); } }, _onShowMoreNodeClick: function(dockableItem, moreItemsArray){ this._createPopupMoreNodes(); if(dockableItem.isOpen){ this.popupMore.setForIcon(dockableItem); this.popupMore.setNodes(moreItemsArray); this.popupMore.show(); }else{ this.popupMore.hide(); } }, _getIconItemById: function(id){ var ret = null; array.some(this.iconList, function(item){ if(item.config.id === id){ ret = item; return true; } }); if(ret === null){ array.some(this.groupList, function(groupItem){ return array.some(groupItem.getItemList(), function(item){ if(item.config.id === id){ ret = item; return true; } }); }); } return ret; }, _addToOpenedIds: function(id){ if(this.openedIds.indexOf(id) === -1){ this.openedIds.push(id); } }, _removeFromOpenedIds: function(id){ var idx = this.openedIds.indexOf(id); if(idx !== -1){ this.openedIds[idx] = undefined; } }, _onGroupNodeClick: function(dockableItem, groupItem){ var position; if(dockableItem.isOpen){ position = this._getGroupPanelPosition(dockableItem, groupItem.box); groupItem.setPosition(position); groupItem.open(); this._addToOpenedIds(dockableItem.config.id); }else{ groupItem.close(); this._removeFromOpenedIds(dockableItem.config.id); } }, _onDockableNodeClick: function(dockableItem){ var panelId, panelConfig; if(dockableItem.config.inPanel === false){ if(dockableItem.isOpen){ this.widgetManager.loadWidget(dockableItem.config).then( lang.hitch(this, function(widget) { this._addToOpenedIds(dockableItem.config.id); var position = this._getOffPanelPosition(dockableItem, this.widgetManager.getWidgetMarginBox(widget)); position.zIndex = 100; widget.setPosition(position, this.containerNode); this.widgetManager.openWidget(widget); this.own(aspect.after(widget, 'onClose', lang.hitch(this, function() { dockableItem.setOpened(false); this._removeFromOpenedIds(dockableItem.config.id); }))); })); }else{ this.widgetManager.closeWidget(dockableItem.config.id); this._removeFromOpenedIds(dockableItem.config.id); } }else{ panelId = dockableItem.config.id + '_panel'; if(dockableItem.isOpen){ dockableItem.setPanelIndex(this._calPanelIndex()); panelConfig = dockableItem.getConfigForPanel(); this.panelManager.showPanel(panelConfig).then(lang.hitch(this, function(panel){ panel.setPosition(panelConfig.panel.position); aspect.after(panel, 'onClose', lang.hitch(this, function(){ dockableItem.setOpened(false); this._removeFromOpenedIds(dockableItem.config.id); })); })); if(this.popupMore){ this.popupMore.hide(); } this._addToOpenedIds(dockableItem.config.id); }else{ this.panelManager.closePanel(panelId); this._removeFromOpenedIds(dockableItem.config.id); } } }, _calPanelIndex: function(){ var openedList = [], i, len; //collect panel index of opened widget. array.forEach(this.iconList, function(item){ if(!item.isGroup() && item.config.inPanel !== false && item.isOpen){ openedList.push(item.getPanelIndex()); } }); array.forEach(this.groupList, function(groupItem){ array.forEach(groupItem.getItemList(), function(item){ if(item.config.inPanel !== false && item.isOpen){ openedList.push(item.getPanelIndex()); } }); }); if(openedList.length === 0){ return 0; } //sort asc openedList.sort(function(a, b){ return a - b; }); //Find the smallest panel index that is not used. if(openedList[0] > 0){ return 0; } for(i = 0, len = openedList.length - 1 ; i < len; i++){ if(openedList[i + 1] - openedList[i] > 1){ return openedList[i] + 1; } } return openedList[len] + 1; }, _createCoverNode: function() { this.moreIconPaneCoverNode = domConstruct.create('div', { 'class': 'jimu-more-icon-cover' }, jimuConfig.layoutId); }, _resizeOpenedPanel: function(){ var panel; //collect panel index of opened widget. array.forEach(this.iconList, function(item){ if(!item.isGroup() && item.config.inPanel !== false && item.isOpen){ panel = this.panelManager.getPanelById(item.config.id + '_panel'); if(panel){ panel.onWindowResize(); } } }, this); array.forEach(this.groupList, function(groupItem){ array.forEach(groupItem.getItemList(), function(item){ if(item.config.inPanel !== false && item.isOpen){ panel = this.panelManager.getPanelById(item.config.id + '_panel'); if(panel){ panel.onWindowResize(); } } }, this); }, this); }, /** * Used by open at start widget. Make the widget icon at the center of the anchor bar. * @param {number} index [description] */ _makeIconVisible: function(index){ var firstVisible, lastVisible; if(this.visibleIcons === this.iconList.length){ return; } firstVisible = index - Math.floor(this.visibleIcons / 2); firstVisible = firstVisible >= 0 ? firstVisible : 0; lastVisible = firstVisible + this.visibleIcons - 1; if(lastVisible >= this.iconList.length){ lastVisible = this.iconList.length - 1; firstVisible = lastVisible - this.visibleIcons + 1; } this._adjustIconStyle(firstVisible, lastVisible); }, _adjustIconStyle: function(firstVisible, lastVisible){ var args; array.forEach(this.iconList, function(iconItem, index){ iconItem.visible = index >= firstVisible && index <= lastVisible; args = { position: '', left: '', top: '', display: iconItem.visible ? '' : 'none' }; if(window.isRTL){ args['margin-right'] = this.iconMargin + 'px'; }else{ args['margin-left'] = this.iconMargin + 'px'; } domStyle.set(iconItem.domNode, args); domStyle.set(iconItem.iconItemNode, { width: ICON_SIZE + 'px', height: ICON_SIZE + 'px' }); domStyle.set(iconItem.imgNode, { width: ICON_IMG_SIZE + 'px', height: ICON_IMG_SIZE + 'px' }); }, this); if(lastVisible < this.allConfigs.length - 1){ domClass.add(this.nextButton, 'enabled'); this.enableNext = true; }else{ domClass.remove(this.nextButton, 'enabled'); this.enableNext = false; } if(firstVisible > 0){ this.enablePrevious = true; domClass.add(this.previousButton, 'enabled'); }else{ this.enablePrevious = false; domClass.remove(this.previousButton, 'enabled'); } } }); return clazz; });