forked from phcode-dev/staging.phcode.dev
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathPanelView.js
More file actions
1 lines (1 loc) · 18.2 KB
/
PanelView.js
File metadata and controls
1 lines (1 loc) · 18.2 KB
1
define(function(require,exports,module){const EventDispatcher=require("utils/EventDispatcher"),PreferencesManager=require("preferences/PreferencesManager"),Resizer=require("utils/Resizer"),DropdownButton=require("widgets/DropdownButton"),Strings=require("strings"),EVENT_PANEL_HIDDEN="panelHidden",EVENT_PANEL_SHOWN="panelShown",PANEL_TYPE_BOTTOM_PANEL="bottomPanel";let _panelMap={},_$container,_$tabBar,_$tabsOverflow,_openIds=[],_activeId=null,_isMaximized=!1;const MAXIMIZE_THRESHOLD=2,MIN_PANEL_HEIGHT=200,PREF_BOTTOM_PANEL_MAXIMIZED="bottomPanelMaximized";let _preMaximizeHeight=null,_$editorHolder=null,_recomputeLayout=null,_defaultPanelId=null;function _getPanelTitle(id,$panel,title){if(title)return title;let $titleEl=$panel.find(".toolbar .title");if($titleEl.length&&$.trim($titleEl.text()))return $.trim($titleEl.text());let label=id.replace(new RegExp("[-_.]","g")," ").split(" ")[0];return label.charAt(0).toUpperCase()+label.slice(1)}function _buildTab(panel,isActive){let title=panel._tabTitle||_getPanelTitle(panel.panelID,panel.$panel);const isDefault=panel.panelID===_defaultPanelId;let $tab=$('<div class="bottom-panel-tab"></div>').toggleClass("bottom-panel-tab-default",isDefault).attr("draggable",isDefault?"false":"true").toggleClass("active",isActive).attr("data-panel-id",panel.panelID);const iconSrc=panel._options.iconSvg||"styles/images/panel-icon-default.svg",$icon=$('<span class="bottom-panel-tab-icon panel-titlebar-icon"></span>'),maskUrl="url('"+iconSrc+"')";return $icon[0].style.maskImage=maskUrl,$icon[0].style.webkitMaskImage=maskUrl,$tab.append($icon),isDefault?$tab.attr("title",title):($tab.append($('<span class="bottom-panel-tab-title"></span>').text(title)),$tab.append($('<span class="bottom-panel-tab-close-btn">×</span>').attr("title",Strings.CLOSE))),$tab}function _updateBottomPanelTabBar(){_$tabsOverflow&&(_$tabsOverflow.empty(),_openIds.forEach(function(panelId){let panel=_panelMap[panelId];panel&&_$tabsOverflow.append(_buildTab(panel,panelId===_activeId))}),_checkTabOverflow())}function _updateActiveTabHighlight(){_$tabBar&&_$tabBar.find(".bottom-panel-tab").each(function(){let $tab=$(this);$tab.data("panel-id")===_activeId?$tab.addClass("active"):$tab.removeClass("active")})}function _addTabToBar(panelId){if(!_$tabsOverflow)return;let panel=_panelMap[panelId];if(!panel)return;let $tab=_buildTab(panel,panelId===_activeId);_$tabsOverflow.append($tab),_checkTabOverflow()}function _removeTabFromBar(panelId){_$tabsOverflow&&(_$tabsOverflow.find('.bottom-panel-tab[data-panel-id="'+panelId+'"]').remove(),_checkTabOverflow())}function _initDragAndDrop(){let draggedTab=null,$indicator=$('<div class="tab-drag-indicator"></div>');function getDropPosition(targetTab,mouseX){const rect=targetTab.getBoundingClientRect();return mouseX<rect.left+rect.width/2}function updateIndicator(targetTab,insertBefore){if(!targetTab)return void $indicator.hide();const rect=targetTab.getBoundingClientRect();$indicator.css({position:"fixed",left:(insertBefore?rect.left:rect.right)+"px",top:rect.top+"px",height:rect.height+"px",width:"2px",zIndex:10001}).show()}function cleanup(){draggedTab&&$(draggedTab).removeClass("bottom-panel-tab-dragging"),draggedTab=null,$indicator.hide(),_$tabBar.find(".bottom-panel-tab").removeClass("drag-target")}function findNearestDropTarget(mouseX){let closest=null,closestDist=1/0;return _$tabsOverflow.find(".bottom-panel-tab").each(function(){if(this===draggedTab)return;if($(this).data("panel-id")===_defaultPanelId)return;const rect=this.getBoundingClientRect(),dist=Math.min(Math.abs(mouseX-rect.left),Math.abs(mouseX-rect.right));dist<closestDist&&(closestDist=dist,closest=this)}),closest}function reorderTabs(targetEl,mouseX){if(!draggedTab||targetEl===draggedTab)return;let draggedId=$(draggedTab).data("panel-id"),targetId=$(targetEl).data("panel-id"),fromIdx=_openIds.indexOf(draggedId),toIdx=_openIds.indexOf(targetId);if(-1===fromIdx||-1===toIdx)return;const insertBefore=getDropPosition(targetEl,mouseX);_openIds.splice(fromIdx,1);let newIdx=_openIds.indexOf(targetId);insertBefore||newIdx++,newIdx<1&&_defaultPanelId&&_openIds[0]===_defaultPanelId&&(newIdx=1),_openIds.splice(newIdx,0,draggedId),_updateBottomPanelTabBar(),_updateActiveTabHighlight()}$("body").append($indicator),_$tabBar.on("dragstart",".bottom-panel-tab",function(e){$(this).data("panel-id")!==_defaultPanelId?(draggedTab=this,e.originalEvent.dataTransfer.effectAllowed="move",e.originalEvent.dataTransfer.setData("application/x-phoenix-panel-tab","1"),$(this).addClass("bottom-panel-tab-dragging")):e.preventDefault()}),_$tabBar.on("dragend",".bottom-panel-tab",function(){setTimeout(cleanup,50)}),_$tabBar.on("dragover",".bottom-panel-tab",function(e){draggedTab&&this!==draggedTab&&$(this).data("panel-id")!==_defaultPanelId&&(e.preventDefault(),e.originalEvent.dataTransfer.dropEffect="move",_$tabBar.find(".bottom-panel-tab").removeClass("drag-target"),$(this).addClass("drag-target"),updateIndicator(this,getDropPosition(this,e.originalEvent.clientX)))}),_$tabsOverflow.on("dragover",function(e){if(!draggedTab)return;const $closestTab=$(e.target).closest(".bottom-panel-tab");if($closestTab.length&&$closestTab[0]!==draggedTab&&$closestTab.data("panel-id")!==_defaultPanelId)return;const nearest=findNearestDropTarget(e.originalEvent.clientX);nearest&&(e.preventDefault(),e.originalEvent.dataTransfer.dropEffect="move",_$tabBar.find(".bottom-panel-tab").removeClass("drag-target"),$(nearest).addClass("drag-target"),updateIndicator(nearest,getDropPosition(nearest,e.originalEvent.clientX)))}),_$tabBar.on("dragleave",".bottom-panel-tab",function(e){const related=e.originalEvent.relatedTarget;$(this).is(related)||$(this).has(related).length||$(this).removeClass("drag-target")}),_$tabBar.on("drop",".bottom-panel-tab",function(e){e.preventDefault(),e.stopPropagation(),draggedTab&&this!==draggedTab?(reorderTabs(this,e.originalEvent.clientX),cleanup()):cleanup()}),_$tabsOverflow.on("drop",function(e){if(!draggedTab)return void cleanup();const nearest=findNearestDropTarget(e.originalEvent.clientX);nearest&&(e.preventDefault(),e.stopPropagation(),reorderTabs(nearest,e.originalEvent.clientX)),cleanup()})}let _$overflowBtn=null,_checkTabOverflowTimer=null;function _checkTabOverflow(){_checkTabOverflowTimer&&cancelAnimationFrame(_checkTabOverflowTimer),_checkTabOverflowTimer=requestAnimationFrame(_doCheckTabOverflow)}function _doCheckTabOverflow(){if(_checkTabOverflowTimer=null,!_$tabBar)return;_$tabBar.removeClass("bottom-panel-tabs-collapsed");const isOverflowing=_$tabsOverflow[0].scrollWidth>_$tabsOverflow[0].clientWidth+1;_$tabBar.toggleClass("bottom-panel-tabs-collapsed",isOverflowing);const stillOverflowing=isOverflowing&&_$tabsOverflow[0].scrollWidth>_$tabsOverflow[0].clientWidth;_$overflowBtn&&_$overflowBtn.toggle(stillOverflowing),_$tabBar.find(".bottom-panel-tab").each(function(){const $tab=$(this);$tab.data("panel-id")!==_defaultPanelId&&(isOverflowing?$tab.attr("title",$tab.find(".bottom-panel-tab-title").text()):$tab.removeAttr("title"))})}function _getHiddenTabs(){const hidden=[],barRect=_$tabsOverflow[0].getBoundingClientRect();return _$tabsOverflow.find(".bottom-panel-tab").each(function(){const tabRect=this.getBoundingClientRect(),isVisible=tabRect.left>=barRect.left&&tabRect.right<=barRect.right+2;if(!isVisible){const $tab=$(this);hidden.push({panelId:$tab.data("panel-id"),title:$tab.find(".bottom-panel-tab-title").text()})}}),hidden}let _overflowDropdown=null;function _showOverflowMenu(){if(_overflowDropdown)return _overflowDropdown.closeDropdown(),void(_overflowDropdown=null);const hidden=_getHiddenTabs();if(!hidden.length)return;(_overflowDropdown=new DropdownButton.DropdownButton("",hidden,function(item){const panel=_panelMap[item.panelId],iconSrc=panel&&panel._options&&panel._options.iconSvg||"styles/images/panel-icon-default.svg",iconStyle="width:14px;height:14px;margin-right:6px;vertical-align:middle;mask-image:url('"+iconSrc+"');-webkit-mask-image:url('"+iconSrc+"')",iconHtml='<span class="panel-titlebar-icon" style="'+iconStyle+'"></span>',activeClass=item.panelId===_activeId?' style="font-weight:600"':"";return{html:'<div class="dropdown-tab-item"'+activeClass+">"+iconHtml+"<span>"+item.title+"</span></div>",enabled:!0}})).dropdownExtraClasses="dropdown-overflow-menu";const btnRect=_$overflowBtn[0].getBoundingClientRect();$("body").append(_overflowDropdown.$button),_overflowDropdown.$button.css({position:"absolute",left:btnRect.left+"px",top:btnRect.top-2+"px",zIndex:1e3}),_overflowDropdown.showDropdown(),_overflowDropdown.on("select",function(e,item){const panel=_panelMap[item.panelId];if(panel){panel.show();const $tab=_$tabsOverflow.find('.bottom-panel-tab[data-panel-id="'+item.panelId+'"]');$tab.length&&$tab[0].scrollIntoView({inline:"nearest"})}}),_overflowDropdown.on(DropdownButton.EVENT_DROPDOWN_CLOSED,function(){_overflowDropdown&&(_overflowDropdown.$button.remove(),_overflowDropdown=null)})}function _switchToTab(panelId){if(_activeId===panelId)return;if(_activeId){let prevPanel=_panelMap[_activeId];prevPanel&&prevPanel.$panel.removeClass("active-bottom-panel")}_activeId=panelId;let newPanel=_panelMap[panelId];newPanel&&newPanel.$panel.addClass("active-bottom-panel"),_updateActiveTabHighlight()}function Panel($panel,id,title,options){this.$panel=$panel,this.panelID=id,this._tabTitle=_getPanelTitle(id,$panel,title),this._options=options||{},_panelMap[id]=this,id===_defaultPanelId&&-1===_openIds.indexOf(id)&&(_openIds.unshift(id),_addTabToBar(id))}function init($container,$tabBar,$tabsOverflow,$editorHolder,recomputeLayoutFn,defaultPanelId){_$container=$container,_$tabsOverflow=$tabsOverflow,_$editorHolder=$editorHolder,_recomputeLayout=recomputeLayoutFn,_defaultPanelId=defaultPanelId,(_$tabBar=$tabBar).on("click",".bottom-panel-tab-close-btn",function(e){e.stopPropagation();let panelId=$(this).closest(".bottom-panel-tab").data("panel-id");if(panelId&&panelId!==_defaultPanelId){let panel=_panelMap[panelId];panel&&panel.requestClose()}}),_$tabBar.on("click",".bottom-panel-tab",function(e){let panelId=$(this).data("panel-id");if(panelId&&panelId!==_activeId){let panel=_panelMap[panelId];panel&&panel.show()}this.scrollIntoView({inline:"nearest"})}),_initDragAndDrop(),(_$overflowBtn=$('<span class="bottom-panel-overflow-btn" title="'+Strings.TABBAR_SHOW_HIDDEN_TABS+'"><i class="fa-solid fa-chevron-down"></i></span>')).hide(),_$tabBar.find(".bottom-panel-tab-bar-actions").before(_$overflowBtn),_$overflowBtn.on("click",function(e){e.stopPropagation(),_showOverflowMenu()}),_$tabBar.on("click",".bottom-panel-hide-btn",function(e){e.stopPropagation(),collapseContainer()}),_$tabBar.on("click",".bottom-panel-maximize-btn",function(e){e.stopPropagation(),_toggleMaximize()}),_$tabBar.on("dblclick",function(e){$(e.target).closest(".bottom-panel-tab, .bottom-panel-tab-close-btn, .bottom-panel-hide-btn, .bottom-panel-maximize-btn").length||_toggleMaximize()}),new ResizeObserver(_checkTabOverflow).observe(_$tabBar[0]),_isMaximized=!0===PreferencesManager.getViewState(PREF_BOTTOM_PANEL_MAXIMIZED),_$container.on("panelExpanded",function(){_isMaximized&&setTimeout(function(){let maxHeight=(_$editorHolder?_$editorHolder.height():0)+_$container.height();_$container.height(maxHeight),_updateMaximizeButton(),_recomputeLayout&&_recomputeLayout()},0)})}function _toggleMaximize(){_$container&&_$container.is(":visible")&&(_isMaximized?_restorePanel():_maximizePanel())}function _maximizePanel(){_preMaximizeHeight=_$container.height();let maxHeight=_$editorHolder.height()+_$container.height();_$container.height(maxHeight),_isMaximized=!0,PreferencesManager.setViewState(PREF_BOTTOM_PANEL_MAXIMIZED,!0),_updateMaximizeButton(),_recomputeLayout&&_recomputeLayout()}function _getDefaultRestoreHeight(){let totalHeight=(_$editorHolder?_$editorHolder.height():0)+(_$container?_$container.height():0);return Math.max(MIN_PANEL_HEIGHT,Math.round(totalHeight/3))}function _isNearMaxHeight(height){let totalHeight;return(_$editorHolder?_$editorHolder.height():0)+(_$container?_$container.height():0)-height<=MAXIMIZE_THRESHOLD}function _restorePanel(){let restoreHeight;restoreHeight=null===_preMaximizeHeight||_isNearMaxHeight(_preMaximizeHeight)?_getDefaultRestoreHeight():_preMaximizeHeight,_$container.height(restoreHeight),_isMaximized=!1,_preMaximizeHeight=null,PreferencesManager.setViewState(PREF_BOTTOM_PANEL_MAXIMIZED,!1),_updateMaximizeButton(),_recomputeLayout&&_recomputeLayout()}function _updateMaximizeButton(){if(!_$tabBar)return;let $btn=_$tabBar.find(".bottom-panel-maximize-btn"),$icon=$btn.find("i");_isMaximized?($icon.removeClass("fa-solid fa-expand").addClass("fa-solid fa-compress"),$btn.attr("title",Strings.BOTTOM_PANEL_RESTORE)):($icon.removeClass("fa-solid fa-compress").addClass("fa-solid fa-expand"),$btn.attr("title",Strings.BOTTOM_PANEL_MAXIMIZE))}function exitMaximizeOnResize(){_isMaximized&&(_isMaximized=!1,_preMaximizeHeight=null,PreferencesManager.setViewState(PREF_BOTTOM_PANEL_MAXIMIZED,!1),_updateMaximizeButton())}function enterMaximizeOnResize(){_isMaximized||(_isMaximized=!0,_preMaximizeHeight=null,PreferencesManager.setViewState(PREF_BOTTOM_PANEL_MAXIMIZED,!0),_updateMaximizeButton())}function restoreIfMaximized(){_isMaximized&&(null===_preMaximizeHeight||_isNearMaxHeight(_preMaximizeHeight)?_$container.height(_getDefaultRestoreHeight()):_$container.height(_preMaximizeHeight),_isMaximized=!1,_preMaximizeHeight=null,PreferencesManager.setViewState(PREF_BOTTOM_PANEL_MAXIMIZED,!1),_updateMaximizeButton())}function isMaximized(){return _isMaximized}function collapseContainer(){_$container&&_$container.is(":visible")&&(restoreIfMaximized(),Resizer.hide(_$container[0]),exports.trigger(EVENT_PANEL_HIDDEN,_defaultPanelId))}function restoreContainer(){_$container&&!_$container.is(":visible")&&(Resizer.show(_$container[0]),_activeId&&exports.trigger(EVENT_PANEL_SHOWN,_activeId))}function getOpenBottomPanelIDs(){return _openIds.slice()}function hideAllOpenPanels(){if(0===_openIds.length)return[];let closedIds=_openIds.slice();for(let i=0;i<closedIds.length;i++){let panel=_panelMap[closedIds[i]];panel&&panel.$panel.removeClass("active-bottom-panel")}_openIds=_defaultPanelId?[_defaultPanelId]:[],_activeId=null,_$container&&_$container.is(":visible")&&(restoreIfMaximized(),Resizer.hide(_$container[0])),_updateBottomPanelTabBar();for(let i=0;i<closedIds.length;i++)exports.trigger(EVENT_PANEL_HIDDEN,closedIds[i]);return closedIds}function getActiveBottomPanel(){return _activeId&&_panelMap[_activeId]?_panelMap[_activeId]:null}function showNextPanel(){if(_openIds.length<=0)return!1;const currentIdx=_activeId?_openIds.indexOf(_activeId):-1,nextIdx=(currentIdx+1)%_openIds.length,nextPanel=_panelMap[_openIds[nextIdx]];return nextPanel&&nextPanel.show(),!0}Panel.prototype.$panel=null,Panel.prototype.isVisible=function(){return _activeId===this.panelID&&_$container&&_$container.is(":visible")},Panel.prototype.registerCanBeShownHandler=function(canShowHandlerFn){this.canBeShownHandler&&canShowHandlerFn&&console.warn(`canBeShownHandler already registered for panel: ${this.panelID}. will be overwritten`),this.canBeShownHandler=canShowHandlerFn},Panel.prototype.canBeShown=function(){let self=this;return!self.canBeShownHandler||self.canBeShownHandler()},Panel.prototype.registerOnCloseRequestedHandler=function(handler){this._onCloseRequestedHandler&&handler&&console.warn(`onCloseRequestedHandler already registered for panel: ${this.panelID}. will be overwritten`),this._onCloseRequestedHandler=handler},Panel.prototype.requestClose=async function(){if(this._onCloseRequestedHandler){const allowed=await this._onCloseRequestedHandler();if(!allowed)return!1}return this.hide(),!0},Panel.prototype.show=function(){if(!this.canBeShown()||!_$container)return;let panelId=this.panelID,isOpen=-1!==_openIds.indexOf(panelId),isActive=_activeId===panelId;if(isOpen&&isActive)_$container.is(":visible")||(Resizer.show(_$container[0]),exports.trigger(EVENT_PANEL_SHOWN,panelId));else{if(isOpen&&!isActive)return _switchToTab(panelId),_$container.is(":visible")||Resizer.show(_$container[0]),void exports.trigger(EVENT_PANEL_SHOWN,panelId);panelId===_defaultPanelId?_openIds.unshift(panelId):_openIds.push(panelId),_$container.is(":visible")||Resizer.show(_$container[0]),_switchToTab(panelId),_addTabToBar(panelId),exports.trigger(EVENT_PANEL_SHOWN,panelId)}},Panel.prototype.addToTabBar=function(){_$container&&-1===_openIds.indexOf(this.panelID)&&(_openIds.push(this.panelID),_addTabToBar(this.panelID))},Panel.prototype.hide=function(){let panelId=this.panelID;if(panelId===_defaultPanelId){if(_activeId!==panelId)return;return this.$panel.removeClass("active-bottom-panel"),_activeId=null,_updateActiveTabHighlight(),_$container&&(restoreIfMaximized(),Resizer.hide(_$container[0])),void exports.trigger(EVENT_PANEL_HIDDEN,panelId)}let idx=_openIds.indexOf(panelId);if(-1===idx)return;_openIds.splice(idx,1),this.$panel.removeClass("active-bottom-panel");let wasActive=_activeId===panelId,activatedId=null;if(wasActive&&_openIds.length>0){let nextIdx=Math.min(idx,_openIds.length-1);activatedId=_openIds[nextIdx],_activeId=null,_switchToTab(activatedId)}else wasActive&&(_activeId=null,_$container&&(restoreIfMaximized(),Resizer.hide(_$container[0])));_removeTabFromBar(panelId),exports.trigger(EVENT_PANEL_HIDDEN,panelId),activatedId&&exports.trigger(EVENT_PANEL_SHOWN,activatedId)},Panel.prototype.focus=function(){return!1},Panel.prototype.setVisible=function(visible){visible?this.show():this.hide()},Panel.prototype.setTitle=function(newTitle){this._tabTitle=newTitle,_$tabsOverflow&&_$tabsOverflow.find('.bottom-panel-tab[data-panel-id="'+this.panelID+'"] .bottom-panel-tab-title').text(newTitle)},Panel.prototype.destroy=function(){-1!==_openIds.indexOf(this.panelID)&&this.hide(),delete _panelMap[this.panelID],this.$panel.remove()},Panel.prototype.getPanelType=function(){return"bottomPanel"},EventDispatcher.makeEventDispatcher(exports),exports.Panel=Panel,exports.init=init,exports.getOpenBottomPanelIDs=getOpenBottomPanelIDs,exports.getActiveBottomPanel=getActiveBottomPanel,exports.showNextPanel=showNextPanel,exports.hideAllOpenPanels=hideAllOpenPanels,exports.exitMaximizeOnResize=exitMaximizeOnResize,exports.enterMaximizeOnResize=enterMaximizeOnResize,exports.restoreIfMaximized=restoreIfMaximized,exports.isMaximized=isMaximized,exports.MAXIMIZE_THRESHOLD=MAXIMIZE_THRESHOLD,exports.collapseContainer=collapseContainer,exports.restoreContainer=restoreContainer,exports.EVENT_PANEL_HIDDEN=EVENT_PANEL_HIDDEN,exports.EVENT_PANEL_SHOWN=EVENT_PANEL_SHOWN,exports.PANEL_TYPE_BOTTOM_PANEL="bottomPanel"});