PluginProbe ʕ •ᴥ•ʔ
Wordfence Security – Firewall, Malware Scan, and Login Security / 8.2.2
Wordfence Security – Firewall, Malware Scan, and Login Security v8.2.2
8.2.2 8.2.1 8.2.0 3.7.1 3.7.2 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.8.8 3.8.9 3.9.1 4.0.1 4.0.2 4.0.3 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.0.9 5.1.1 5.1.2 5.1.4 5.1.5 5.1.6 5.1.7 5.1.8 5.1.9 5.2.1 5.2.2 5.2.3 5.2.4 5.2.5 5.2.6 5.2.7 5.2.8 5.2.9 5.3.1 5.3.10 5.3.11 5.3.12 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.3.7 5.3.8 5.3.9 6.0.1 6.0.10 6.0.11 6.0.12 6.0.14 6.0.15 6.0.16 6.0.17 6.0.18 6.0.19 6.0.2 6.0.20 6.0.21 6.0.22 6.0.23 6.0.24 6.0.25 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.0.8 6.0.9 6.1.1 6.1.10 6.1.11 6.1.12 6.1.14 6.1.15 6.1.16 6.1.17 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.1.9 6.2.0 6.2.1 6.2.10 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10 6.3.11 6.3.12 6.3.14 6.3.15 6.3.16 6.3.17 6.3.18 6.3.19 6.3.2 6.3.20 6.3.21 6.3.22 6.3.3 6.3.4 6.3.5 6.3.6 6.3.7 6.3.8 6.3.9 7.0.1 7.0.2 7.0.3 7.0.4 7.0.5 7.1.0 7.1.1 7.1.10 7.1.11 7.1.12 7.1.14 7.1.15 7.1.16 7.1.17 7.1.18 7.1.19 7.1.2 7.1.20 7.1.3 7.1.4 7.1.5 7.1.6 7.1.7 7.1.8 7.1.9 7.10.0 7.10.1 7.10.2 7.10.3 7.10.4 7.10.5 7.10.6 7.10.7 7.11.0 7.11.1 7.11.2 7.11.3 7.11.4 7.11.5 7.11.6 7.11.7 7.2.1 7.2.2 7.2.3 7.2.4 7.2.5 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.4.0 7.4.1 7.4.10 7.4.11 7.4.12 7.4.14 7.4.2 7.4.3 trunk 7.4.4 1.1 7.4.5 1.2 7.4.6 1.3 7.4.7 1.3.1 7.4.8 1.3.2 7.4.9 1.3.3 7.5.0 1.4.2 7.5.1 1.4.3 7.5.10 1.4.4 7.5.11 1.4.5 7.5.2 1.4.6 7.5.3 1.4.7 7.5.4 1.4.8 7.5.5 1.5.1 7.5.6 1.5.2 7.5.7 1.5.3 7.5.8 1.5.4 7.5.9 1.5.5 7.6.0 1.5.6 7.6.1 2.0.1 7.6.2 2.0.2 7.7.0 2.0.3 7.7.1 2.0.5 7.8.0 2.0.6 7.8.1 2.0.7 7.8.2 2.1.0 7.9.0 2.1.1 7.9.1 2.1.2 7.9.2 2.1.3 7.9.3 2.1.4 8.0.0 2.1.5 8.0.1 3.0.2 8.0.2 3.0.3 8.0.3 3.0.4 8.0.4 3.0.5 8.0.5 3.0.6 8.1.0 3.0.7 8.1.1 3.0.8 8.1.2 3.0.9 8.1.3 3.1.0 8.1.4 3.1.1 v1.4.1 3.1.2 3.1.4 3.1.6 3.2.1 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.4.1 3.4.4 3.4.5 3.5.1 3.5.2 3.6.1 3.6.3 3.6.4 3.6.5 3.6.6 3.6.7 3.6.8 3.6.9
wordfence / js / wfpopover.1778685035.js
wordfence / js Last commit date
admin.1778685035.js 3 weeks ago admin.ajaxWatcher.1778685035.js 3 weeks ago chart.umd.1778685035.js 3 weeks ago jquery.qrcode.min.1778685035.js 3 weeks ago vue.esm-browser.prod.1778685035.js 3 weeks ago wfdashboard.1778685035.js 3 weeks ago wfdropdown.1778685035.js 3 weeks ago wfglobal.1778685035.js 3 weeks ago wfi18n.1778685035.js 3 weeks ago wfonboarding.1778685035.js 3 weeks ago wfpopover.1778685035.js 3 weeks ago wordfence.1778685035.js 3 weeks ago
wfpopover.1778685035.js
786 lines
1 /* ========================================================================
2 * Bootstrap: tooltip.js v3.4.1 and wfpopover.js v3.4.1 (adapted to WF prefix)
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 WFTooltip = 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('wftooltip', element, options)
157 }
158
159 WFTooltip.VERSION = '3.4.1'
160
161 WFTooltip.TRANSITION_DURATION = 150
162
163 WFTooltip.DEFAULTS = {
164 animation: true,
165 placement: 'top',
166 selector: false,
167 template: '<div class="wftooltip" role="wftooltip"><div class="wftooltip-arrow"></div><div class="wftooltip-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 WFTooltip.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 WFTooltip.prototype.getDefaults = function () {
216 return WFTooltip.DEFAULTS
217 }
218
219 WFTooltip.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 WFTooltip.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 WFTooltip.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('wf-in') || self.hoverState == 'wf-in') {
269 self.hoverState = 'wf-in'
270 return
271 }
272
273 clearTimeout(self.timeout)
274
275 self.hoverState = 'wf-in'
276
277 if (!self.options.delay || !self.options.delay.show) return self.show()
278
279 self.timeout = setTimeout(function () {
280 if (self.hoverState == 'wf-in') self.show()
281 }, self.options.delay.show)
282 }
283
284 WFTooltip.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 WFTooltip.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 = 'wf-out'
310
311 if (!self.options.delay || !self.options.delay.hide) return self.hide()
312
313 self.timeout = setTimeout(function () {
314 if (self.hoverState == 'wf-out') self.hide()
315 }, self.options.delay.hide)
316 }
317
318 WFTooltip.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('wf-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, '') || 'wf-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 == 'wf-bottom' && pos.bottom + actualHeight > viewportDim.bottom ? 'wf-top' :
364 placement == 'wf-top' && pos.top - actualHeight < viewportDim.top ? 'wf-bottom' :
365 placement == 'wf-right' && pos.right + actualWidth > viewportDim.width ? 'wf-left' :
366 placement == 'wf-left' && pos.left - actualWidth < viewportDim.left ? 'wf-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 == 'wf-out') that.leave(that)
384 }
385
386 $.support.transition && this.$tip.hasClass('wf-fade') ?
387 $tip
388 .one('bsTransitionEnd', complete)
389 .emulateTransitionEnd(WFTooltip.TRANSITION_DURATION) :
390 complete()
391 }
392 }
393
394 WFTooltip.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('wf-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 == 'wf-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 WFTooltip.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 WFTooltip.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('.wftooltip-inner').html(title)
460 } else {
461 $tip.find('.wftooltip-inner').text(title)
462 }
463
464 $tip.removeClass('wf-fade wf-in wf-top wf-bottom wf-left wf-right')
465 }
466
467 WFTooltip.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('wf-in')
487
488 $.support.transition && $tip.hasClass('wf-fade') ?
489 $tip
490 .one('bsTransitionEnd', complete)
491 .emulateTransitionEnd(WFTooltip.TRANSITION_DURATION) :
492 complete()
493
494 this.hoverState = null
495
496 return this
497 }
498
499 WFTooltip.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 WFTooltip.prototype.hasContent = function () {
507 return this.getTitle()
508 }
509
510 WFTooltip.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 WFTooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
532 return placement == 'wf-bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2 } :
533 placement == 'wf-top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2 } :
534 placement == 'wf-left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
535 /* placement == 'wf-right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
536
537 }
538
539 WFTooltip.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 WFTooltip.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 WFTooltip.prototype.getUID = function (prefix) {
579 do prefix += ~~(Math.random() * 1000000)
580 while (document.getElementById(prefix))
581 return prefix
582 }
583
584 WFTooltip.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 WFTooltip.prototype.arrow = function () {
595 return (this.$arrow = this.$arrow || this.tip().find('.wftooltip-arrow'))
596 }
597
598 WFTooltip.prototype.enable = function () {
599 this.enabled = true
600 }
601
602 WFTooltip.prototype.disable = function () {
603 this.enabled = false
604 }
605
606 WFTooltip.prototype.toggleEnabled = function () {
607 this.enabled = !this.enabled
608 }
609
610 WFTooltip.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('wf-in') ? self.leave(self) : self.enter(self)
626 }
627 }
628
629 WFTooltip.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 WFTooltip.prototype.sanitizeHtml = function (unsafeHtml) {
645 return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
646 }
647
648 // TOOLTIP PLUGIN DEFINITION
649 // =========================
650
651 function WFPlugin(option) {
652 return this.each(function () {
653 var $this = $(this)
654 var data = $this.data('bs.wftooltip')
655 var options = typeof option == 'object' && option
656
657 if (!data && /destroy|hide/.test(option)) return
658 if (!data) $this.data('bs.wftooltip', (data = new WFTooltip(this, options)))
659 if (typeof option == 'string') data[option]()
660 })
661 }
662
663 var old = $.fn.wftooltip
664
665 $.fn.wftooltip = WFPlugin
666 $.fn.wftooltip.Constructor = WFTooltip
667
668
669 // TOOLTIP NO CONFLICT
670 // ===================
671
672 $.fn.wftooltip.noConflict = function () {
673 $.fn.wftooltip = old
674 return this
675 }
676
677 // POPOVER PUBLIC CLASS DEFINITION
678 // ===============================
679
680 var WFPopover = function (element, options) {
681 this.init('wfpopover', element, options)
682 }
683
684 WFPopover.VERSION = '3.4.1'
685
686 WFPopover.DEFAULTS = $.extend({}, $.fn.wftooltip.Constructor.DEFAULTS, {
687 placement: 'wf-right',
688 trigger: 'click',
689 content: '',
690 template: '<div class="wfpopover" role="wftooltip"><div class="wf-arrow"></div><h3 class="wfpopover-title"></h3><div class="wfpopover-content"></div></div>'
691 })
692
693
694 // NOTE: POPOVER EXTENDS wftooltip.js
695 // ================================
696
697 WFPopover.prototype = $.extend({}, $.fn.wftooltip.Constructor.prototype)
698
699 WFPopover.prototype.constructor = WFPopover
700
701 WFPopover.prototype.getDefaults = function () {
702 return WFPopover.DEFAULTS
703 }
704
705 WFPopover.prototype.setContent = function () {
706 var $tip = this.tip()
707 var title = this.getTitle()
708 var content = this.getContent()
709
710 if (this.options.html) {
711 var typeContent = typeof content
712
713 if (this.options.sanitize) {
714 title = this.sanitizeHtml(title)
715
716 if (typeContent === 'string') {
717 content = this.sanitizeHtml(content)
718 }
719 }
720
721 $tip.find('.wfpopover-title').html(title)
722 $tip.find('.wfpopover-content').children().detach().end()[
723 typeContent === 'string' ? 'html' : 'append'
724 ](content)
725 } else {
726 $tip.find('.wfpopover-title').text(title)
727 $tip.find('.wfpopover-content').children().detach().end().text(content)
728 }
729
730 $tip.removeClass('wf-fade wf-top wf-bottom wf-left wf-right wf-in')
731
732 // IE8 doesn't accept hiding via the `:empty` pseudo selector, we have to do
733 // this manually by checking the contents.
734 if (!$tip.find('.wfpopover-title').html()) $tip.find('.wfpopover-title').hide()
735 }
736
737 WFPopover.prototype.hasContent = function () {
738 return this.getTitle() || this.getContent()
739 }
740
741 WFPopover.prototype.getContent = function () {
742 var $e = this.$element
743 var o = this.options
744
745 return $e.attr('data-content')
746 || (typeof o.content == 'function' ?
747 o.content.call($e[0]) :
748 o.content)
749 }
750
751 WFPopover.prototype.arrow = function () {
752 return (this.$arrow = this.$arrow || this.tip().find('.wf-arrow'))
753 }
754
755
756 // POPOVER PLUGIN DEFINITION
757 // =========================
758
759 function WFPlugin(option) {
760 return this.each(function () {
761 var $this = $(this)
762 var data = $this.data('bs.wfpopover')
763 var options = typeof option == 'object' && option
764
765 if (!data && /destroy|hide/.test(option)) return
766 if (!data) $this.data('bs.wfpopover', (data = new WFPopover(this, options)))
767 if (typeof option == 'string') data[option]()
768 })
769 }
770
771 var old = $.fn.wfpopover
772
773 $.fn.wfpopover = WFPlugin
774 $.fn.wfpopover.Constructor = WFPopover
775
776
777 // POPOVER NO CONFLICT
778 // ===================
779
780 $.fn.wfpopover.noConflict = function () {
781 $.fn.wfpopover = old
782 return this
783 }
784
785 }(jQuery);
786