github.com/swiftstack/proxyfs@v0.0.0-20201223034610-5434d919416e/docs/source/theme/swiftopensource/static/js/webui-popover.js (about) 1 ;(function ( $, window, document, undefined ) { 2 3 // Create the defaults once 4 var pluginName = 'webuiPopover'; 5 var pluginClass = 'webui-popover'; 6 var pluginType = 'webui.popover'; 7 var defaults = { 8 placement:'auto', 9 width:'auto', 10 height:'auto', 11 trigger:'click', 12 style:'', 13 delay:300, 14 cache:true, 15 multi:false, 16 arrow:true, 17 title:'', 18 content:'', 19 closeable:false, 20 padding:true, 21 url:'', 22 type:'html', 23 template:'<div class="webui-popover">'+ 24 '<div class="arrow"></div>'+ 25 '<div class="webui-popover-inner">'+ 26 '<a href="#" class="close">x</a>'+ 27 '<h3 class="webui-popover-title"></h3>'+ 28 '<div class="webui-popover-content"><i class="icon-refresh"></i> <p> </p></div>'+ 29 '</div>'+ 30 '</div>' 31 }; 32 33 34 // The actual plugin constructor 35 function WebuiPopover ( element, options ) { 36 this.$element = $(element); 37 this.options = $.extend( {}, defaults, options ); 38 this._defaults = defaults; 39 this._name = pluginName; 40 this.init(); 41 42 } 43 44 WebuiPopover.prototype = { 45 //init webui popover 46 init: function () { 47 //init the event handlers 48 if (this.options.trigger==='click'){ 49 this.$element.off('click').on('click',$.proxy(this.toggle,this)); 50 }else{ 51 this.$element.off('mouseenter mouseleave') 52 .on('mouseenter',$.proxy(this.mouseenterHandler,this)) 53 .on('mouseleave',$.proxy(this.mouseleaveHandler,this)); 54 } 55 this._poped = false; 56 this._inited = true; 57 }, 58 /* api methods and actions */ 59 destroy:function(){ 60 this.hide(); 61 this.$element.data('plugin_'+pluginName,null); 62 this.$element.off(); 63 if (this.$target){ 64 this.$target.remove(); 65 } 66 }, 67 hide:function(event){ 68 if (event){ 69 event.preventDefault(); 70 event.stopPropagation(); 71 } 72 var e = $.Event('hide.' + pluginType); 73 this.$element.trigger(e); 74 if (this.$target){this.$target.removeClass('in').hide();} 75 this.$element.trigger('hidden.'+pluginType); 76 }, 77 toggle:function(e){ 78 if (e) { 79 e.preventDefault(); 80 e.stopPropagation(); 81 } 82 this[this.getTarget().hasClass('in') ? 'hide' : 'show'](); 83 }, 84 hideAll:function(){ 85 $('div.webui-popover').not('.webui-popover-fixed').removeClass('in').hide(); 86 }, 87 /*core method ,show popover */ 88 show:function(){ 89 var 90 $target = this.getTarget().removeClass().addClass(pluginClass); 91 if (!this.options.multi){ 92 this.hideAll(); 93 } 94 // use cache by default, if not cache set, reInit the contents 95 if (!this.options.cache||!this._poped){ 96 this.setTitle(this.getTitle()); 97 if (!this.options.closeable){ 98 $target.find('.close').off('click').remove(); 99 } 100 if (!this.isAsync()){ 101 this.setContent(this.getContent()); 102 }else{ 103 this.setContentASync(this.options.content); 104 this.displayContent(); 105 return; 106 } 107 $target.show(); 108 } 109 this.displayContent(); 110 this.bindBodyEvents(); 111 }, 112 displayContent:function(){ 113 var 114 //element position 115 elementPos = this.getElementPosition(), 116 //target position 117 $target = this.getTarget().removeClass().addClass(pluginClass), 118 //target content 119 $targetContent = this.getContentElement(), 120 //target Width 121 targetWidth = $target[0].offsetWidth, 122 //target Height 123 targetHeight = $target[0].offsetHeight, 124 //placement 125 placement = 'bottom', 126 e = $.Event('show.' + pluginType); 127 //if (this.hasContent()){ 128 this.$element.trigger(e); 129 //} 130 if (this.options.width!=='auto') {$target.width(this.options.width);} 131 if (this.options.height!=='auto'){$targetContent.height(this.options.height);} 132 133 //init the popover and insert into the document body 134 if (!this.options.arrow){ 135 $target.find('.arrow').remove(); 136 } 137 $target.remove().css({ top: -1000, left: -1000, display: 'block' }).appendTo(document.body); 138 targetWidth = $target[0].offsetWidth; 139 targetHeight = $target[0].offsetHeight; 140 placement = this.getPlacement(elementPos,targetHeight); 141 this.initTargetEvents(); 142 var postionInfo = this.getTargetPositin(elementPos,placement,targetWidth,targetHeight); 143 this.$target.css(postionInfo.position).addClass(placement).addClass('in'); 144 145 if (this.options.type==='iframe'){ 146 var $iframe = $target.find('iframe'); 147 $iframe.width($target.width()).height($iframe.parent().height()); 148 } 149 150 if (this.options.style){ 151 this.$target.addClass(pluginClass+'-'+this.options.style); 152 } 153 154 if (!this.options.padding){ 155 $targetContent.css('height',$targetContent.outerHeight()); 156 this.$target.addClass('webui-no-padding'); 157 } 158 if (!this.options.arrow){ 159 this.$target.css({'margin':0}); 160 } 161 if (this.options.arrow){ 162 var $arrow = this.$target.find('.arrow'); 163 $arrow.removeAttr('style'); 164 if (postionInfo.arrowOffset){ 165 $arrow.css(postionInfo.arrowOffset); 166 } 167 } 168 this._poped = true; 169 this.$element.trigger('shown.'+pluginType); 170 171 }, 172 173 isTargetLoaded:function(){ 174 return this.getTarget().find('i.glyphicon-refresh').length===0; 175 }, 176 177 /*getter setters */ 178 getTarget:function(){ 179 if (!this.$target){ 180 this.$target = $(this.options.template); 181 } 182 return this.$target; 183 }, 184 getTitleElement:function(){ 185 return this.getTarget().find('.'+pluginClass+'-title'); 186 }, 187 getContentElement:function(){ 188 return this.getTarget().find('.'+pluginClass+'-content'); 189 }, 190 getTitle:function(){ 191 return this.options.title||this.$element.attr('data-title')||this.$element.attr('title'); 192 }, 193 setTitle:function(title){ 194 var $titleEl = this.getTitleElement(); 195 if (title){ 196 $titleEl.html(title); 197 }else{ 198 $titleEl.remove(); 199 } 200 }, 201 hasContent:function () { 202 return this.getContent(); 203 }, 204 getContent:function(){ 205 if (this.options.url){ 206 if (this.options.type==='iframe'){ 207 this.content = $('<iframe frameborder="0"></iframe>').attr('src',this.options.url); 208 } 209 }else if (!this.content){ 210 var content=''; 211 if ($.isFunction(this.options.content)){ 212 content = this.options.content.apply(this.$element[0],arguments); 213 }else{ 214 content = this.options.content; 215 } 216 this.content = this.$element.attr('data-content')||content; 217 } 218 return this.content; 219 }, 220 setContent:function(content){ 221 var $target = this.getTarget(); 222 this.getContentElement().html(content); 223 this.$target = $target; 224 }, 225 isAsync:function(){ 226 return this.options.type==='async'; 227 }, 228 setContentASync:function(content){ 229 var that = this; 230 $.ajax({ 231 url:this.options.url, 232 type:'GET', 233 cache:this.options.cache, 234 success:function(data){ 235 if (content&&$.isFunction(content)){ 236 that.content = content.apply(that.$element[0],[data]); 237 }else{ 238 that.content = data; 239 } 240 that.setContent(that.content); 241 var $targetContent = that.getContentElement(); 242 $targetContent.removeAttr('style'); 243 that.displayContent(); 244 } 245 }); 246 }, 247 248 bindBodyEvents:function(){ 249 $('body').off('keyup.webui-popover').on('keyup.webui-popover',$.proxy(this.escapeHandler,this)); 250 $('body').off('click.webui-popover').on('click.webui-popover',$.proxy(this.bodyClickHandler,this)); 251 }, 252 253 /* event handlers */ 254 mouseenterHandler:function(){ 255 var self = this; 256 if (self._timeout){clearTimeout(self._timeout);} 257 if (!self.getTarget().is(':visible')){self.show();} 258 }, 259 mouseleaveHandler:function(){ 260 var self = this; 261 //key point, set the _timeout then use clearTimeout when mouse leave 262 self._timeout = setTimeout(function(){ 263 self.hide(); 264 },self.options.delay); 265 }, 266 escapeHandler:function(e){ 267 if (e.keyCode===27){ 268 this.hideAll(); 269 } 270 }, 271 bodyClickHandler:function(){ 272 this.hideAll(); 273 }, 274 275 targetClickHandler:function(e){ 276 e.stopPropagation(); 277 }, 278 279 //reset and init the target events; 280 initTargetEvents:function(){ 281 if (this.options.trigger!=='click'){ 282 this.$target.off('mouseenter mouseleave') 283 .on('mouseenter',$.proxy(this.mouseenterHandler,this)) 284 .on('mouseleave',$.proxy(this.mouseleaveHandler,this)); 285 } 286 this.$target.find('.close').off('click').on('click', $.proxy(this.hide,this)); 287 this.$target.off('click.webui-popover').on('click.webui-popover',$.proxy(this.targetClickHandler,this)); 288 }, 289 /* utils methods */ 290 //caculate placement of the popover 291 getPlacement:function(pos,targetHeight){ 292 var 293 placement, 294 de = document.documentElement, 295 db = document.body, 296 clientWidth = de.clientWidth, 297 clientHeight = de.clientHeight, 298 scrollTop = Math.max(db.scrollTop,de.scrollTop), 299 scrollLeft = Math.max(db.scrollLeft,de.scrollLeft), 300 pageX = Math.max(0,pos.left - scrollLeft), 301 pageY = Math.max(0,pos.top - scrollTop), 302 arrowSize = 20; 303 304 //if placement equals autoļ¼caculate the placement by element information; 305 if (typeof(this.options.placement)==='function'){ 306 placement = this.options.placement.call(this, this.getTarget()[0], this.$element[0]); 307 }else{ 308 placement = this.$element.data('placement')||this.options.placement; 309 } 310 311 if (placement==='auto'){ 312 if (pageX<clientWidth/3){ 313 if (pageY<clientHeight/3){ 314 placement = 'bottom-right'; 315 }else if (pageY<clientHeight*2/3){ 316 placement = 'right'; 317 }else{ 318 placement = 'top-right'; 319 } 320 //placement= pageY>targetHeight+arrowSize?'top-right':'bottom-right'; 321 }else if (pageX<clientWidth*2/3){ 322 if (pageY<clientHeight/3){ 323 placement = 'bottom'; 324 }else if (pageY<clientHeight*2/3){ 325 placement = 'bottom'; 326 }else{ 327 placement = 'top'; 328 } 329 }else{ 330 placement = pageY>targetHeight+arrowSize?'top-left':'bottom-left'; 331 if (pageY<clientHeight/3){ 332 placement = 'bottom-left'; 333 }else if (pageY<clientHeight*2/3){ 334 placement = 'left'; 335 }else{ 336 placement = 'top-left'; 337 } 338 } 339 } 340 return placement; 341 }, 342 getElementPosition:function(){ 343 return $.extend({},this.$element.offset(), { 344 width: this.$element[0].offsetWidth, 345 height: this.$element[0].offsetHeight 346 }); 347 }, 348 349 getTargetPositin:function(elementPos,placement,targetWidth,targetHeight){ 350 var pos = elementPos, 351 elementW = this.$element.outerWidth(), 352 elementH = this.$element.outerHeight(), 353 position={}, 354 arrowOffset=null, 355 arrowSize = this.options.arrow?28:0, 356 fixedW = elementW<arrowSize+10?arrowSize:0, 357 fixedH = elementH<arrowSize+10?arrowSize:0; 358 switch (placement) { 359 case 'bottom': 360 position = {top: pos.top + pos.height, left: pos.left + pos.width / 2 - targetWidth / 2}; 361 break; 362 case 'top': 363 position = {top: pos.top - targetHeight, left: pos.left + pos.width / 2 - targetWidth / 2}; 364 break; 365 case 'left': 366 position = {top: pos.top + pos.height / 2 - targetHeight / 2, left: pos.left - targetWidth}; 367 break; 368 case 'right': 369 position = {top: pos.top + pos.height / 2 - targetHeight / 2, left: pos.left + pos.width}; 370 break; 371 case 'top-right': 372 position = {top: pos.top - targetHeight, left: pos.left-fixedW}; 373 arrowOffset = {left: elementW/2 + fixedW}; 374 break; 375 case 'top-left': 376 position = {top: pos.top - targetHeight, left: pos.left -targetWidth +pos.width + fixedW}; 377 arrowOffset = {left: targetWidth - elementW /2 -fixedW}; 378 break; 379 case 'bottom-right': 380 position = {top: pos.top + pos.height, left: pos.left-fixedW}; 381 arrowOffset = {left: elementW /2+fixedW}; 382 break; 383 case 'bottom-left': 384 position = {top: pos.top + pos.height, left: pos.left -targetWidth +pos.width+fixedW}; 385 arrowOffset = {left: targetWidth- elementW /2 - fixedW}; 386 break; 387 case 'right-top': 388 position = {top: pos.top -targetHeight + pos.height + fixedH, left: pos.left + pos.width}; 389 arrowOffset = {top: targetHeight - elementH/2 -fixedH}; 390 break; 391 case 'right-bottom': 392 position = {top: pos.top - fixedH, left: pos.left + pos.width}; 393 arrowOffset = {top: elementH /2 +fixedH }; 394 break; 395 case 'left-top': 396 position = {top: pos.top -targetHeight + pos.height+fixedH, left: pos.left - targetWidth}; 397 arrowOffset = {top: targetHeight - elementH/2 - fixedH}; 398 break; 399 case 'left-bottom': 400 position = {top: pos.top , left: pos.left -targetWidth}; 401 arrowOffset = {top: elementH /2 }; 402 break; 403 404 } 405 return {position:position,arrowOffset:arrowOffset}; 406 } 407 }; 408 $.fn[ pluginName ] = function ( options ) { 409 return this.each(function() { 410 var webuiPopover = $.data( this, 'plugin_' + pluginName ); 411 if (!webuiPopover) { 412 if (!options){ 413 webuiPopover = new WebuiPopover( this, null); 414 }else if (typeof options ==='string'){ 415 if (options!=='destroy'){ 416 webuiPopover = new WebuiPopover( this, null ); 417 webuiPopover[options](); 418 } 419 }else if (typeof options ==='object'){ 420 webuiPopover = new WebuiPopover( this, options ); 421 } 422 $.data( this, 'plugin_' + pluginName, webuiPopover); 423 }else{ 424 if (options==='destroy'){ 425 webuiPopover.destroy(); 426 }else if (typeof options ==='string'){ 427 webuiPopover[options](); 428 } 429 } 430 }); 431 }; 432 433 })( jQuery, window, document ); 434