| Hao Zhu | 4a888b3 | 2020-08-11 15:48:23 -0400 | [diff] [blame] | 1 | /* ======================================================================== | 
|  | 2 | * Bootstrap: tooltip.js v3.4.1 | 
|  | 3 | * https://getbootstrap.com/docs/3.4/javascript/#tooltip | 
|  | 4 | * Inspired by the original jQuery.tipsy by Jason Frame | 
|  | 5 | * ======================================================================== | 
|  | 6 | * Copyright 2011-2019 Twitter, Inc. | 
|  | 7 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | 
|  | 8 | * ======================================================================== */ | 
|  | 9 |  | 
|  | 10 | +function ($) { | 
|  | 11 | 'use strict'; | 
|  | 12 |  | 
|  | 13 | var DISALLOWED_ATTRIBUTES = ['sanitize', 'whiteList', 'sanitizeFn'] | 
|  | 14 |  | 
|  | 15 | var uriAttrs = [ | 
|  | 16 | 'background', | 
|  | 17 | 'cite', | 
|  | 18 | 'href', | 
|  | 19 | 'itemtype', | 
|  | 20 | 'longdesc', | 
|  | 21 | 'poster', | 
|  | 22 | 'src', | 
|  | 23 | 'xlink:href' | 
|  | 24 | ] | 
|  | 25 |  | 
|  | 26 | var ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i | 
|  | 27 |  | 
|  | 28 | var DefaultWhitelist = { | 
|  | 29 | // Global attributes allowed on any supplied element below. | 
|  | 30 | '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN], | 
|  | 31 | a: ['target', 'href', 'title', 'rel'], | 
|  | 32 | area: [], | 
|  | 33 | b: [], | 
|  | 34 | br: [], | 
|  | 35 | col: [], | 
|  | 36 | code: [], | 
|  | 37 | div: [], | 
|  | 38 | em: [], | 
|  | 39 | hr: [], | 
|  | 40 | h1: [], | 
|  | 41 | h2: [], | 
|  | 42 | h3: [], | 
|  | 43 | h4: [], | 
|  | 44 | h5: [], | 
|  | 45 | h6: [], | 
|  | 46 | i: [], | 
|  | 47 | img: ['src', 'alt', 'title', 'width', 'height'], | 
|  | 48 | li: [], | 
|  | 49 | ol: [], | 
|  | 50 | p: [], | 
|  | 51 | pre: [], | 
|  | 52 | s: [], | 
|  | 53 | small: [], | 
|  | 54 | span: [], | 
|  | 55 | sub: [], | 
|  | 56 | sup: [], | 
|  | 57 | strong: [], | 
|  | 58 | u: [], | 
|  | 59 | ul: [] | 
|  | 60 | } | 
|  | 61 |  | 
|  | 62 | /** | 
|  | 63 | * A pattern that recognizes a commonly useful subset of URLs that are safe. | 
|  | 64 | * | 
|  | 65 | * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | 
|  | 66 | */ | 
|  | 67 | var SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^&:/?#]*(?:[/?#]|$))/gi | 
|  | 68 |  | 
|  | 69 | /** | 
|  | 70 | * A pattern that matches safe data URLs. Only matches image, video and audio types. | 
|  | 71 | * | 
|  | 72 | * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts | 
|  | 73 | */ | 
|  | 74 | var DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[a-z0-9+/]+=*$/i | 
|  | 75 |  | 
|  | 76 | function allowedAttribute(attr, allowedAttributeList) { | 
|  | 77 | var attrName = attr.nodeName.toLowerCase() | 
|  | 78 |  | 
|  | 79 | if ($.inArray(attrName, allowedAttributeList) !== -1) { | 
|  | 80 | if ($.inArray(attrName, uriAttrs) !== -1) { | 
|  | 81 | return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN)) | 
|  | 82 | } | 
|  | 83 |  | 
|  | 84 | return true | 
|  | 85 | } | 
|  | 86 |  | 
|  | 87 | var regExp = $(allowedAttributeList).filter(function (index, value) { | 
|  | 88 | return value instanceof RegExp | 
|  | 89 | }) | 
|  | 90 |  | 
|  | 91 | // Check if a regular expression validates the attribute. | 
|  | 92 | for (var i = 0, l = regExp.length; i < l; i++) { | 
|  | 93 | if (attrName.match(regExp[i])) { | 
|  | 94 | return true | 
|  | 95 | } | 
|  | 96 | } | 
|  | 97 |  | 
|  | 98 | return false | 
|  | 99 | } | 
|  | 100 |  | 
|  | 101 | function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) { | 
|  | 102 | if (unsafeHtml.length === 0) { | 
|  | 103 | return unsafeHtml | 
|  | 104 | } | 
|  | 105 |  | 
|  | 106 | if (sanitizeFn && typeof sanitizeFn === 'function') { | 
|  | 107 | return sanitizeFn(unsafeHtml) | 
|  | 108 | } | 
|  | 109 |  | 
|  | 110 | // IE 8 and below don't support createHTMLDocument | 
|  | 111 | if (!document.implementation || !document.implementation.createHTMLDocument) { | 
|  | 112 | return unsafeHtml | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | var createdDocument = document.implementation.createHTMLDocument('sanitization') | 
|  | 116 | createdDocument.body.innerHTML = unsafeHtml | 
|  | 117 |  | 
|  | 118 | var whitelistKeys = $.map(whiteList, function (el, i) { return i }) | 
|  | 119 | var elements = $(createdDocument.body).find('*') | 
|  | 120 |  | 
|  | 121 | for (var i = 0, len = elements.length; i < len; i++) { | 
|  | 122 | var el = elements[i] | 
|  | 123 | var elName = el.nodeName.toLowerCase() | 
|  | 124 |  | 
|  | 125 | if ($.inArray(elName, whitelistKeys) === -1) { | 
|  | 126 | el.parentNode.removeChild(el) | 
|  | 127 |  | 
|  | 128 | continue | 
|  | 129 | } | 
|  | 130 |  | 
|  | 131 | var attributeList = $.map(el.attributes, function (el) { return el }) | 
|  | 132 | var whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || []) | 
|  | 133 |  | 
|  | 134 | for (var j = 0, len2 = attributeList.length; j < len2; j++) { | 
|  | 135 | if (!allowedAttribute(attributeList[j], whitelistedAttributes)) { | 
|  | 136 | el.removeAttribute(attributeList[j].nodeName) | 
|  | 137 | } | 
|  | 138 | } | 
|  | 139 | } | 
|  | 140 |  | 
|  | 141 | return createdDocument.body.innerHTML | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | // TOOLTIP PUBLIC CLASS DEFINITION | 
|  | 145 | // =============================== | 
|  | 146 |  | 
|  | 147 | var Tooltip = function (element, options) { | 
|  | 148 | this.type       = null | 
|  | 149 | this.options    = null | 
|  | 150 | this.enabled    = null | 
|  | 151 | this.timeout    = null | 
|  | 152 | this.hoverState = null | 
|  | 153 | this.$element   = null | 
|  | 154 | this.inState    = null | 
|  | 155 |  | 
|  | 156 | this.init('tooltip', element, options) | 
|  | 157 | } | 
|  | 158 |  | 
|  | 159 | Tooltip.VERSION  = '3.4.1' | 
|  | 160 |  | 
|  | 161 | Tooltip.TRANSITION_DURATION = 150 | 
|  | 162 |  | 
|  | 163 | Tooltip.DEFAULTS = { | 
|  | 164 | animation: true, | 
|  | 165 | placement: 'top', | 
|  | 166 | selector: false, | 
|  | 167 | template: '<div class="tooltip" role="tooltip"><div class="tooltip-arrow"></div><div class="tooltip-inner"></div></div>', | 
|  | 168 | trigger: 'hover focus', | 
|  | 169 | title: '', | 
|  | 170 | delay: 0, | 
|  | 171 | html: false, | 
|  | 172 | container: false, | 
|  | 173 | viewport: { | 
|  | 174 | selector: 'body', | 
|  | 175 | padding: 0 | 
|  | 176 | }, | 
|  | 177 | sanitize : true, | 
|  | 178 | sanitizeFn : null, | 
|  | 179 | whiteList : DefaultWhitelist | 
|  | 180 | } | 
|  | 181 |  | 
|  | 182 | Tooltip.prototype.init = function (type, element, options) { | 
|  | 183 | this.enabled   = true | 
|  | 184 | this.type      = type | 
|  | 185 | this.$element  = $(element) | 
|  | 186 | this.options   = this.getOptions(options) | 
|  | 187 | this.$viewport = this.options.viewport && $(document).find($.isFunction(this.options.viewport) ? this.options.viewport.call(this, this.$element) : (this.options.viewport.selector || this.options.viewport)) | 
|  | 188 | this.inState   = { click: false, hover: false, focus: false } | 
|  | 189 |  | 
|  | 190 | if (this.$element[0] instanceof document.constructor && !this.options.selector) { | 
|  | 191 | throw new Error('`selector` option must be specified when initializing ' + this.type + ' on the window.document object!') | 
|  | 192 | } | 
|  | 193 |  | 
|  | 194 | var triggers = this.options.trigger.split(' ') | 
|  | 195 |  | 
|  | 196 | for (var i = triggers.length; i--;) { | 
|  | 197 | var trigger = triggers[i] | 
|  | 198 |  | 
|  | 199 | if (trigger == 'click') { | 
|  | 200 | this.$element.on('click.' + this.type, this.options.selector, $.proxy(this.toggle, this)) | 
|  | 201 | } else if (trigger != 'manual') { | 
|  | 202 | var eventIn  = trigger == 'hover' ? 'mouseenter' : 'focusin' | 
|  | 203 | var eventOut = trigger == 'hover' ? 'mouseleave' : 'focusout' | 
|  | 204 |  | 
|  | 205 | this.$element.on(eventIn  + '.' + this.type, this.options.selector, $.proxy(this.enter, this)) | 
|  | 206 | this.$element.on(eventOut + '.' + this.type, this.options.selector, $.proxy(this.leave, this)) | 
|  | 207 | } | 
|  | 208 | } | 
|  | 209 |  | 
|  | 210 | this.options.selector ? | 
|  | 211 | (this._options = $.extend({}, this.options, { trigger: 'manual', selector: '' })) : | 
|  | 212 | this.fixTitle() | 
|  | 213 | } | 
|  | 214 |  | 
|  | 215 | Tooltip.prototype.getDefaults = function () { | 
|  | 216 | return Tooltip.DEFAULTS | 
|  | 217 | } | 
|  | 218 |  | 
|  | 219 | Tooltip.prototype.getOptions = function (options) { | 
|  | 220 | var dataAttributes = this.$element.data() | 
|  | 221 |  | 
|  | 222 | for (var dataAttr in dataAttributes) { | 
|  | 223 | if (dataAttributes.hasOwnProperty(dataAttr) && $.inArray(dataAttr, DISALLOWED_ATTRIBUTES) !== -1) { | 
|  | 224 | delete dataAttributes[dataAttr] | 
|  | 225 | } | 
|  | 226 | } | 
|  | 227 |  | 
|  | 228 | options = $.extend({}, this.getDefaults(), dataAttributes, options) | 
|  | 229 |  | 
|  | 230 | if (options.delay && typeof options.delay == 'number') { | 
|  | 231 | options.delay = { | 
|  | 232 | show: options.delay, | 
|  | 233 | hide: options.delay | 
|  | 234 | } | 
|  | 235 | } | 
|  | 236 |  | 
|  | 237 | if (options.sanitize) { | 
|  | 238 | options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn) | 
|  | 239 | } | 
|  | 240 |  | 
|  | 241 | return options | 
|  | 242 | } | 
|  | 243 |  | 
|  | 244 | Tooltip.prototype.getDelegateOptions = function () { | 
|  | 245 | var options  = {} | 
|  | 246 | var defaults = this.getDefaults() | 
|  | 247 |  | 
|  | 248 | this._options && $.each(this._options, function (key, value) { | 
|  | 249 | if (defaults[key] != value) options[key] = value | 
|  | 250 | }) | 
|  | 251 |  | 
|  | 252 | return options | 
|  | 253 | } | 
|  | 254 |  | 
|  | 255 | Tooltip.prototype.enter = function (obj) { | 
|  | 256 | var self = obj instanceof this.constructor ? | 
|  | 257 | obj : $(obj.currentTarget).data('bs.' + this.type) | 
|  | 258 |  | 
|  | 259 | if (!self) { | 
|  | 260 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) | 
|  | 261 | $(obj.currentTarget).data('bs.' + this.type, self) | 
|  | 262 | } | 
|  | 263 |  | 
|  | 264 | if (obj instanceof $.Event) { | 
|  | 265 | self.inState[obj.type == 'focusin' ? 'focus' : 'hover'] = true | 
|  | 266 | } | 
|  | 267 |  | 
|  | 268 | if (self.tip().hasClass('in') || self.hoverState == 'in') { | 
|  | 269 | self.hoverState = 'in' | 
|  | 270 | return | 
|  | 271 | } | 
|  | 272 |  | 
|  | 273 | clearTimeout(self.timeout) | 
|  | 274 |  | 
|  | 275 | self.hoverState = 'in' | 
|  | 276 |  | 
|  | 277 | if (!self.options.delay || !self.options.delay.show) return self.show() | 
|  | 278 |  | 
|  | 279 | self.timeout = setTimeout(function () { | 
|  | 280 | if (self.hoverState == 'in') self.show() | 
|  | 281 | }, self.options.delay.show) | 
|  | 282 | } | 
|  | 283 |  | 
|  | 284 | Tooltip.prototype.isInStateTrue = function () { | 
|  | 285 | for (var key in this.inState) { | 
|  | 286 | if (this.inState[key]) return true | 
|  | 287 | } | 
|  | 288 |  | 
|  | 289 | return false | 
|  | 290 | } | 
|  | 291 |  | 
|  | 292 | Tooltip.prototype.leave = function (obj) { | 
|  | 293 | var self = obj instanceof this.constructor ? | 
|  | 294 | obj : $(obj.currentTarget).data('bs.' + this.type) | 
|  | 295 |  | 
|  | 296 | if (!self) { | 
|  | 297 | self = new this.constructor(obj.currentTarget, this.getDelegateOptions()) | 
|  | 298 | $(obj.currentTarget).data('bs.' + this.type, self) | 
|  | 299 | } | 
|  | 300 |  | 
|  | 301 | if (obj instanceof $.Event) { | 
|  | 302 | self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false | 
|  | 303 | } | 
|  | 304 |  | 
|  | 305 | if (self.isInStateTrue()) return | 
|  | 306 |  | 
|  | 307 | clearTimeout(self.timeout) | 
|  | 308 |  | 
|  | 309 | self.hoverState = 'out' | 
|  | 310 |  | 
|  | 311 | if (!self.options.delay || !self.options.delay.hide) return self.hide() | 
|  | 312 |  | 
|  | 313 | self.timeout = setTimeout(function () { | 
|  | 314 | if (self.hoverState == 'out') self.hide() | 
|  | 315 | }, self.options.delay.hide) | 
|  | 316 | } | 
|  | 317 |  | 
|  | 318 | Tooltip.prototype.show = function () { | 
|  | 319 | var e = $.Event('show.bs.' + this.type) | 
|  | 320 |  | 
|  | 321 | if (this.hasContent() && this.enabled) { | 
|  | 322 | this.$element.trigger(e) | 
|  | 323 |  | 
|  | 324 | var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0]) | 
|  | 325 | if (e.isDefaultPrevented() || !inDom) return | 
|  | 326 | var that = this | 
|  | 327 |  | 
|  | 328 | var $tip = this.tip() | 
|  | 329 |  | 
|  | 330 | var tipId = this.getUID(this.type) | 
|  | 331 |  | 
|  | 332 | this.setContent() | 
|  | 333 | $tip.attr('id', tipId) | 
|  | 334 | this.$element.attr('aria-describedby', tipId) | 
|  | 335 |  | 
|  | 336 | if (this.options.animation) $tip.addClass('fade') | 
|  | 337 |  | 
|  | 338 | var placement = typeof this.options.placement == 'function' ? | 
|  | 339 | this.options.placement.call(this, $tip[0], this.$element[0]) : | 
|  | 340 | this.options.placement | 
|  | 341 |  | 
|  | 342 | var autoToken = /\s?auto?\s?/i | 
|  | 343 | var autoPlace = autoToken.test(placement) | 
|  | 344 | if (autoPlace) placement = placement.replace(autoToken, '') || 'top' | 
|  | 345 |  | 
|  | 346 | $tip | 
|  | 347 | .detach() | 
|  | 348 | .css({ top: 0, left: 0, display: 'block' }) | 
|  | 349 | .addClass(placement) | 
|  | 350 | .data('bs.' + this.type, this) | 
|  | 351 |  | 
|  | 352 | this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element) | 
|  | 353 | this.$element.trigger('inserted.bs.' + this.type) | 
|  | 354 |  | 
|  | 355 | var pos          = this.getPosition() | 
|  | 356 | var actualWidth  = $tip[0].offsetWidth | 
|  | 357 | var actualHeight = $tip[0].offsetHeight | 
|  | 358 |  | 
|  | 359 | if (autoPlace) { | 
|  | 360 | var orgPlacement = placement | 
|  | 361 | var viewportDim = this.getPosition(this.$viewport) | 
|  | 362 |  | 
|  | 363 | placement = placement == 'bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'top'    : | 
|  | 364 | placement == 'top'    && pos.top    - actualHeight < viewportDim.top    ? 'bottom' : | 
|  | 365 | placement == 'right'  && pos.right  + actualWidth  > viewportDim.width  ? 'left'   : | 
|  | 366 | placement == 'left'   && pos.left   - actualWidth  < viewportDim.left   ? 'right'  : | 
|  | 367 | placement | 
|  | 368 |  | 
|  | 369 | $tip | 
|  | 370 | .removeClass(orgPlacement) | 
|  | 371 | .addClass(placement) | 
|  | 372 | } | 
|  | 373 |  | 
|  | 374 | var calculatedOffset = this.getCalculatedOffset(placement, pos, actualWidth, actualHeight) | 
|  | 375 |  | 
|  | 376 | this.applyPlacement(calculatedOffset, placement) | 
|  | 377 |  | 
|  | 378 | var complete = function () { | 
|  | 379 | var prevHoverState = that.hoverState | 
|  | 380 | that.$element.trigger('shown.bs.' + that.type) | 
|  | 381 | that.hoverState = null | 
|  | 382 |  | 
|  | 383 | if (prevHoverState == 'out') that.leave(that) | 
|  | 384 | } | 
|  | 385 |  | 
|  | 386 | $.support.transition && this.$tip.hasClass('fade') ? | 
|  | 387 | $tip | 
|  | 388 | .one('bsTransitionEnd', complete) | 
|  | 389 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : | 
|  | 390 | complete() | 
|  | 391 | } | 
|  | 392 | } | 
|  | 393 |  | 
|  | 394 | Tooltip.prototype.applyPlacement = function (offset, placement) { | 
|  | 395 | var $tip   = this.tip() | 
|  | 396 | var width  = $tip[0].offsetWidth | 
|  | 397 | var height = $tip[0].offsetHeight | 
|  | 398 |  | 
|  | 399 | // manually read margins because getBoundingClientRect includes difference | 
|  | 400 | var marginTop = parseInt($tip.css('margin-top'), 10) | 
|  | 401 | var marginLeft = parseInt($tip.css('margin-left'), 10) | 
|  | 402 |  | 
|  | 403 | // we must check for NaN for ie 8/9 | 
|  | 404 | if (isNaN(marginTop))  marginTop  = 0 | 
|  | 405 | if (isNaN(marginLeft)) marginLeft = 0 | 
|  | 406 |  | 
|  | 407 | offset.top  += marginTop | 
|  | 408 | offset.left += marginLeft | 
|  | 409 |  | 
|  | 410 | // $.fn.offset doesn't round pixel values | 
|  | 411 | // so we use setOffset directly with our own function B-0 | 
|  | 412 | $.offset.setOffset($tip[0], $.extend({ | 
|  | 413 | using: function (props) { | 
|  | 414 | $tip.css({ | 
|  | 415 | top: Math.round(props.top), | 
|  | 416 | left: Math.round(props.left) | 
|  | 417 | }) | 
|  | 418 | } | 
|  | 419 | }, offset), 0) | 
|  | 420 |  | 
|  | 421 | $tip.addClass('in') | 
|  | 422 |  | 
|  | 423 | // check to see if placing tip in new offset caused the tip to resize itself | 
|  | 424 | var actualWidth  = $tip[0].offsetWidth | 
|  | 425 | var actualHeight = $tip[0].offsetHeight | 
|  | 426 |  | 
|  | 427 | if (placement == 'top' && actualHeight != height) { | 
|  | 428 | offset.top = offset.top + height - actualHeight | 
|  | 429 | } | 
|  | 430 |  | 
|  | 431 | var delta = this.getViewportAdjustedDelta(placement, offset, actualWidth, actualHeight) | 
|  | 432 |  | 
|  | 433 | if (delta.left) offset.left += delta.left | 
|  | 434 | else offset.top += delta.top | 
|  | 435 |  | 
|  | 436 | var isVertical          = /top|bottom/.test(placement) | 
|  | 437 | var arrowDelta          = isVertical ? delta.left * 2 - width + actualWidth : delta.top * 2 - height + actualHeight | 
|  | 438 | var arrowOffsetPosition = isVertical ? 'offsetWidth' : 'offsetHeight' | 
|  | 439 |  | 
|  | 440 | $tip.offset(offset) | 
|  | 441 | this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical) | 
|  | 442 | } | 
|  | 443 |  | 
|  | 444 | Tooltip.prototype.replaceArrow = function (delta, dimension, isVertical) { | 
|  | 445 | this.arrow() | 
|  | 446 | .css(isVertical ? 'left' : 'top', 50 * (1 - delta / dimension) + '%') | 
|  | 447 | .css(isVertical ? 'top' : 'left', '') | 
|  | 448 | } | 
|  | 449 |  | 
|  | 450 | Tooltip.prototype.setContent = function () { | 
|  | 451 | var $tip  = this.tip() | 
|  | 452 | var title = this.getTitle() | 
|  | 453 |  | 
|  | 454 | if (this.options.html) { | 
|  | 455 | if (this.options.sanitize) { | 
|  | 456 | title = sanitizeHtml(title, this.options.whiteList, this.options.sanitizeFn) | 
|  | 457 | } | 
|  | 458 |  | 
|  | 459 | $tip.find('.tooltip-inner').html(title) | 
|  | 460 | } else { | 
|  | 461 | $tip.find('.tooltip-inner').text(title) | 
|  | 462 | } | 
|  | 463 |  | 
|  | 464 | $tip.removeClass('fade in top bottom left right') | 
|  | 465 | } | 
|  | 466 |  | 
|  | 467 | Tooltip.prototype.hide = function (callback) { | 
|  | 468 | var that = this | 
|  | 469 | var $tip = $(this.$tip) | 
|  | 470 | var e    = $.Event('hide.bs.' + this.type) | 
|  | 471 |  | 
|  | 472 | function complete() { | 
|  | 473 | if (that.hoverState != 'in') $tip.detach() | 
|  | 474 | if (that.$element) { // TODO: Check whether guarding this code with this `if` is really necessary. | 
|  | 475 | that.$element | 
|  | 476 | .removeAttr('aria-describedby') | 
|  | 477 | .trigger('hidden.bs.' + that.type) | 
|  | 478 | } | 
|  | 479 | callback && callback() | 
|  | 480 | } | 
|  | 481 |  | 
|  | 482 | this.$element.trigger(e) | 
|  | 483 |  | 
|  | 484 | if (e.isDefaultPrevented()) return | 
|  | 485 |  | 
|  | 486 | $tip.removeClass('in') | 
|  | 487 |  | 
|  | 488 | $.support.transition && $tip.hasClass('fade') ? | 
|  | 489 | $tip | 
|  | 490 | .one('bsTransitionEnd', complete) | 
|  | 491 | .emulateTransitionEnd(Tooltip.TRANSITION_DURATION) : | 
|  | 492 | complete() | 
|  | 493 |  | 
|  | 494 | this.hoverState = null | 
|  | 495 |  | 
|  | 496 | return this | 
|  | 497 | } | 
|  | 498 |  | 
|  | 499 | Tooltip.prototype.fixTitle = function () { | 
|  | 500 | var $e = this.$element | 
|  | 501 | if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') { | 
|  | 502 | $e.attr('data-original-title', $e.attr('title') || '').attr('title', '') | 
|  | 503 | } | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | Tooltip.prototype.hasContent = function () { | 
|  | 507 | return this.getTitle() | 
|  | 508 | } | 
|  | 509 |  | 
|  | 510 | Tooltip.prototype.getPosition = function ($element) { | 
|  | 511 | $element   = $element || this.$element | 
|  | 512 |  | 
|  | 513 | var el     = $element[0] | 
|  | 514 | var isBody = el.tagName == 'BODY' | 
|  | 515 |  | 
|  | 516 | var elRect    = el.getBoundingClientRect() | 
|  | 517 | if (elRect.width == null) { | 
|  | 518 | // width and height are missing in IE8, so compute them manually; see https://github.com/twbs/bootstrap/issues/14093 | 
|  | 519 | elRect = $.extend({}, elRect, { width: elRect.right - elRect.left, height: elRect.bottom - elRect.top }) | 
|  | 520 | } | 
|  | 521 | var isSvg = window.SVGElement && el instanceof window.SVGElement | 
|  | 522 | // Avoid using $.offset() on SVGs since it gives incorrect results in jQuery 3. | 
|  | 523 | // See https://github.com/twbs/bootstrap/issues/20280 | 
|  | 524 | var elOffset  = isBody ? { top: 0, left: 0 } : (isSvg ? null : $element.offset()) | 
|  | 525 | var scroll    = { scroll: isBody ? document.documentElement.scrollTop || document.body.scrollTop : $element.scrollTop() } | 
|  | 526 | var outerDims = isBody ? { width: $(window).width(), height: $(window).height() } : null | 
|  | 527 |  | 
|  | 528 | return $.extend({}, elRect, scroll, outerDims, elOffset) | 
|  | 529 | } | 
|  | 530 |  | 
|  | 531 | Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) { | 
|  | 532 | return placement == 'bottom' ? { top: pos.top + pos.height,   left: pos.left + pos.width / 2 - actualWidth / 2 } : | 
|  | 533 | placement == 'top'    ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } : | 
|  | 534 | placement == 'left'   ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } : | 
|  | 535 | /* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width } | 
|  | 536 |  | 
|  | 537 | } | 
|  | 538 |  | 
|  | 539 | Tooltip.prototype.getViewportAdjustedDelta = function (placement, pos, actualWidth, actualHeight) { | 
|  | 540 | var delta = { top: 0, left: 0 } | 
|  | 541 | if (!this.$viewport) return delta | 
|  | 542 |  | 
|  | 543 | var viewportPadding = this.options.viewport && this.options.viewport.padding || 0 | 
|  | 544 | var viewportDimensions = this.getPosition(this.$viewport) | 
|  | 545 |  | 
|  | 546 | if (/right|left/.test(placement)) { | 
|  | 547 | var topEdgeOffset    = pos.top - viewportPadding - viewportDimensions.scroll | 
|  | 548 | var bottomEdgeOffset = pos.top + viewportPadding - viewportDimensions.scroll + actualHeight | 
|  | 549 | if (topEdgeOffset < viewportDimensions.top) { // top overflow | 
|  | 550 | delta.top = viewportDimensions.top - topEdgeOffset | 
|  | 551 | } else if (bottomEdgeOffset > viewportDimensions.top + viewportDimensions.height) { // bottom overflow | 
|  | 552 | delta.top = viewportDimensions.top + viewportDimensions.height - bottomEdgeOffset | 
|  | 553 | } | 
|  | 554 | } else { | 
|  | 555 | var leftEdgeOffset  = pos.left - viewportPadding | 
|  | 556 | var rightEdgeOffset = pos.left + viewportPadding + actualWidth | 
|  | 557 | if (leftEdgeOffset < viewportDimensions.left) { // left overflow | 
|  | 558 | delta.left = viewportDimensions.left - leftEdgeOffset | 
|  | 559 | } else if (rightEdgeOffset > viewportDimensions.right) { // right overflow | 
|  | 560 | delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset | 
|  | 561 | } | 
|  | 562 | } | 
|  | 563 |  | 
|  | 564 | return delta | 
|  | 565 | } | 
|  | 566 |  | 
|  | 567 | Tooltip.prototype.getTitle = function () { | 
|  | 568 | var title | 
|  | 569 | var $e = this.$element | 
|  | 570 | var o  = this.options | 
|  | 571 |  | 
|  | 572 | title = $e.attr('data-original-title') | 
|  | 573 | || (typeof o.title == 'function' ? o.title.call($e[0]) :  o.title) | 
|  | 574 |  | 
|  | 575 | return title | 
|  | 576 | } | 
|  | 577 |  | 
|  | 578 | Tooltip.prototype.getUID = function (prefix) { | 
|  | 579 | do prefix += ~~(Math.random() * 1000000) | 
|  | 580 | while (document.getElementById(prefix)) | 
|  | 581 | return prefix | 
|  | 582 | } | 
|  | 583 |  | 
|  | 584 | Tooltip.prototype.tip = function () { | 
|  | 585 | if (!this.$tip) { | 
|  | 586 | this.$tip = $(this.options.template) | 
|  | 587 | if (this.$tip.length != 1) { | 
|  | 588 | throw new Error(this.type + ' `template` option must consist of exactly 1 top-level element!') | 
|  | 589 | } | 
|  | 590 | } | 
|  | 591 | return this.$tip | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | Tooltip.prototype.arrow = function () { | 
|  | 595 | return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow')) | 
|  | 596 | } | 
|  | 597 |  | 
|  | 598 | Tooltip.prototype.enable = function () { | 
|  | 599 | this.enabled = true | 
|  | 600 | } | 
|  | 601 |  | 
|  | 602 | Tooltip.prototype.disable = function () { | 
|  | 603 | this.enabled = false | 
|  | 604 | } | 
|  | 605 |  | 
|  | 606 | Tooltip.prototype.toggleEnabled = function () { | 
|  | 607 | this.enabled = !this.enabled | 
|  | 608 | } | 
|  | 609 |  | 
|  | 610 | Tooltip.prototype.toggle = function (e) { | 
|  | 611 | var self = this | 
|  | 612 | if (e) { | 
|  | 613 | self = $(e.currentTarget).data('bs.' + this.type) | 
|  | 614 | if (!self) { | 
|  | 615 | self = new this.constructor(e.currentTarget, this.getDelegateOptions()) | 
|  | 616 | $(e.currentTarget).data('bs.' + this.type, self) | 
|  | 617 | } | 
|  | 618 | } | 
|  | 619 |  | 
|  | 620 | if (e) { | 
|  | 621 | self.inState.click = !self.inState.click | 
|  | 622 | if (self.isInStateTrue()) self.enter(self) | 
|  | 623 | else self.leave(self) | 
|  | 624 | } else { | 
|  | 625 | self.tip().hasClass('in') ? self.leave(self) : self.enter(self) | 
|  | 626 | } | 
|  | 627 | } | 
|  | 628 |  | 
|  | 629 | Tooltip.prototype.destroy = function () { | 
|  | 630 | var that = this | 
|  | 631 | clearTimeout(this.timeout) | 
|  | 632 | this.hide(function () { | 
|  | 633 | that.$element.off('.' + that.type).removeData('bs.' + that.type) | 
|  | 634 | if (that.$tip) { | 
|  | 635 | that.$tip.detach() | 
|  | 636 | } | 
|  | 637 | that.$tip = null | 
|  | 638 | that.$arrow = null | 
|  | 639 | that.$viewport = null | 
|  | 640 | that.$element = null | 
|  | 641 | }) | 
|  | 642 | } | 
|  | 643 |  | 
|  | 644 | Tooltip.prototype.sanitizeHtml = function (unsafeHtml) { | 
|  | 645 | return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn) | 
|  | 646 | } | 
|  | 647 |  | 
|  | 648 | // TOOLTIP PLUGIN DEFINITION | 
|  | 649 | // ========================= | 
|  | 650 |  | 
|  | 651 | function Plugin(option) { | 
|  | 652 | return this.each(function () { | 
|  | 653 | var $this   = $(this) | 
|  | 654 | var data    = $this.data('bs.tooltip') | 
|  | 655 | var options = typeof option == 'object' && option | 
|  | 656 |  | 
|  | 657 | if (!data && /destroy|hide/.test(option)) return | 
|  | 658 | if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options))) | 
|  | 659 | if (typeof option == 'string') data[option]() | 
|  | 660 | }) | 
|  | 661 | } | 
|  | 662 |  | 
|  | 663 | var old = $.fn.tooltip | 
|  | 664 |  | 
|  | 665 | $.fn.tooltip             = Plugin | 
|  | 666 | $.fn.tooltip.Constructor = Tooltip | 
|  | 667 |  | 
|  | 668 |  | 
|  | 669 | // TOOLTIP NO CONFLICT | 
|  | 670 | // =================== | 
|  | 671 |  | 
|  | 672 | $.fn.tooltip.noConflict = function () { | 
|  | 673 | $.fn.tooltip = old | 
|  | 674 | return this | 
|  | 675 | } | 
|  | 676 |  | 
|  | 677 | }(jQuery); | 
|  | 678 |  | 
|  | 679 | /* ======================================================================== | 
|  | 680 | * Bootstrap: popover.js v3.4.1 | 
|  | 681 | * https://getbootstrap.com/docs/3.4/javascript/#popovers | 
|  | 682 | * ======================================================================== | 
|  | 683 | * Copyright 2011-2019 Twitter, Inc. | 
|  | 684 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE) | 
|  | 685 | * ======================================================================== */ | 
|  | 686 |  | 
|  | 687 |  | 
|  | 688 | +function ($) { | 
|  | 689 | 'use strict'; | 
|  | 690 |  | 
|  | 691 | // POPOVER PUBLIC CLASS DEFINITION | 
|  | 692 | // =============================== | 
|  | 693 |  | 
|  | 694 | var Popover = function (element, options) { | 
|  | 695 | this.init('popover', element, options) | 
|  | 696 | } | 
|  | 697 |  | 
|  | 698 | if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js') | 
|  | 699 |  | 
|  | 700 | Popover.VERSION  = '3.4.1' | 
|  | 701 |  | 
|  | 702 | Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, { | 
|  | 703 | placement: 'right', | 
|  | 704 | trigger: 'click', | 
|  | 705 | content: '', | 
|  | 706 | template: '<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-title"></h3><div class="popover-content"></div></div>' | 
|  | 707 | }) | 
|  | 708 |  | 
|  | 709 |  | 
|  | 710 | // NOTE: POPOVER EXTENDS tooltip.js | 
|  | 711 | // ================================ | 
|  | 712 |  | 
|  | 713 | Popover.prototype = $.extend({}, $.fn.tooltip.Constructor.prototype) | 
|  | 714 |  | 
|  | 715 | Popover.prototype.constructor = Popover | 
|  | 716 |  | 
|  | 717 | Popover.prototype.getDefaults = function () { | 
|  | 718 | return Popover.DEFAULTS | 
|  | 719 | } | 
|  | 720 |  | 
|  | 721 | Popover.prototype.setContent = function () { | 
|  | 722 | var $tip    = this.tip() | 
|  | 723 | var title   = this.getTitle() | 
|  | 724 | var content = this.getContent() | 
|  | 725 |  | 
|  | 726 | if (this.options.html) { | 
|  | 727 | var typeContent = typeof content | 
|  | 728 |  | 
|  | 729 | if (this.options.sanitize) { | 
|  | 730 | title = this.sanitizeHtml(title) | 
|  | 731 |  | 
|  | 732 | if (typeContent === 'string') { | 
|  | 733 | content = this.sanitizeHtml(content) | 
|  | 734 | } | 
|  | 735 | } | 
|  | 736 |  | 
|  | 737 | $tip.find('.popover-title').html(title) | 
|  | 738 | $tip.find('.popover-content').children().detach().end()[ | 
|  | 739 | typeContent === 'string' ? 'html' : 'append' | 
|  | 740 | ](content) | 
|  | 741 | } else { | 
|  | 742 | $tip.find('.popover-title').text(title) | 
|  | 743 | $tip.find('.popover-content').children().detach().end().text(content) | 
|  | 744 | } | 
|  | 745 |  | 
|  | 746 | $tip.removeClass('fade top bottom left right in') | 
|  | 747 |  | 
|  | 748 | // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do | 
|  | 749 | // this manually by checking the contents. | 
|  | 750 | if (!$tip.find('.popover-title').html()) $tip.find('.popover-title').hide() | 
|  | 751 | } | 
|  | 752 |  | 
|  | 753 | Popover.prototype.hasContent = function () { | 
|  | 754 | return this.getTitle() || this.getContent() | 
|  | 755 | } | 
|  | 756 |  | 
|  | 757 | Popover.prototype.getContent = function () { | 
|  | 758 | var $e = this.$element | 
|  | 759 | var o  = this.options | 
|  | 760 |  | 
|  | 761 | return $e.attr('data-content') | 
|  | 762 | || (typeof o.content == 'function' ? | 
|  | 763 | o.content.call($e[0]) : | 
|  | 764 | o.content) | 
|  | 765 | } | 
|  | 766 |  | 
|  | 767 | Popover.prototype.arrow = function () { | 
|  | 768 | return (this.$arrow = this.$arrow || this.tip().find('.arrow')) | 
|  | 769 | } | 
|  | 770 |  | 
|  | 771 |  | 
|  | 772 | // POPOVER PLUGIN DEFINITION | 
|  | 773 | // ========================= | 
|  | 774 |  | 
|  | 775 | function Plugin(option) { | 
|  | 776 | return this.each(function () { | 
|  | 777 | var $this   = $(this) | 
|  | 778 | var data    = $this.data('bs.popover') | 
|  | 779 | var options = typeof option == 'object' && option | 
|  | 780 |  | 
|  | 781 | if (!data && /destroy|hide/.test(option)) return | 
|  | 782 | if (!data) $this.data('bs.popover', (data = new Popover(this, options))) | 
|  | 783 | if (typeof option == 'string') data[option]() | 
|  | 784 | }) | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | var old = $.fn.popover | 
|  | 788 |  | 
|  | 789 | $.fn.popover             = Plugin | 
|  | 790 | $.fn.popover.Constructor = Popover | 
|  | 791 |  | 
|  | 792 |  | 
|  | 793 | // POPOVER NO CONFLICT | 
|  | 794 | // =================== | 
|  | 795 |  | 
|  | 796 | $.fn.popover.noConflict = function () { | 
|  | 797 | $.fn.popover = old | 
|  | 798 | return this | 
|  | 799 | } | 
|  | 800 |  | 
|  | 801 | }(jQuery); |