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>&nbsp;</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