1 /** 2 * @fileOverview 3 * @author <a href="https://www.labkey.org">LabKey</a> (<a href="mailto:info@labkey.com">info@labkey.com</a>) 4 * @license Copyright (c) 2009-2016 LabKey Corporation 5 * <p/> 6 * Licensed under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * <p/> 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * <p/> 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 * <p/> 18 */ 19 20 /** 21 * @private 22 * @namespace LabKey Popup Menu Web Class. 23 * This class allows an element to display a popup menu based on a LabKey webpart 24 * The element will highlight on hover over. 25 * 26 * @constructor 27 * @param {Object} config Describes the HoverPopup's properties. 28 * @param {String} config.hoverElem Element or element id that should trigger the popup 29 * @param {String} config.webPartName Name of webPart to load on hover 30 * @param {Object} config.partConfig PartConfig for the webpart same as used in LABKEY.WebPart 31 * 32 */ 33 LABKEY.HoverPopup = function(config) 34 { 35 Ext.apply(this, config); 36 LABKEY.HoverPopup.superclass.constructor.call(this); 37 38 this.extElem = Ext.get(config.hoverElem); 39 if (!this.extElem) { 40 return; // Custom Menu Bar may be hidden in which case element is null 41 } 42 43 this.showDelay = 150; 44 45 var popup = Ext.DomHelper.insertAfter("menubar", 46 {id:config.hoverElem + "_menu", tag:"div", cls:"labkey-webpart-menu", 47 children:[{tag:"div", cls:"loading-indicator", style:"width:100px;height:100px"}]}); 48 this.extPopup = new Ext.Layer({shadow:true,shadowOffset:8,zindex:1000},popup); 49 this.webPartName = config.webPartName; 50 this.partConfig = config.partConfig || {}; 51 52 this.extElem.hover(function(e) { 53 this.cancelHide(); 54 55 // show immediately if we already have a menu up 56 // Otherwise, make sure that someone hovers for a while 57 LABKEY.HoverPopup._visiblePopup ? this.showFn() : this.delayShow(); 58 59 }, this.delayCheck, this); 60 61 this.extPopup.hover(this.cancelHide, this.delayCheck, this); 62 63 //Update the shadow on click, since we sometimes cause the change of the inner div 64 this.extPopup.on("click", function(e) {this.extPopup.enableShadow(true)}, this); 65 }; 66 67 Ext.extend(LABKEY.HoverPopup, Ext.util.Observable, { 68 //private 69 cancelHide: function() { 70 if (this.hideTimeout) { 71 clearTimeout(this.hideTimeout); 72 delete this.hideTimeout; 73 } 74 }, 75 76 //private 77 delayCheck : function(e) { 78 if (!this.extElem.getRegion().contains(e.getPoint()) && !this.extPopup.getRegion().contains(e.getPoint())) { 79 this.delayHide(); 80 } 81 }, 82 83 //private 84 delayHide: function() { 85 if (this.hideTimeout) { 86 clearTimeout(this.hideTimeout); 87 } 88 if (this.showTimeout) { 89 clearTimeout(this.showTimeout); 90 delete this.showTimeout; 91 } 92 this.hideTimeout = this.hideFn.defer(200, this); 93 }, 94 95 //private 96 delayShow: function() { 97 if (!this.showTimeout) { 98 this.showTimeout = this.showFn.defer(this.showDelay, this); 99 } 100 }, 101 102 //private 103 showFn: function() { 104 if (LABKEY.HoverPopup._visiblePopup) { 105 if (LABKEY.HoverPopup._visiblePopup == this) { 106 return; 107 } 108 else { 109 LABKEY.HoverPopup._visiblePopup.hideFn(); 110 } 111 } 112 this.extElem.addClass("selected"); 113 //console.log(this.extElem.id + " extPopup.y: " + this.extPopup.getY()); 114 if (!this.rendered) { 115 var p = new LABKEY.WebPart({ 116 partName : this.webPartName, 117 renderTo : this.extPopup.id, 118 frame : 'none', 119 partConfig : this.partConfig, 120 failure : function(err) {if (window.console && window.console.log) { window.console.log(err);}}, 121 success : function() { 122 var x = function() {this.extPopup.enableShadow(true);}; 123 x.defer(100, this); 124 }, 125 scope:this 126 }); 127 p.render(); 128 this.rendered = true; 129 this.showDelay = 100; // show more quickly 130 } 131 this.extPopup.show(); 132 this.extPopup.constrain = false; 133 this.extPopup.alignTo(this.extElem, "tl-bl"); 134 this.extPopup.setXY([Math.max(0 - this.extPopup.getBorderWidth('t'), this.extPopup.getX() - 1), this.extPopup.getY()- this.extPopup.getBorderWidth('t')]); 135 this.extPopup.enableShadow(true); 136 LABKEY.HoverPopup._visiblePopup = this; 137 }, 138 139 //private 140 hideFn: function () { 141 this.extElem.removeClass("selected"); 142 this.extPopup.hide(); 143 if (LABKEY.HoverPopup._visiblePopup == this) { 144 LABKEY.HoverPopup._visiblePopup = null; 145 } 146 } 147 }); 148 149