rails_admin 2.1.1 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of rails_admin might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/app/assets/javascripts/rails_admin/jquery.migrate.js +3 -0
- data/app/assets/javascripts/rails_admin/ra.filter-box.js +1 -4
- data/app/assets/javascripts/rails_admin/ra.nested-form-hooks.js +3 -3
- data/app/assets/javascripts/rails_admin/ra.widgets.js +1 -1
- data/app/assets/javascripts/rails_admin/rails_admin.js +2 -1
- data/app/assets/javascripts/rails_admin/ui.js +2 -2
- data/app/helpers/rails_admin/form_builder.rb +2 -0
- data/lib/rails_admin/extensions/paper_trail/auditing_adapter.rb +1 -1
- data/lib/rails_admin/version.rb +2 -2
- data/vendor/assets/javascripts/rails_admin/bootstrap-datetimepicker.js +317 -150
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-affix.js +50 -28
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-alert.js +10 -7
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-button.js +35 -20
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-carousel.js +48 -25
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-collapse.js +70 -28
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-dropdown.js +56 -42
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-modal.js +118 -40
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-popover.js +26 -16
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-scrollspy.js +29 -27
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-tab.js +46 -19
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-tooltip.js +280 -60
- data/vendor/assets/javascripts/rails_admin/bootstrap/bootstrap-transition.js +5 -5
- data/vendor/assets/javascripts/rails_admin/jquery.pjax.js +317 -160
- data/vendor/assets/javascripts/rails_admin/moment-with-locales.js +11210 -9290
- metadata +3 -3
- data/config/initializers/devise_patch.rb +0 -9
@@ -1,8 +1,8 @@
|
|
1
1
|
/* ========================================================================
|
2
|
-
* Bootstrap: popover.js v3.
|
3
|
-
*
|
2
|
+
* Bootstrap: popover.js v3.4.1
|
3
|
+
* https://getbootstrap.com/docs/3.4/javascript/#popovers
|
4
4
|
* ========================================================================
|
5
|
-
* Copyright 2011-
|
5
|
+
* Copyright 2011-2019 Twitter, Inc.
|
6
6
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
7
7
|
* ======================================================================== */
|
8
8
|
|
@@ -19,7 +19,7 @@
|
|
19
19
|
|
20
20
|
if (!$.fn.tooltip) throw new Error('Popover requires tooltip.js')
|
21
21
|
|
22
|
-
Popover.VERSION = '3.
|
22
|
+
Popover.VERSION = '3.4.1'
|
23
23
|
|
24
24
|
Popover.DEFAULTS = $.extend({}, $.fn.tooltip.Constructor.DEFAULTS, {
|
25
25
|
placement: 'right',
|
@@ -45,10 +45,25 @@
|
|
45
45
|
var title = this.getTitle()
|
46
46
|
var content = this.getContent()
|
47
47
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
48
|
+
if (this.options.html) {
|
49
|
+
var typeContent = typeof content
|
50
|
+
|
51
|
+
if (this.options.sanitize) {
|
52
|
+
title = this.sanitizeHtml(title)
|
53
|
+
|
54
|
+
if (typeContent === 'string') {
|
55
|
+
content = this.sanitizeHtml(content)
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
$tip.find('.popover-title').html(title)
|
60
|
+
$tip.find('.popover-content').children().detach().end()[
|
61
|
+
typeContent === 'string' ? 'html' : 'append'
|
62
|
+
](content)
|
63
|
+
} else {
|
64
|
+
$tip.find('.popover-title').text(title)
|
65
|
+
$tip.find('.popover-content').children().detach().end().text(content)
|
66
|
+
}
|
52
67
|
|
53
68
|
$tip.removeClass('fade top bottom left right in')
|
54
69
|
|
@@ -67,19 +82,14 @@
|
|
67
82
|
|
68
83
|
return $e.attr('data-content')
|
69
84
|
|| (typeof o.content == 'function' ?
|
70
|
-
|
71
|
-
|
85
|
+
o.content.call($e[0]) :
|
86
|
+
o.content)
|
72
87
|
}
|
73
88
|
|
74
89
|
Popover.prototype.arrow = function () {
|
75
90
|
return (this.$arrow = this.$arrow || this.tip().find('.arrow'))
|
76
91
|
}
|
77
92
|
|
78
|
-
Popover.prototype.tip = function () {
|
79
|
-
if (!this.$tip) this.$tip = $(this.options.template)
|
80
|
-
return this.$tip
|
81
|
-
}
|
82
|
-
|
83
93
|
|
84
94
|
// POPOVER PLUGIN DEFINITION
|
85
95
|
// =========================
|
@@ -90,7 +100,7 @@
|
|
90
100
|
var data = $this.data('bs.popover')
|
91
101
|
var options = typeof option == 'object' && option
|
92
102
|
|
93
|
-
if (!data && option
|
103
|
+
if (!data && /destroy|hide/.test(option)) return
|
94
104
|
if (!data) $this.data('bs.popover', (data = new Popover(this, options)))
|
95
105
|
if (typeof option == 'string') data[option]()
|
96
106
|
})
|
@@ -1,8 +1,8 @@
|
|
1
1
|
/* ========================================================================
|
2
|
-
* Bootstrap: scrollspy.js v3.
|
3
|
-
*
|
2
|
+
* Bootstrap: scrollspy.js v3.4.1
|
3
|
+
* https://getbootstrap.com/docs/3.4/javascript/#scrollspy
|
4
4
|
* ========================================================================
|
5
|
-
* Copyright 2011-
|
5
|
+
* Copyright 2011-2019 Twitter, Inc.
|
6
6
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
7
7
|
* ======================================================================== */
|
8
8
|
|
@@ -14,10 +14,8 @@
|
|
14
14
|
// ==========================
|
15
15
|
|
16
16
|
function ScrollSpy(element, options) {
|
17
|
-
|
18
|
-
|
19
|
-
this.$body = $('body')
|
20
|
-
this.$scrollElement = $(element).is('body') ? $(window) : $(element)
|
17
|
+
this.$body = $(document.body)
|
18
|
+
this.$scrollElement = $(element).is(document.body) ? $(window) : $(element)
|
21
19
|
this.options = $.extend({}, ScrollSpy.DEFAULTS, options)
|
22
20
|
this.selector = (this.options.target || '') + ' .nav li > a'
|
23
21
|
this.offsets = []
|
@@ -25,12 +23,12 @@
|
|
25
23
|
this.activeTarget = null
|
26
24
|
this.scrollHeight = 0
|
27
25
|
|
28
|
-
this.$scrollElement.on('scroll.bs.scrollspy', process)
|
26
|
+
this.$scrollElement.on('scroll.bs.scrollspy', $.proxy(this.process, this))
|
29
27
|
this.refresh()
|
30
28
|
this.process()
|
31
29
|
}
|
32
30
|
|
33
|
-
ScrollSpy.VERSION = '3.
|
31
|
+
ScrollSpy.VERSION = '3.4.1'
|
34
32
|
|
35
33
|
ScrollSpy.DEFAULTS = {
|
36
34
|
offset: 10
|
@@ -41,20 +39,19 @@
|
|
41
39
|
}
|
42
40
|
|
43
41
|
ScrollSpy.prototype.refresh = function () {
|
44
|
-
var
|
45
|
-
var
|
42
|
+
var that = this
|
43
|
+
var offsetMethod = 'offset'
|
44
|
+
var offsetBase = 0
|
45
|
+
|
46
|
+
this.offsets = []
|
47
|
+
this.targets = []
|
48
|
+
this.scrollHeight = this.getScrollHeight()
|
46
49
|
|
47
50
|
if (!$.isWindow(this.$scrollElement[0])) {
|
48
51
|
offsetMethod = 'position'
|
49
52
|
offsetBase = this.$scrollElement.scrollTop()
|
50
53
|
}
|
51
54
|
|
52
|
-
this.offsets = []
|
53
|
-
this.targets = []
|
54
|
-
this.scrollHeight = this.getScrollHeight()
|
55
|
-
|
56
|
-
var self = this
|
57
|
-
|
58
55
|
this.$body
|
59
56
|
.find(this.selector)
|
60
57
|
.map(function () {
|
@@ -69,8 +66,8 @@
|
|
69
66
|
})
|
70
67
|
.sort(function (a, b) { return a[0] - b[0] })
|
71
68
|
.each(function () {
|
72
|
-
|
73
|
-
|
69
|
+
that.offsets.push(this[0])
|
70
|
+
that.targets.push(this[1])
|
74
71
|
})
|
75
72
|
}
|
76
73
|
|
@@ -91,14 +88,15 @@
|
|
91
88
|
return activeTarget != (i = targets[targets.length - 1]) && this.activate(i)
|
92
89
|
}
|
93
90
|
|
94
|
-
if (activeTarget && scrollTop
|
95
|
-
|
91
|
+
if (activeTarget && scrollTop < offsets[0]) {
|
92
|
+
this.activeTarget = null
|
93
|
+
return this.clear()
|
96
94
|
}
|
97
95
|
|
98
96
|
for (i = offsets.length; i--;) {
|
99
97
|
activeTarget != targets[i]
|
100
98
|
&& scrollTop >= offsets[i]
|
101
|
-
&& (
|
99
|
+
&& (offsets[i + 1] === undefined || scrollTop < offsets[i + 1])
|
102
100
|
&& this.activate(targets[i])
|
103
101
|
}
|
104
102
|
}
|
@@ -106,13 +104,11 @@
|
|
106
104
|
ScrollSpy.prototype.activate = function (target) {
|
107
105
|
this.activeTarget = target
|
108
106
|
|
109
|
-
|
110
|
-
.parentsUntil(this.options.target, '.active')
|
111
|
-
.removeClass('active')
|
107
|
+
this.clear()
|
112
108
|
|
113
109
|
var selector = this.selector +
|
114
|
-
|
115
|
-
|
110
|
+
'[data-target="' + target + '"],' +
|
111
|
+
this.selector + '[href="' + target + '"]'
|
116
112
|
|
117
113
|
var active = $(selector)
|
118
114
|
.parents('li')
|
@@ -127,6 +123,12 @@
|
|
127
123
|
active.trigger('activate.bs.scrollspy')
|
128
124
|
}
|
129
125
|
|
126
|
+
ScrollSpy.prototype.clear = function () {
|
127
|
+
$(this.selector)
|
128
|
+
.parentsUntil(this.options.target, '.active')
|
129
|
+
.removeClass('active')
|
130
|
+
}
|
131
|
+
|
130
132
|
|
131
133
|
// SCROLLSPY PLUGIN DEFINITION
|
132
134
|
// ===========================
|
@@ -1,8 +1,8 @@
|
|
1
1
|
/* ========================================================================
|
2
|
-
* Bootstrap: tab.js v3.
|
3
|
-
*
|
2
|
+
* Bootstrap: tab.js v3.4.1
|
3
|
+
* https://getbootstrap.com/docs/3.4/javascript/#tabs
|
4
4
|
* ========================================================================
|
5
|
-
* Copyright 2011-
|
5
|
+
* Copyright 2011-2019 Twitter, Inc.
|
6
6
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
7
7
|
* ======================================================================== */
|
8
8
|
|
@@ -14,10 +14,14 @@
|
|
14
14
|
// ====================
|
15
15
|
|
16
16
|
var Tab = function (element) {
|
17
|
+
// jscs:disable requireDollarBeforejQueryAssignment
|
17
18
|
this.element = $(element)
|
19
|
+
// jscs:enable requireDollarBeforejQueryAssignment
|
18
20
|
}
|
19
21
|
|
20
|
-
Tab.VERSION = '3.
|
22
|
+
Tab.VERSION = '3.4.1'
|
23
|
+
|
24
|
+
Tab.TRANSITION_DURATION = 150
|
21
25
|
|
22
26
|
Tab.prototype.show = function () {
|
23
27
|
var $this = this.element
|
@@ -31,22 +35,30 @@
|
|
31
35
|
|
32
36
|
if ($this.parent('li').hasClass('active')) return
|
33
37
|
|
34
|
-
var previous = $ul.find('.active:last a')
|
35
|
-
var
|
36
|
-
relatedTarget:
|
38
|
+
var $previous = $ul.find('.active:last a')
|
39
|
+
var hideEvent = $.Event('hide.bs.tab', {
|
40
|
+
relatedTarget: $this[0]
|
41
|
+
})
|
42
|
+
var showEvent = $.Event('show.bs.tab', {
|
43
|
+
relatedTarget: $previous[0]
|
37
44
|
})
|
38
45
|
|
39
|
-
$
|
46
|
+
$previous.trigger(hideEvent)
|
47
|
+
$this.trigger(showEvent)
|
40
48
|
|
41
|
-
if (
|
49
|
+
if (showEvent.isDefaultPrevented() || hideEvent.isDefaultPrevented()) return
|
42
50
|
|
43
|
-
var $target = $(selector)
|
51
|
+
var $target = $(document).find(selector)
|
44
52
|
|
45
53
|
this.activate($this.closest('li'), $ul)
|
46
54
|
this.activate($target, $target.parent(), function () {
|
55
|
+
$previous.trigger({
|
56
|
+
type: 'hidden.bs.tab',
|
57
|
+
relatedTarget: $this[0]
|
58
|
+
})
|
47
59
|
$this.trigger({
|
48
60
|
type: 'shown.bs.tab',
|
49
|
-
relatedTarget: previous
|
61
|
+
relatedTarget: $previous[0]
|
50
62
|
})
|
51
63
|
})
|
52
64
|
}
|
@@ -55,15 +67,21 @@
|
|
55
67
|
var $active = container.find('> .active')
|
56
68
|
var transition = callback
|
57
69
|
&& $.support.transition
|
58
|
-
&& $active.hasClass('fade')
|
70
|
+
&& ($active.length && $active.hasClass('fade') || !!container.find('> .fade').length)
|
59
71
|
|
60
72
|
function next() {
|
61
73
|
$active
|
62
74
|
.removeClass('active')
|
63
75
|
.find('> .dropdown-menu > .active')
|
64
76
|
.removeClass('active')
|
77
|
+
.end()
|
78
|
+
.find('[data-toggle="tab"]')
|
79
|
+
.attr('aria-expanded', false)
|
65
80
|
|
66
|
-
element
|
81
|
+
element
|
82
|
+
.addClass('active')
|
83
|
+
.find('[data-toggle="tab"]')
|
84
|
+
.attr('aria-expanded', true)
|
67
85
|
|
68
86
|
if (transition) {
|
69
87
|
element[0].offsetWidth // reflow for transition
|
@@ -72,17 +90,22 @@
|
|
72
90
|
element.removeClass('fade')
|
73
91
|
}
|
74
92
|
|
75
|
-
if (element.parent('.dropdown-menu')) {
|
76
|
-
element
|
93
|
+
if (element.parent('.dropdown-menu').length) {
|
94
|
+
element
|
95
|
+
.closest('li.dropdown')
|
96
|
+
.addClass('active')
|
97
|
+
.end()
|
98
|
+
.find('[data-toggle="tab"]')
|
99
|
+
.attr('aria-expanded', true)
|
77
100
|
}
|
78
101
|
|
79
102
|
callback && callback()
|
80
103
|
}
|
81
104
|
|
82
|
-
transition ?
|
105
|
+
$active.length && transition ?
|
83
106
|
$active
|
84
107
|
.one('bsTransitionEnd', next)
|
85
|
-
.emulateTransitionEnd(
|
108
|
+
.emulateTransitionEnd(Tab.TRANSITION_DURATION) :
|
86
109
|
next()
|
87
110
|
|
88
111
|
$active.removeClass('in')
|
@@ -120,9 +143,13 @@
|
|
120
143
|
// TAB DATA-API
|
121
144
|
// ============
|
122
145
|
|
123
|
-
|
146
|
+
var clickHandler = function (e) {
|
124
147
|
e.preventDefault()
|
125
148
|
Plugin.call($(this), 'show')
|
126
|
-
}
|
149
|
+
}
|
150
|
+
|
151
|
+
$(document)
|
152
|
+
.on('click.bs.tab.data-api', '[data-toggle="tab"]', clickHandler)
|
153
|
+
.on('click.bs.tab.data-api', '[data-toggle="pill"]', clickHandler)
|
127
154
|
|
128
155
|
}(jQuery);
|
@@ -1,31 +1,164 @@
|
|
1
1
|
/* ========================================================================
|
2
|
-
* Bootstrap: tooltip.js v3.
|
3
|
-
*
|
2
|
+
* Bootstrap: tooltip.js v3.4.1
|
3
|
+
* https://getbootstrap.com/docs/3.4/javascript/#tooltip
|
4
4
|
* Inspired by the original jQuery.tipsy by Jason Frame
|
5
5
|
* ========================================================================
|
6
|
-
* Copyright 2011-
|
6
|
+
* Copyright 2011-2019 Twitter, Inc.
|
7
7
|
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
|
8
8
|
* ======================================================================== */
|
9
9
|
|
10
|
-
|
11
10
|
+function ($) {
|
12
11
|
'use strict';
|
13
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
|
+
|
14
144
|
// TOOLTIP PUBLIC CLASS DEFINITION
|
15
145
|
// ===============================
|
16
146
|
|
17
147
|
var Tooltip = function (element, options) {
|
18
|
-
this.type =
|
19
|
-
this.options =
|
20
|
-
this.enabled =
|
21
|
-
this.timeout =
|
22
|
-
this.hoverState =
|
148
|
+
this.type = null
|
149
|
+
this.options = null
|
150
|
+
this.enabled = null
|
151
|
+
this.timeout = null
|
152
|
+
this.hoverState = null
|
23
153
|
this.$element = null
|
154
|
+
this.inState = null
|
24
155
|
|
25
156
|
this.init('tooltip', element, options)
|
26
157
|
}
|
27
158
|
|
28
|
-
Tooltip.VERSION = '3.
|
159
|
+
Tooltip.VERSION = '3.4.1'
|
160
|
+
|
161
|
+
Tooltip.TRANSITION_DURATION = 150
|
29
162
|
|
30
163
|
Tooltip.DEFAULTS = {
|
31
164
|
animation: true,
|
@@ -40,7 +173,10 @@
|
|
40
173
|
viewport: {
|
41
174
|
selector: 'body',
|
42
175
|
padding: 0
|
43
|
-
}
|
176
|
+
},
|
177
|
+
sanitize : true,
|
178
|
+
sanitizeFn : null,
|
179
|
+
whiteList : DefaultWhitelist
|
44
180
|
}
|
45
181
|
|
46
182
|
Tooltip.prototype.init = function (type, element, options) {
|
@@ -48,7 +184,12 @@
|
|
48
184
|
this.type = type
|
49
185
|
this.$element = $(element)
|
50
186
|
this.options = this.getOptions(options)
|
51
|
-
this.$viewport = this.options.viewport && $(this.options.viewport.selector || this.options.viewport)
|
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
|
+
}
|
52
193
|
|
53
194
|
var triggers = this.options.trigger.split(' ')
|
54
195
|
|
@@ -76,7 +217,15 @@
|
|
76
217
|
}
|
77
218
|
|
78
219
|
Tooltip.prototype.getOptions = function (options) {
|
79
|
-
|
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)
|
80
229
|
|
81
230
|
if (options.delay && typeof options.delay == 'number') {
|
82
231
|
options.delay = {
|
@@ -85,6 +234,10 @@
|
|
85
234
|
}
|
86
235
|
}
|
87
236
|
|
237
|
+
if (options.sanitize) {
|
238
|
+
options.template = sanitizeHtml(options.template, options.whiteList, options.sanitizeFn)
|
239
|
+
}
|
240
|
+
|
88
241
|
return options
|
89
242
|
}
|
90
243
|
|
@@ -108,6 +261,15 @@
|
|
108
261
|
$(obj.currentTarget).data('bs.' + this.type, self)
|
109
262
|
}
|
110
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
|
+
|
111
273
|
clearTimeout(self.timeout)
|
112
274
|
|
113
275
|
self.hoverState = 'in'
|
@@ -119,6 +281,14 @@
|
|
119
281
|
}, self.options.delay.show)
|
120
282
|
}
|
121
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
|
+
|
122
292
|
Tooltip.prototype.leave = function (obj) {
|
123
293
|
var self = obj instanceof this.constructor ?
|
124
294
|
obj : $(obj.currentTarget).data('bs.' + this.type)
|
@@ -128,6 +298,12 @@
|
|
128
298
|
$(obj.currentTarget).data('bs.' + this.type, self)
|
129
299
|
}
|
130
300
|
|
301
|
+
if (obj instanceof $.Event) {
|
302
|
+
self.inState[obj.type == 'focusout' ? 'focus' : 'hover'] = false
|
303
|
+
}
|
304
|
+
|
305
|
+
if (self.isInStateTrue()) return
|
306
|
+
|
131
307
|
clearTimeout(self.timeout)
|
132
308
|
|
133
309
|
self.hoverState = 'out'
|
@@ -145,7 +321,7 @@
|
|
145
321
|
if (this.hasContent() && this.enabled) {
|
146
322
|
this.$element.trigger(e)
|
147
323
|
|
148
|
-
var inDom = $.contains(
|
324
|
+
var inDom = $.contains(this.$element[0].ownerDocument.documentElement, this.$element[0])
|
149
325
|
if (e.isDefaultPrevented() || !inDom) return
|
150
326
|
var that = this
|
151
327
|
|
@@ -173,7 +349,8 @@
|
|
173
349
|
.addClass(placement)
|
174
350
|
.data('bs.' + this.type, this)
|
175
351
|
|
176
|
-
this.options.container ? $tip.appendTo(this.options.container) : $tip.insertAfter(this.$element)
|
352
|
+
this.options.container ? $tip.appendTo($(document).find(this.options.container)) : $tip.insertAfter(this.$element)
|
353
|
+
this.$element.trigger('inserted.bs.' + this.type)
|
177
354
|
|
178
355
|
var pos = this.getPosition()
|
179
356
|
var actualWidth = $tip[0].offsetWidth
|
@@ -181,13 +358,12 @@
|
|
181
358
|
|
182
359
|
if (autoPlace) {
|
183
360
|
var orgPlacement = placement
|
184
|
-
var
|
185
|
-
var parentDim = this.getPosition($parent)
|
361
|
+
var viewportDim = this.getPosition(this.$viewport)
|
186
362
|
|
187
|
-
placement = placement == 'bottom' && pos.
|
188
|
-
placement == 'top' && pos.top
|
189
|
-
placement == 'right' && pos.right
|
190
|
-
placement == 'left' && pos.left
|
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' :
|
191
367
|
placement
|
192
368
|
|
193
369
|
$tip
|
@@ -200,14 +376,17 @@
|
|
200
376
|
this.applyPlacement(calculatedOffset, placement)
|
201
377
|
|
202
378
|
var complete = function () {
|
379
|
+
var prevHoverState = that.hoverState
|
203
380
|
that.$element.trigger('shown.bs.' + that.type)
|
204
381
|
that.hoverState = null
|
382
|
+
|
383
|
+
if (prevHoverState == 'out') that.leave(that)
|
205
384
|
}
|
206
385
|
|
207
386
|
$.support.transition && this.$tip.hasClass('fade') ?
|
208
387
|
$tip
|
209
388
|
.one('bsTransitionEnd', complete)
|
210
|
-
.emulateTransitionEnd(
|
389
|
+
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
|
211
390
|
complete()
|
212
391
|
}
|
213
392
|
}
|
@@ -225,8 +404,8 @@
|
|
225
404
|
if (isNaN(marginTop)) marginTop = 0
|
226
405
|
if (isNaN(marginLeft)) marginLeft = 0
|
227
406
|
|
228
|
-
offset.top
|
229
|
-
offset.left
|
407
|
+
offset.top += marginTop
|
408
|
+
offset.left += marginLeft
|
230
409
|
|
231
410
|
// $.fn.offset doesn't round pixel values
|
232
411
|
// so we use setOffset directly with our own function B-0
|
@@ -254,36 +433,50 @@
|
|
254
433
|
if (delta.left) offset.left += delta.left
|
255
434
|
else offset.top += delta.top
|
256
435
|
|
257
|
-
var
|
258
|
-
var
|
259
|
-
var arrowOffsetPosition =
|
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'
|
260
439
|
|
261
440
|
$tip.offset(offset)
|
262
|
-
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition],
|
441
|
+
this.replaceArrow(arrowDelta, $tip[0][arrowOffsetPosition], isVertical)
|
263
442
|
}
|
264
443
|
|
265
|
-
Tooltip.prototype.replaceArrow = function (delta, dimension,
|
266
|
-
this.arrow()
|
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', '')
|
267
448
|
}
|
268
449
|
|
269
450
|
Tooltip.prototype.setContent = function () {
|
270
451
|
var $tip = this.tip()
|
271
452
|
var title = this.getTitle()
|
272
453
|
|
273
|
-
|
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
|
+
|
274
464
|
$tip.removeClass('fade in top bottom left right')
|
275
465
|
}
|
276
466
|
|
277
|
-
Tooltip.prototype.hide = function () {
|
467
|
+
Tooltip.prototype.hide = function (callback) {
|
278
468
|
var that = this
|
279
|
-
var $tip = this
|
469
|
+
var $tip = $(this.$tip)
|
280
470
|
var e = $.Event('hide.bs.' + this.type)
|
281
471
|
|
282
|
-
this.$element.removeAttr('aria-describedby')
|
283
|
-
|
284
472
|
function complete() {
|
285
473
|
if (that.hoverState != 'in') $tip.detach()
|
286
|
-
that.$element
|
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()
|
287
480
|
}
|
288
481
|
|
289
482
|
this.$element.trigger(e)
|
@@ -292,10 +485,10 @@
|
|
292
485
|
|
293
486
|
$tip.removeClass('in')
|
294
487
|
|
295
|
-
$.support.transition &&
|
488
|
+
$.support.transition && $tip.hasClass('fade') ?
|
296
489
|
$tip
|
297
490
|
.one('bsTransitionEnd', complete)
|
298
|
-
.emulateTransitionEnd(
|
491
|
+
.emulateTransitionEnd(Tooltip.TRANSITION_DURATION) :
|
299
492
|
complete()
|
300
493
|
|
301
494
|
this.hoverState = null
|
@@ -305,7 +498,7 @@
|
|
305
498
|
|
306
499
|
Tooltip.prototype.fixTitle = function () {
|
307
500
|
var $e = this.$element
|
308
|
-
if ($e.attr('title') || typeof
|
501
|
+
if ($e.attr('title') || typeof $e.attr('data-original-title') != 'string') {
|
309
502
|
$e.attr('data-original-title', $e.attr('title') || '').attr('title', '')
|
310
503
|
}
|
311
504
|
}
|
@@ -316,20 +509,30 @@
|
|
316
509
|
|
317
510
|
Tooltip.prototype.getPosition = function ($element) {
|
318
511
|
$element = $element || this.$element
|
512
|
+
|
319
513
|
var el = $element[0]
|
320
514
|
var isBody = el.tagName == 'BODY'
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
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)
|
326
529
|
}
|
327
530
|
|
328
531
|
Tooltip.prototype.getCalculatedOffset = function (placement, pos, actualWidth, actualHeight) {
|
329
|
-
return placement == 'bottom' ? { top: pos.top + pos.height, left: pos.left + pos.width / 2 - actualWidth / 2
|
330
|
-
placement == 'top' ? { top: pos.top - actualHeight, left: pos.left + pos.width / 2 - actualWidth / 2
|
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 } :
|
331
534
|
placement == 'left' ? { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left - actualWidth } :
|
332
|
-
/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width
|
535
|
+
/* placement == 'right' */ { top: pos.top + pos.height / 2 - actualHeight / 2, left: pos.left + pos.width }
|
333
536
|
|
334
537
|
}
|
335
538
|
|
@@ -353,7 +556,7 @@
|
|
353
556
|
var rightEdgeOffset = pos.left + viewportPadding + actualWidth
|
354
557
|
if (leftEdgeOffset < viewportDimensions.left) { // left overflow
|
355
558
|
delta.left = viewportDimensions.left - leftEdgeOffset
|
356
|
-
} else if (rightEdgeOffset > viewportDimensions.
|
559
|
+
} else if (rightEdgeOffset > viewportDimensions.right) { // right overflow
|
357
560
|
delta.left = viewportDimensions.left + viewportDimensions.width - rightEdgeOffset
|
358
561
|
}
|
359
562
|
}
|
@@ -379,21 +582,19 @@
|
|
379
582
|
}
|
380
583
|
|
381
584
|
Tooltip.prototype.tip = function () {
|
382
|
-
|
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
|
383
592
|
}
|
384
593
|
|
385
594
|
Tooltip.prototype.arrow = function () {
|
386
595
|
return (this.$arrow = this.$arrow || this.tip().find('.tooltip-arrow'))
|
387
596
|
}
|
388
597
|
|
389
|
-
Tooltip.prototype.validate = function () {
|
390
|
-
if (!this.$element[0].parentNode) {
|
391
|
-
this.hide()
|
392
|
-
this.$element = null
|
393
|
-
this.options = null
|
394
|
-
}
|
395
|
-
}
|
396
|
-
|
397
598
|
Tooltip.prototype.enable = function () {
|
398
599
|
this.enabled = true
|
399
600
|
}
|
@@ -416,14 +617,33 @@
|
|
416
617
|
}
|
417
618
|
}
|
418
619
|
|
419
|
-
|
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
|
+
}
|
420
627
|
}
|
421
628
|
|
422
629
|
Tooltip.prototype.destroy = function () {
|
630
|
+
var that = this
|
423
631
|
clearTimeout(this.timeout)
|
424
|
-
this.hide(
|
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
|
+
})
|
425
642
|
}
|
426
643
|
|
644
|
+
Tooltip.prototype.sanitizeHtml = function (unsafeHtml) {
|
645
|
+
return sanitizeHtml(unsafeHtml, this.options.whiteList, this.options.sanitizeFn)
|
646
|
+
}
|
427
647
|
|
428
648
|
// TOOLTIP PLUGIN DEFINITION
|
429
649
|
// =========================
|
@@ -434,7 +654,7 @@
|
|
434
654
|
var data = $this.data('bs.tooltip')
|
435
655
|
var options = typeof option == 'object' && option
|
436
656
|
|
437
|
-
if (!data && option
|
657
|
+
if (!data && /destroy|hide/.test(option)) return
|
438
658
|
if (!data) $this.data('bs.tooltip', (data = new Tooltip(this, options)))
|
439
659
|
if (typeof option == 'string') data[option]()
|
440
660
|
})
|