good_job 1.9.4 → 1.11.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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +82 -0
  3. data/README.md +47 -0
  4. data/engine/app/assets/vendor/bootstrap/bootstrap.bundle.min.js +7 -0
  5. data/engine/app/assets/vendor/bootstrap/bootstrap.min.css +7 -0
  6. data/engine/app/controllers/good_job/assets_controller.rb +29 -0
  7. data/engine/app/controllers/good_job/dashboards_controller.rb +1 -1
  8. data/engine/app/controllers/good_job/jobs_controller.rb +9 -0
  9. data/engine/app/views/good_job/dashboards/index.html.erb +1 -1
  10. data/engine/app/views/layouts/good_job/base.html.erb +21 -12
  11. data/engine/app/views/shared/_jobs_table.erb +13 -1
  12. data/engine/app/views/shared/icons/_check.html.erb +4 -0
  13. data/engine/app/views/shared/icons/_exclamation.html.erb +4 -0
  14. data/engine/app/views/shared/icons/_trash.html.erb +5 -0
  15. data/engine/config/routes.rb +10 -1
  16. data/lib/generators/good_job/install_generator.rb +5 -15
  17. data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +27 -0
  18. data/lib/generators/good_job/templates/{migration.rb.erb → update/migrations/01_create_good_jobs.rb} +3 -3
  19. data/lib/generators/good_job/templates/update/migrations/02_add_active_job_id_concurrency_key_cron_key_to_good_jobs.rb +15 -0
  20. data/lib/generators/good_job/templates/update/migrations/03_add_active_job_id_index_and_concurrency_key_index_to_good_jobs.rb +32 -0
  21. data/lib/generators/good_job/update_generator.rb +29 -0
  22. data/lib/good_job/active_job_extensions.rb +4 -0
  23. data/lib/good_job/active_job_extensions/concurrency.rb +68 -0
  24. data/lib/good_job/current_execution.rb +12 -5
  25. data/lib/good_job/job.rb +43 -6
  26. data/lib/good_job/lockable.rb +114 -57
  27. data/lib/good_job/poller.rb +7 -3
  28. data/lib/good_job/version.rb +1 -1
  29. metadata +30 -5
  30. data/engine/app/assets/vendor/bootstrap/bootstrap-native.js +0 -1662
  31. data/engine/app/assets/vendor/bootstrap/bootstrap.css +0 -10258
@@ -5,11 +5,13 @@ module GoodJob # :nodoc:
5
5
  # Pollers regularly wake up execution threads to check for new work.
6
6
  #
7
7
  class Poller
8
+ TIMEOUT_INTERVAL = 5
9
+
8
10
  # Defaults for instance of Concurrent::TimerTask.
9
11
  # The timer controls how and when sleeping threads check for new work.
10
12
  DEFAULT_TIMER_OPTIONS = {
11
13
  execution_interval: Configuration::DEFAULT_POLL_INTERVAL,
12
- timeout_interval: 1,
14
+ timeout_interval: TIMEOUT_INTERVAL,
13
15
  run_now: true,
14
16
  }.freeze
15
17
 
@@ -49,9 +51,11 @@ module GoodJob # :nodoc:
49
51
 
50
52
  # Tests whether the timer is shutdown.
51
53
  # @return [true, false, nil]
52
- delegate :shutdown?, to: :timer, allow_nil: true
54
+ def shutdown?
55
+ timer ? timer.shutdown? : true
56
+ end
53
57
 
54
- # Shut down the notifier.
58
+ # Shut down the poller.
55
59
  # Use {#shutdown?} to determine whether threads have stopped.
56
60
  # @param timeout [nil, Numeric] Seconds to wait for active threads.
57
61
  # * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
@@ -1,4 +1,4 @@
1
1
  module GoodJob
2
2
  # GoodJob gem version.
3
- VERSION = '1.9.4'.freeze
3
+ VERSION = '1.11.0'.freeze
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: good_job
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.4
4
+ version: 1.11.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Sheldon
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-05-18 00:00:00.000000000 Z
11
+ date: 2021-07-07 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activejob
@@ -94,6 +94,20 @@ dependencies:
94
94
  - - ">="
95
95
  - !ruby/object:Gem::Version
96
96
  version: '2.0'
97
+ - !ruby/object:Gem::Dependency
98
+ name: benchmark-ips
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - '='
102
+ - !ruby/object:Gem::Version
103
+ version: 2.8.4
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - '='
109
+ - !ruby/object:Gem::Version
110
+ version: 2.8.4
97
111
  - !ruby/object:Gem::Dependency
98
112
  name: capybara
99
113
  requirement: !ruby/object:Gem::Requirement
@@ -319,26 +333,37 @@ files:
319
333
  - LICENSE.txt
320
334
  - README.md
321
335
  - engine/app/assets/style.css
322
- - engine/app/assets/vendor/bootstrap/bootstrap-native.js
323
- - engine/app/assets/vendor/bootstrap/bootstrap.css
336
+ - engine/app/assets/vendor/bootstrap/bootstrap.bundle.min.js
337
+ - engine/app/assets/vendor/bootstrap/bootstrap.min.css
324
338
  - engine/app/assets/vendor/chartist/chartist.css
325
339
  - engine/app/assets/vendor/chartist/chartist.js
326
340
  - engine/app/controllers/good_job/active_jobs_controller.rb
341
+ - engine/app/controllers/good_job/assets_controller.rb
327
342
  - engine/app/controllers/good_job/base_controller.rb
328
343
  - engine/app/controllers/good_job/dashboards_controller.rb
344
+ - engine/app/controllers/good_job/jobs_controller.rb
329
345
  - engine/app/helpers/good_job/application_helper.rb
330
346
  - engine/app/views/good_job/active_jobs/show.html.erb
331
347
  - engine/app/views/good_job/dashboards/index.html.erb
332
348
  - engine/app/views/layouts/good_job/base.html.erb
333
349
  - engine/app/views/shared/_chart.erb
334
350
  - engine/app/views/shared/_jobs_table.erb
351
+ - engine/app/views/shared/icons/_check.html.erb
352
+ - engine/app/views/shared/icons/_exclamation.html.erb
353
+ - engine/app/views/shared/icons/_trash.html.erb
335
354
  - engine/config/routes.rb
336
355
  - engine/lib/good_job/engine.rb
337
356
  - exe/good_job
338
357
  - lib/active_job/queue_adapters/good_job_adapter.rb
339
358
  - lib/generators/good_job/install_generator.rb
340
- - lib/generators/good_job/templates/migration.rb.erb
359
+ - lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb
360
+ - lib/generators/good_job/templates/update/migrations/01_create_good_jobs.rb
361
+ - lib/generators/good_job/templates/update/migrations/02_add_active_job_id_concurrency_key_cron_key_to_good_jobs.rb
362
+ - lib/generators/good_job/templates/update/migrations/03_add_active_job_id_index_and_concurrency_key_index_to_good_jobs.rb
363
+ - lib/generators/good_job/update_generator.rb
341
364
  - lib/good_job.rb
365
+ - lib/good_job/active_job_extensions.rb
366
+ - lib/good_job/active_job_extensions/concurrency.rb
342
367
  - lib/good_job/adapter.rb
343
368
  - lib/good_job/cli.rb
344
369
  - lib/good_job/configuration.rb
@@ -1,1662 +0,0 @@
1
- /*!
2
- * Native JavaScript for Bootstrap v3.0.10 (https://thednp.github.io/bootstrap.native/)
3
- * Copyright 2015-2020 © dnp_theme
4
- * Licensed under MIT (https://github.com/thednp/bootstrap.native/blob/master/LICENSE)
5
- */
6
- (function (global, factory) {
7
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
8
- typeof define === 'function' && define.amd ? define(factory) :
9
- (global = global || self, global.BSN = factory());
10
- }(this, (function () { 'use strict';
11
-
12
- var transitionEndEvent = 'webkitTransition' in document.head.style ? 'webkitTransitionEnd' : 'transitionend';
13
-
14
- var supportTransition = 'webkitTransition' in document.head.style || 'transition' in document.head.style;
15
-
16
- var transitionDuration = 'webkitTransition' in document.head.style ? 'webkitTransitionDuration' : 'transitionDuration';
17
-
18
- function getElementTransitionDuration(element) {
19
- var duration = supportTransition ? parseFloat(getComputedStyle(element)[transitionDuration]) : 0;
20
- duration = typeof duration === 'number' && !isNaN(duration) ? duration * 1000 : 0;
21
- return duration;
22
- }
23
-
24
- function emulateTransitionEnd(element,handler){
25
- var called = 0, duration = getElementTransitionDuration(element);
26
- duration ? element.addEventListener( transitionEndEvent, function transitionEndWrapper(e){
27
- !called && handler(e), called = 1;
28
- element.removeEventListener( transitionEndEvent, transitionEndWrapper);
29
- })
30
- : setTimeout(function() { !called && handler(), called = 1; }, 17);
31
- }
32
-
33
- function queryElement(selector, parent) {
34
- var lookUp = parent && parent instanceof Element ? parent : document;
35
- return selector instanceof Element ? selector : lookUp.querySelector(selector);
36
- }
37
-
38
- function bootstrapCustomEvent(eventName, componentName, related) {
39
- var OriginalCustomEvent = new CustomEvent( eventName + '.bs.' + componentName, {cancelable: true});
40
- OriginalCustomEvent.relatedTarget = related;
41
- return OriginalCustomEvent;
42
- }
43
-
44
- function dispatchCustomEvent(customEvent){
45
- this && this.dispatchEvent(customEvent);
46
- }
47
-
48
- function Alert(element) {
49
- var self = this,
50
- alert,
51
- closeCustomEvent = bootstrapCustomEvent('close','alert'),
52
- closedCustomEvent = bootstrapCustomEvent('closed','alert');
53
- function triggerHandler() {
54
- alert.classList.contains('fade') ? emulateTransitionEnd(alert,transitionEndHandler) : transitionEndHandler();
55
- }
56
- function toggleEvents(action){
57
- action = action ? 'addEventListener' : 'removeEventListener';
58
- element[action]('click',clickHandler,false);
59
- }
60
- function clickHandler(e) {
61
- alert = e && e.target.closest(".alert");
62
- element = queryElement('[data-dismiss="alert"]',alert);
63
- element && alert && (element === e.target || element.contains(e.target)) && self.close();
64
- }
65
- function transitionEndHandler() {
66
- toggleEvents();
67
- alert.parentNode.removeChild(alert);
68
- dispatchCustomEvent.call(alert,closedCustomEvent);
69
- }
70
- self.close = function () {
71
- if ( alert && element && alert.classList.contains('show') ) {
72
- dispatchCustomEvent.call(alert,closeCustomEvent);
73
- if ( closeCustomEvent.defaultPrevented ) { return; }
74
- self.dispose();
75
- alert.classList.remove('show');
76
- triggerHandler();
77
- }
78
- };
79
- self.dispose = function () {
80
- toggleEvents();
81
- delete element.Alert;
82
- };
83
- element = queryElement(element);
84
- alert = element.closest('.alert');
85
- element.Alert && element.Alert.dispose();
86
- if ( !element.Alert ) {
87
- toggleEvents(1);
88
- }
89
- self.element = element;
90
- element.Alert = self;
91
- }
92
-
93
- function Button(element) {
94
- var self = this, labels,
95
- changeCustomEvent = bootstrapCustomEvent('change', 'button');
96
- function toggle(e) {
97
- var input,
98
- label = e.target.tagName === 'LABEL' ? e.target
99
- : e.target.closest('LABEL') ? e.target.closest('LABEL') : null;
100
- input = label && label.getElementsByTagName('INPUT')[0];
101
- if ( !input ) { return; }
102
- dispatchCustomEvent.call(input, changeCustomEvent);
103
- dispatchCustomEvent.call(element, changeCustomEvent);
104
- if ( input.type === 'checkbox' ) {
105
- if ( changeCustomEvent.defaultPrevented ) { return; }
106
- if ( !input.checked ) {
107
- label.classList.add('active');
108
- input.getAttribute('checked');
109
- input.setAttribute('checked','checked');
110
- input.checked = true;
111
- } else {
112
- label.classList.remove('active');
113
- input.getAttribute('checked');
114
- input.removeAttribute('checked');
115
- input.checked = false;
116
- }
117
- if (!element.toggled) {
118
- element.toggled = true;
119
- }
120
- }
121
- if ( input.type === 'radio' && !element.toggled ) {
122
- if ( changeCustomEvent.defaultPrevented ) { return; }
123
- if ( !input.checked || (e.screenX === 0 && e.screenY == 0) ) {
124
- label.classList.add('active');
125
- label.classList.add('focus');
126
- input.setAttribute('checked','checked');
127
- input.checked = true;
128
- element.toggled = true;
129
- Array.from(labels).map(function (otherLabel){
130
- var otherInput = otherLabel.getElementsByTagName('INPUT')[0];
131
- if ( otherLabel !== label && otherLabel.classList.contains('active') ) {
132
- dispatchCustomEvent.call(otherInput, changeCustomEvent);
133
- otherLabel.classList.remove('active');
134
- otherInput.removeAttribute('checked');
135
- otherInput.checked = false;
136
- }
137
- });
138
- }
139
- }
140
- setTimeout( function () { element.toggled = false; }, 50 );
141
- }
142
- function keyHandler(e) {
143
- var key = e.which || e.keyCode;
144
- key === 32 && e.target === document.activeElement && toggle(e);
145
- }
146
- function preventScroll(e) {
147
- var key = e.which || e.keyCode;
148
- key === 32 && e.preventDefault();
149
- }
150
- function focusToggle(e) {
151
- if (e.target.tagName === 'INPUT' ) {
152
- var action = e.type === 'focusin' ? 'add' : 'remove';
153
- e.target.closest('.btn').classList[action]('focus');
154
- }
155
- }
156
- function toggleEvents(action) {
157
- action = action ? 'addEventListener' : 'removeEventListener';
158
- element[action]('click',toggle,false );
159
- element[action]('keyup',keyHandler,false), element[action]('keydown',preventScroll,false);
160
- element[action]('focusin',focusToggle,false), element[action]('focusout',focusToggle,false);
161
- }
162
- self.dispose = function () {
163
- toggleEvents();
164
- delete element.Button;
165
- };
166
- element = queryElement(element);
167
- element.Button && element.Button.dispose();
168
- labels = element.getElementsByClassName('btn');
169
- if (!labels.length) { return; }
170
- if ( !element.Button ) {
171
- toggleEvents(1);
172
- }
173
- element.toggled = false;
174
- element.Button = self;
175
- Array.from(labels).map(function (btn){
176
- !btn.classList.contains('active')
177
- && queryElement('input:checked',btn)
178
- && btn.classList.add('active');
179
- btn.classList.contains('active')
180
- && !queryElement('input:checked',btn)
181
- && btn.classList.remove('active');
182
- });
183
- }
184
-
185
- var mouseHoverEvents = ('onmouseleave' in document) ? [ 'mouseenter', 'mouseleave'] : [ 'mouseover', 'mouseout' ];
186
-
187
- var supportPassive = (function () {
188
- var result = false;
189
- try {
190
- var opts = Object.defineProperty({}, 'passive', {
191
- get: function() {
192
- result = true;
193
- }
194
- });
195
- document.addEventListener('DOMContentLoaded', function wrap(){
196
- document.removeEventListener('DOMContentLoaded', wrap, opts);
197
- }, opts);
198
- } catch (e) {}
199
- return result;
200
- })();
201
-
202
- var passiveHandler = supportPassive ? { passive: true } : false;
203
-
204
- function isElementInScrollRange(element) {
205
- var bcr = element.getBoundingClientRect(),
206
- viewportHeight = window.innerHeight || document.documentElement.clientHeight;
207
- return bcr.top <= viewportHeight && bcr.bottom >= 0;
208
- }
209
-
210
- function Carousel (element,options) {
211
- options = options || {};
212
- var self = this,
213
- vars, ops,
214
- slideCustomEvent, slidCustomEvent,
215
- slides, leftArrow, rightArrow, indicator, indicators;
216
- function pauseHandler() {
217
- if ( ops.interval !==false && !element.classList.contains('paused') ) {
218
- element.classList.add('paused');
219
- !vars.isSliding && ( clearInterval(vars.timer), vars.timer = null );
220
- }
221
- }
222
- function resumeHandler() {
223
- if ( ops.interval !== false && element.classList.contains('paused') ) {
224
- element.classList.remove('paused');
225
- !vars.isSliding && ( clearInterval(vars.timer), vars.timer = null );
226
- !vars.isSliding && self.cycle();
227
- }
228
- }
229
- function indicatorHandler(e) {
230
- e.preventDefault();
231
- if (vars.isSliding) { return; }
232
- var eventTarget = e.target;
233
- if ( eventTarget && !eventTarget.classList.contains('active') && eventTarget.getAttribute('data-slide-to') ) {
234
- vars.index = parseInt( eventTarget.getAttribute('data-slide-to'));
235
- } else { return false; }
236
- self.slideTo( vars.index );
237
- }
238
- function controlsHandler(e) {
239
- e.preventDefault();
240
- if (vars.isSliding) { return; }
241
- var eventTarget = e.currentTarget || e.srcElement;
242
- if ( eventTarget === rightArrow ) {
243
- vars.index++;
244
- } else if ( eventTarget === leftArrow ) {
245
- vars.index--;
246
- }
247
- self.slideTo( vars.index );
248
- }
249
- function keyHandler(ref) {
250
- var which = ref.which;
251
- if (vars.isSliding) { return; }
252
- switch (which) {
253
- case 39:
254
- vars.index++;
255
- break;
256
- case 37:
257
- vars.index--;
258
- break;
259
- default: return;
260
- }
261
- self.slideTo( vars.index );
262
- }
263
- function toggleEvents(action) {
264
- action = action ? 'addEventListener' : 'removeEventListener';
265
- if ( ops.pause && ops.interval ) {
266
- element[action]( mouseHoverEvents[0], pauseHandler, false );
267
- element[action]( mouseHoverEvents[1], resumeHandler, false );
268
- element[action]( 'touchstart', pauseHandler, passiveHandler );
269
- element[action]( 'touchend', resumeHandler, passiveHandler );
270
- }
271
- ops.touch && slides.length > 1 && element[action]( 'touchstart', touchDownHandler, passiveHandler );
272
- rightArrow && rightArrow[action]( 'click', controlsHandler,false );
273
- leftArrow && leftArrow[action]( 'click', controlsHandler,false );
274
- indicator && indicator[action]( 'click', indicatorHandler,false );
275
- ops.keyboard && window[action]( 'keydown', keyHandler,false );
276
- }
277
- function toggleTouchEvents(action) {
278
- action = action ? 'addEventListener' : 'removeEventListener';
279
- element[action]( 'touchmove', touchMoveHandler, passiveHandler );
280
- element[action]( 'touchend', touchEndHandler, passiveHandler );
281
- }
282
- function touchDownHandler(e) {
283
- if ( vars.isTouch ) { return; }
284
- vars.touchPosition.startX = e.changedTouches[0].pageX;
285
- if ( element.contains(e.target) ) {
286
- vars.isTouch = true;
287
- toggleTouchEvents(1);
288
- }
289
- }
290
- function touchMoveHandler(e) {
291
- if ( !vars.isTouch ) { e.preventDefault(); return; }
292
- vars.touchPosition.currentX = e.changedTouches[0].pageX;
293
- if ( e.type === 'touchmove' && e.changedTouches.length > 1 ) {
294
- e.preventDefault();
295
- return false;
296
- }
297
- }
298
- function touchEndHandler (e) {
299
- if ( !vars.isTouch || vars.isSliding ) { return }
300
- vars.touchPosition.endX = vars.touchPosition.currentX || e.changedTouches[0].pageX;
301
- if ( vars.isTouch ) {
302
- if ( (!element.contains(e.target) || !element.contains(e.relatedTarget) )
303
- && Math.abs(vars.touchPosition.startX - vars.touchPosition.endX) < 75 ) {
304
- return false;
305
- } else {
306
- if ( vars.touchPosition.currentX < vars.touchPosition.startX ) {
307
- vars.index++;
308
- } else if ( vars.touchPosition.currentX > vars.touchPosition.startX ) {
309
- vars.index--;
310
- }
311
- vars.isTouch = false;
312
- self.slideTo(vars.index);
313
- }
314
- toggleTouchEvents();
315
- }
316
- }
317
- function setActivePage(pageIndex) {
318
- Array.from(indicators).map(function (x){x.classList.remove('active');});
319
- indicators[pageIndex] && indicators[pageIndex].classList.add('active');
320
- }
321
- function transitionEndHandler(e){
322
- if (vars.touchPosition){
323
- var next = vars.index,
324
- timeout = e && e.target !== slides[next] ? e.elapsedTime*1000+100 : 20,
325
- activeItem = self.getActiveIndex(),
326
- orientation = vars.direction === 'left' ? 'next' : 'prev';
327
- vars.isSliding && setTimeout(function () {
328
- if (vars.touchPosition){
329
- vars.isSliding = false;
330
- slides[next].classList.add('active');
331
- slides[activeItem].classList.remove('active');
332
- slides[next].classList.remove(("carousel-item-" + orientation));
333
- slides[next].classList.remove(("carousel-item-" + (vars.direction)));
334
- slides[activeItem].classList.remove(("carousel-item-" + (vars.direction)));
335
- dispatchCustomEvent.call(element, slidCustomEvent);
336
- if ( !document.hidden && ops.interval && !element.classList.contains('paused') ) {
337
- self.cycle();
338
- }
339
- }
340
- }, timeout);
341
- }
342
- }
343
- self.cycle = function () {
344
- if (vars.timer) {
345
- clearInterval(vars.timer);
346
- vars.timer = null;
347
- }
348
- vars.timer = setInterval(function () {
349
- var idx = vars.index || self.getActiveIndex();
350
- isElementInScrollRange(element) && (idx++, self.slideTo( idx ) );
351
- }, ops.interval);
352
- };
353
- self.slideTo = function (next) {
354
- if (vars.isSliding) { return; }
355
- var activeItem = self.getActiveIndex(), orientation;
356
- if ( activeItem === next ) {
357
- return;
358
- } else if ( (activeItem < next ) || (activeItem === 0 && next === slides.length -1 ) ) {
359
- vars.direction = 'left';
360
- } else if ( (activeItem > next) || (activeItem === slides.length - 1 && next === 0 ) ) {
361
- vars.direction = 'right';
362
- }
363
- if ( next < 0 ) { next = slides.length - 1; }
364
- else if ( next >= slides.length ){ next = 0; }
365
- orientation = vars.direction === 'left' ? 'next' : 'prev';
366
- slideCustomEvent = bootstrapCustomEvent('slide', 'carousel', slides[next]);
367
- slidCustomEvent = bootstrapCustomEvent('slid', 'carousel', slides[next]);
368
- dispatchCustomEvent.call(element, slideCustomEvent);
369
- if (slideCustomEvent.defaultPrevented) { return; }
370
- vars.index = next;
371
- vars.isSliding = true;
372
- clearInterval(vars.timer);
373
- vars.timer = null;
374
- setActivePage( next );
375
- if ( getElementTransitionDuration(slides[next]) && element.classList.contains('slide') ) {
376
- slides[next].classList.add(("carousel-item-" + orientation));
377
- slides[next].offsetWidth;
378
- slides[next].classList.add(("carousel-item-" + (vars.direction)));
379
- slides[activeItem].classList.add(("carousel-item-" + (vars.direction)));
380
- emulateTransitionEnd(slides[next], transitionEndHandler);
381
- } else {
382
- slides[next].classList.add('active');
383
- slides[next].offsetWidth;
384
- slides[activeItem].classList.remove('active');
385
- setTimeout(function () {
386
- vars.isSliding = false;
387
- if ( ops.interval && element && !element.classList.contains('paused') ) {
388
- self.cycle();
389
- }
390
- dispatchCustomEvent.call(element, slidCustomEvent);
391
- }, 100 );
392
- }
393
- };
394
- self.getActiveIndex = function () { return Array.from(slides).indexOf(element.getElementsByClassName('carousel-item active')[0]) || 0; };
395
- self.dispose = function () {
396
- var itemClasses = ['left','right','prev','next'];
397
- Array.from(slides).map(function (slide,idx) {
398
- slide.classList.contains('active') && setActivePage( idx );
399
- itemClasses.map(function (cls) { return slide.classList.remove(("carousel-item-" + cls)); });
400
- });
401
- clearInterval(vars.timer);
402
- toggleEvents();
403
- vars = {};
404
- ops = {};
405
- delete element.Carousel;
406
- };
407
- element = queryElement( element );
408
- element.Carousel && element.Carousel.dispose();
409
- slides = element.getElementsByClassName('carousel-item');
410
- leftArrow = element.getElementsByClassName('carousel-control-prev')[0];
411
- rightArrow = element.getElementsByClassName('carousel-control-next')[0];
412
- indicator = element.getElementsByClassName('carousel-indicators')[0];
413
- indicators = indicator && indicator.getElementsByTagName( "LI" ) || [];
414
- if (slides.length < 2) { return }
415
- var
416
- intervalAttribute = element.getAttribute('data-interval'),
417
- intervalData = intervalAttribute === 'false' ? 0 : parseInt(intervalAttribute),
418
- touchData = element.getAttribute('data-touch') === 'false' ? 0 : 1,
419
- pauseData = element.getAttribute('data-pause') === 'hover' || false,
420
- keyboardData = element.getAttribute('data-keyboard') === 'true' || false,
421
- intervalOption = options.interval,
422
- touchOption = options.touch;
423
- ops = {};
424
- ops.keyboard = options.keyboard === true || keyboardData;
425
- ops.pause = (options.pause === 'hover' || pauseData) ? 'hover' : false;
426
- ops.touch = touchOption || touchData;
427
- ops.interval = typeof intervalOption === 'number' ? intervalOption
428
- : intervalOption === false || intervalData === 0 || intervalData === false ? 0
429
- : isNaN(intervalData) ? 5000
430
- : intervalData;
431
- if (self.getActiveIndex()<0) {
432
- slides.length && slides[0].classList.add('active');
433
- indicators.length && setActivePage(0);
434
- }
435
- vars = {};
436
- vars.direction = 'left';
437
- vars.index = 0;
438
- vars.timer = null;
439
- vars.isSliding = false;
440
- vars.isTouch = false;
441
- vars.touchPosition = {
442
- startX : 0,
443
- currentX : 0,
444
- endX : 0
445
- };
446
- toggleEvents(1);
447
- if ( ops.interval ){ self.cycle(); }
448
- element.Carousel = self;
449
- }
450
-
451
- function Collapse(element,options) {
452
- options = options || {};
453
- var self = this;
454
- var accordion = null,
455
- collapse = null,
456
- activeCollapse,
457
- activeElement,
458
- showCustomEvent,
459
- shownCustomEvent,
460
- hideCustomEvent,
461
- hiddenCustomEvent;
462
- function openAction(collapseElement, toggle) {
463
- dispatchCustomEvent.call(collapseElement, showCustomEvent);
464
- if ( showCustomEvent.defaultPrevented ) { return; }
465
- collapseElement.isAnimating = true;
466
- collapseElement.classList.add('collapsing');
467
- collapseElement.classList.remove('collapse');
468
- collapseElement.style.height = (collapseElement.scrollHeight) + "px";
469
- emulateTransitionEnd(collapseElement, function () {
470
- collapseElement.isAnimating = false;
471
- collapseElement.setAttribute('aria-expanded','true');
472
- toggle.setAttribute('aria-expanded','true');
473
- collapseElement.classList.remove('collapsing');
474
- collapseElement.classList.add('collapse');
475
- collapseElement.classList.add('show');
476
- collapseElement.style.height = '';
477
- dispatchCustomEvent.call(collapseElement, shownCustomEvent);
478
- });
479
- }
480
- function closeAction(collapseElement, toggle) {
481
- dispatchCustomEvent.call(collapseElement, hideCustomEvent);
482
- if ( hideCustomEvent.defaultPrevented ) { return; }
483
- collapseElement.isAnimating = true;
484
- collapseElement.style.height = (collapseElement.scrollHeight) + "px";
485
- collapseElement.classList.remove('collapse');
486
- collapseElement.classList.remove('show');
487
- collapseElement.classList.add('collapsing');
488
- collapseElement.offsetWidth;
489
- collapseElement.style.height = '0px';
490
- emulateTransitionEnd(collapseElement, function () {
491
- collapseElement.isAnimating = false;
492
- collapseElement.setAttribute('aria-expanded','false');
493
- toggle.setAttribute('aria-expanded','false');
494
- collapseElement.classList.remove('collapsing');
495
- collapseElement.classList.add('collapse');
496
- collapseElement.style.height = '';
497
- dispatchCustomEvent.call(collapseElement, hiddenCustomEvent);
498
- });
499
- }
500
- self.toggle = function (e) {
501
- if (e && e.target.tagName === 'A' || element.tagName === 'A') {e.preventDefault();}
502
- if (element.contains(e.target) || e.target === element) {
503
- if (!collapse.classList.contains('show')) { self.show(); }
504
- else { self.hide(); }
505
- }
506
- };
507
- self.hide = function () {
508
- if ( collapse.isAnimating ) { return; }
509
- closeAction(collapse,element);
510
- element.classList.add('collapsed');
511
- };
512
- self.show = function () {
513
- if ( accordion ) {
514
- activeCollapse = accordion.getElementsByClassName("collapse show")[0];
515
- activeElement = activeCollapse && (queryElement(("[data-target=\"#" + (activeCollapse.id) + "\"]"),accordion)
516
- || queryElement(("[href=\"#" + (activeCollapse.id) + "\"]"),accordion) );
517
- }
518
- if ( !collapse.isAnimating ) {
519
- if ( activeElement && activeCollapse !== collapse ) {
520
- closeAction(activeCollapse,activeElement);
521
- activeElement.classList.add('collapsed');
522
- }
523
- openAction(collapse,element);
524
- element.classList.remove('collapsed');
525
- }
526
- };
527
- self.dispose = function () {
528
- element.removeEventListener('click',self.toggle,false);
529
- delete element.Collapse;
530
- };
531
- element = queryElement(element);
532
- element.Collapse && element.Collapse.dispose();
533
- var accordionData = element.getAttribute('data-parent');
534
- showCustomEvent = bootstrapCustomEvent('show', 'collapse');
535
- shownCustomEvent = bootstrapCustomEvent('shown', 'collapse');
536
- hideCustomEvent = bootstrapCustomEvent('hide', 'collapse');
537
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'collapse');
538
- collapse = queryElement(options.target || element.getAttribute('data-target') || element.getAttribute('href'));
539
- collapse.isAnimating = false;
540
- accordion = element.closest(options.parent || accordionData);
541
- if ( !element.Collapse ) {
542
- element.addEventListener('click',self.toggle,false);
543
- }
544
- element.Collapse = self;
545
- }
546
-
547
- function setFocus (element){
548
- element.focus ? element.focus() : element.setActive();
549
- }
550
-
551
- function Dropdown(element,option) {
552
- var self = this,
553
- showCustomEvent,
554
- shownCustomEvent,
555
- hideCustomEvent,
556
- hiddenCustomEvent,
557
- relatedTarget = null,
558
- parent, menu, menuItems = [],
559
- persist;
560
- function preventEmptyAnchor(anchor) {
561
- (anchor.href && anchor.href.slice(-1) === '#' || anchor.parentNode && anchor.parentNode.href
562
- && anchor.parentNode.href.slice(-1) === '#') && this.preventDefault();
563
- }
564
- function toggleDismiss() {
565
- var action = element.open ? 'addEventListener' : 'removeEventListener';
566
- document[action]('click',dismissHandler,false);
567
- document[action]('keydown',preventScroll,false);
568
- document[action]('keyup',keyHandler,false);
569
- document[action]('focus',dismissHandler,false);
570
- }
571
- function dismissHandler(e) {
572
- var eventTarget = e.target,
573
- hasData = eventTarget && (eventTarget.getAttribute('data-toggle')
574
- || eventTarget.parentNode && eventTarget.parentNode.getAttribute
575
- && eventTarget.parentNode.getAttribute('data-toggle'));
576
- if ( e.type === 'focus' && (eventTarget === element || eventTarget === menu || menu.contains(eventTarget) ) ) {
577
- return;
578
- }
579
- if ( (eventTarget === menu || menu.contains(eventTarget)) && (persist || hasData) ) { return; }
580
- else {
581
- relatedTarget = eventTarget === element || element.contains(eventTarget) ? element : null;
582
- self.hide();
583
- }
584
- preventEmptyAnchor.call(e,eventTarget);
585
- }
586
- function clickHandler(e) {
587
- relatedTarget = element;
588
- self.show();
589
- preventEmptyAnchor.call(e,e.target);
590
- }
591
- function preventScroll(e) {
592
- var key = e.which || e.keyCode;
593
- if( key === 38 || key === 40 ) { e.preventDefault(); }
594
- }
595
- function keyHandler(e) {
596
- var key = e.which || e.keyCode,
597
- activeItem = document.activeElement,
598
- isSameElement = activeItem === element,
599
- isInsideMenu = menu.contains(activeItem),
600
- isMenuItem = activeItem.parentNode === menu || activeItem.parentNode.parentNode === menu,
601
- idx = menuItems.indexOf(activeItem);
602
- if ( isMenuItem ) {
603
- idx = isSameElement ? 0
604
- : key === 38 ? (idx>1?idx-1:0)
605
- : key === 40 ? (idx<menuItems.length-1?idx+1:idx) : idx;
606
- menuItems[idx] && setFocus(menuItems[idx]);
607
- }
608
- if ( (menuItems.length && isMenuItem
609
- || !menuItems.length && (isInsideMenu || isSameElement)
610
- || !isInsideMenu )
611
- && element.open && key === 27
612
- ) {
613
- self.toggle();
614
- relatedTarget = null;
615
- }
616
- }
617
- self.show = function () {
618
- showCustomEvent = bootstrapCustomEvent('show', 'dropdown', relatedTarget);
619
- dispatchCustomEvent.call(parent, showCustomEvent);
620
- if ( showCustomEvent.defaultPrevented ) { return; }
621
- menu.classList.add('show');
622
- parent.classList.add('show');
623
- element.setAttribute('aria-expanded',true);
624
- element.open = true;
625
- element.removeEventListener('click',clickHandler,false);
626
- setTimeout(function () {
627
- setFocus( menu.getElementsByTagName('INPUT')[0] || element );
628
- toggleDismiss();
629
- shownCustomEvent = bootstrapCustomEvent( 'shown', 'dropdown', relatedTarget);
630
- dispatchCustomEvent.call(parent, shownCustomEvent);
631
- },1);
632
- };
633
- self.hide = function () {
634
- hideCustomEvent = bootstrapCustomEvent('hide', 'dropdown', relatedTarget);
635
- dispatchCustomEvent.call(parent, hideCustomEvent);
636
- if ( hideCustomEvent.defaultPrevented ) { return; }
637
- menu.classList.remove('show');
638
- parent.classList.remove('show');
639
- element.setAttribute('aria-expanded',false);
640
- element.open = false;
641
- toggleDismiss();
642
- setFocus(element);
643
- setTimeout(function () {
644
- element.Dropdown && element.addEventListener('click',clickHandler,false);
645
- },1);
646
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'dropdown', relatedTarget);
647
- dispatchCustomEvent.call(parent, hiddenCustomEvent);
648
- };
649
- self.toggle = function () {
650
- if (parent.classList.contains('show') && element.open) { self.hide(); }
651
- else { self.show(); }
652
- };
653
- self.dispose = function () {
654
- if (parent.classList.contains('show') && element.open) { self.hide(); }
655
- element.removeEventListener('click',clickHandler,false);
656
- delete element.Dropdown;
657
- };
658
- element = queryElement(element);
659
- element.Dropdown && element.Dropdown.dispose();
660
- parent = element.parentNode;
661
- menu = queryElement('.dropdown-menu', parent);
662
- Array.from(menu.children).map(function (child){
663
- child.children.length && (child.children[0].tagName === 'A' && menuItems.push(child.children[0]));
664
- child.tagName === 'A' && menuItems.push(child);
665
- });
666
- if ( !element.Dropdown ) {
667
- !('tabindex' in menu) && menu.setAttribute('tabindex', '0');
668
- element.addEventListener('click',clickHandler,false);
669
- }
670
- persist = option === true || element.getAttribute('data-persist') === 'true' || false;
671
- element.open = false;
672
- element.Dropdown = self;
673
- }
674
-
675
- function Modal(element,options) {
676
- options = options || {};
677
- var self = this, modal,
678
- showCustomEvent,
679
- shownCustomEvent,
680
- hideCustomEvent,
681
- hiddenCustomEvent,
682
- relatedTarget = null,
683
- scrollBarWidth,
684
- overlay,
685
- overlayDelay,
686
- fixedItems,
687
- ops = {};
688
- function setScrollbar() {
689
- var openModal = document.body.classList.contains('modal-open'),
690
- bodyPad = parseInt(getComputedStyle(document.body).paddingRight),
691
- bodyOverflow = document.documentElement.clientHeight !== document.documentElement.scrollHeight
692
- || document.body.clientHeight !== document.body.scrollHeight,
693
- modalOverflow = modal.clientHeight !== modal.scrollHeight;
694
- scrollBarWidth = measureScrollbar();
695
- modal.style.paddingRight = !modalOverflow && scrollBarWidth ? (scrollBarWidth + "px") : '';
696
- document.body.style.paddingRight = modalOverflow || bodyOverflow ? ((bodyPad + (openModal ? 0:scrollBarWidth)) + "px") : '';
697
- fixedItems.length && fixedItems.map(function (fixed){
698
- var itemPad = getComputedStyle(fixed).paddingRight;
699
- fixed.style.paddingRight = modalOverflow || bodyOverflow ? ((parseInt(itemPad) + (openModal?0:scrollBarWidth)) + "px") : ((parseInt(itemPad)) + "px");
700
- });
701
- }
702
- function resetScrollbar() {
703
- document.body.style.paddingRight = '';
704
- modal.style.paddingRight = '';
705
- fixedItems.length && fixedItems.map(function (fixed){
706
- fixed.style.paddingRight = '';
707
- });
708
- }
709
- function measureScrollbar() {
710
- var scrollDiv = document.createElement('div'), widthValue;
711
- scrollDiv.className = 'modal-scrollbar-measure';
712
- document.body.appendChild(scrollDiv);
713
- widthValue = scrollDiv.offsetWidth - scrollDiv.clientWidth;
714
- document.body.removeChild(scrollDiv);
715
- return widthValue;
716
- }
717
- function createOverlay() {
718
- var newOverlay = document.createElement('div');
719
- overlay = queryElement('.modal-backdrop');
720
- if ( overlay === null ) {
721
- newOverlay.setAttribute('class', 'modal-backdrop' + (ops.animation ? ' fade' : ''));
722
- overlay = newOverlay;
723
- document.body.appendChild(overlay);
724
- }
725
- return overlay;
726
- }
727
- function removeOverlay () {
728
- overlay = queryElement('.modal-backdrop');
729
- if ( overlay && !document.getElementsByClassName('modal show')[0] ) {
730
- document.body.removeChild(overlay); overlay = null;
731
- }
732
- overlay === null && (document.body.classList.remove('modal-open'), resetScrollbar());
733
- }
734
- function toggleEvents(action) {
735
- action = action ? 'addEventListener' : 'removeEventListener';
736
- window[action]( 'resize', self.update, passiveHandler);
737
- modal[action]( 'click',dismissHandler,false);
738
- document[action]( 'keydown',keyHandler,false);
739
- }
740
- function beforeShow() {
741
- modal.style.display = 'block';
742
- setScrollbar();
743
- !document.getElementsByClassName('modal show')[0] && document.body.classList.add('modal-open');
744
- modal.classList.add('show');
745
- modal.setAttribute('aria-hidden', false);
746
- modal.classList.contains('fade') ? emulateTransitionEnd(modal, triggerShow) : triggerShow();
747
- }
748
- function triggerShow() {
749
- setFocus(modal);
750
- modal.isAnimating = false;
751
- toggleEvents(1);
752
- shownCustomEvent = bootstrapCustomEvent('shown', 'modal', relatedTarget);
753
- dispatchCustomEvent.call(modal, shownCustomEvent);
754
- }
755
- function triggerHide(force) {
756
- modal.style.display = '';
757
- element && (setFocus(element));
758
- overlay = queryElement('.modal-backdrop');
759
- if (force !== 1 && overlay && overlay.classList.contains('show') && !document.getElementsByClassName('modal show')[0]) {
760
- overlay.classList.remove('show');
761
- emulateTransitionEnd(overlay,removeOverlay);
762
- } else {
763
- removeOverlay();
764
- }
765
- toggleEvents();
766
- modal.isAnimating = false;
767
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'modal');
768
- dispatchCustomEvent.call(modal, hiddenCustomEvent);
769
- }
770
- function clickHandler(e) {
771
- if ( modal.isAnimating ) { return; }
772
- var clickTarget = e.target,
773
- modalID = "#" + (modal.getAttribute('id')),
774
- targetAttrValue = clickTarget.getAttribute('data-target') || clickTarget.getAttribute('href'),
775
- elemAttrValue = element.getAttribute('data-target') || element.getAttribute('href');
776
- if ( !modal.classList.contains('show')
777
- && (clickTarget === element && targetAttrValue === modalID
778
- || element.contains(clickTarget) && elemAttrValue === modalID) ) {
779
- modal.modalTrigger = element;
780
- relatedTarget = element;
781
- self.show();
782
- e.preventDefault();
783
- }
784
- }
785
- function keyHandler(ref) {
786
- var which = ref.which;
787
- if (!modal.isAnimating && ops.keyboard && which == 27 && modal.classList.contains('show') ) {
788
- self.hide();
789
- }
790
- }
791
- function dismissHandler(e) {
792
- if ( modal.isAnimating ) { return; }
793
- var clickTarget = e.target,
794
- hasData = clickTarget.getAttribute('data-dismiss') === 'modal',
795
- parentWithData = clickTarget.closest('[data-dismiss="modal"]');
796
- if ( modal.classList.contains('show') && ( parentWithData || hasData
797
- || clickTarget === modal && ops.backdrop !== 'static' ) ) {
798
- self.hide(); relatedTarget = null;
799
- e.preventDefault();
800
- }
801
- }
802
- self.toggle = function () {
803
- if ( modal.classList.contains('show') ) {self.hide();} else {self.show();}
804
- };
805
- self.show = function () {
806
- if (modal.classList.contains('show') && !!modal.isAnimating ) {return}
807
- showCustomEvent = bootstrapCustomEvent('show', 'modal', relatedTarget);
808
- dispatchCustomEvent.call(modal, showCustomEvent);
809
- if ( showCustomEvent.defaultPrevented ) { return; }
810
- modal.isAnimating = true;
811
- var currentOpen = document.getElementsByClassName('modal show')[0];
812
- if (currentOpen && currentOpen !== modal) {
813
- currentOpen.modalTrigger && currentOpen.modalTrigger.Modal.hide();
814
- currentOpen.Modal && currentOpen.Modal.hide();
815
- }
816
- if ( ops.backdrop ) {
817
- overlay = createOverlay();
818
- }
819
- if ( overlay && !currentOpen && !overlay.classList.contains('show') ) {
820
- overlay.offsetWidth;
821
- overlayDelay = getElementTransitionDuration(overlay);
822
- overlay.classList.add('show');
823
- }
824
- !currentOpen ? setTimeout( beforeShow, overlay && overlayDelay ? overlayDelay:0 ) : beforeShow();
825
- };
826
- self.hide = function (force) {
827
- if ( !modal.classList.contains('show') ) {return}
828
- hideCustomEvent = bootstrapCustomEvent( 'hide', 'modal');
829
- dispatchCustomEvent.call(modal, hideCustomEvent);
830
- if ( hideCustomEvent.defaultPrevented ) { return; }
831
- modal.isAnimating = true;
832
- modal.classList.remove('show');
833
- modal.setAttribute('aria-hidden', true);
834
- modal.classList.contains('fade') && force !== 1 ? emulateTransitionEnd(modal, triggerHide) : triggerHide();
835
- };
836
- self.setContent = function (content) {
837
- queryElement('.modal-content',modal).innerHTML = content;
838
- };
839
- self.update = function () {
840
- if (modal.classList.contains('show')) {
841
- setScrollbar();
842
- }
843
- };
844
- self.dispose = function () {
845
- self.hide(1);
846
- if (element) {element.removeEventListener('click',clickHandler,false); delete element.Modal; }
847
- else {delete modal.Modal;}
848
- };
849
- element = queryElement(element);
850
- var checkModal = queryElement( element.getAttribute('data-target') || element.getAttribute('href') );
851
- modal = element.classList.contains('modal') ? element : checkModal;
852
- fixedItems = Array.from(document.getElementsByClassName('fixed-top'))
853
- .concat(Array.from(document.getElementsByClassName('fixed-bottom')));
854
- if ( element.classList.contains('modal') ) { element = null; }
855
- element && element.Modal && element.Modal.dispose();
856
- modal && modal.Modal && modal.Modal.dispose();
857
- ops.keyboard = options.keyboard === false || modal.getAttribute('data-keyboard') === 'false' ? false : true;
858
- ops.backdrop = options.backdrop === 'static' || modal.getAttribute('data-backdrop') === 'static' ? 'static' : true;
859
- ops.backdrop = options.backdrop === false || modal.getAttribute('data-backdrop') === 'false' ? false : ops.backdrop;
860
- ops.animation = modal.classList.contains('fade') ? true : false;
861
- ops.content = options.content;
862
- modal.isAnimating = false;
863
- if ( element && !element.Modal ) {
864
- element.addEventListener('click',clickHandler,false);
865
- }
866
- if ( ops.content ) {
867
- self.setContent( ops.content.trim() );
868
- }
869
- if (element) {
870
- modal.modalTrigger = element;
871
- element.Modal = self;
872
- } else {
873
- modal.Modal = self;
874
- }
875
- }
876
-
877
- var mouseClickEvents = { down: 'mousedown', up: 'mouseup' };
878
-
879
- function getScroll() {
880
- return {
881
- y : window.pageYOffset || document.documentElement.scrollTop,
882
- x : window.pageXOffset || document.documentElement.scrollLeft
883
- }
884
- }
885
-
886
- function styleTip(link,element,position,parent) {
887
- var tipPositions = /\b(top|bottom|left|right)+/,
888
- elementDimensions = { w : element.offsetWidth, h: element.offsetHeight },
889
- windowWidth = (document.documentElement.clientWidth || document.body.clientWidth),
890
- windowHeight = (document.documentElement.clientHeight || document.body.clientHeight),
891
- rect = link.getBoundingClientRect(),
892
- scroll = parent === document.body ? getScroll() : { x: parent.offsetLeft + parent.scrollLeft, y: parent.offsetTop + parent.scrollTop },
893
- linkDimensions = { w: rect.right - rect.left, h: rect.bottom - rect.top },
894
- isPopover = element.classList.contains('popover'),
895
- arrow = element.getElementsByClassName('arrow')[0],
896
- halfTopExceed = rect.top + linkDimensions.h/2 - elementDimensions.h/2 < 0,
897
- halfLeftExceed = rect.left + linkDimensions.w/2 - elementDimensions.w/2 < 0,
898
- halfRightExceed = rect.left + elementDimensions.w/2 + linkDimensions.w/2 >= windowWidth,
899
- halfBottomExceed = rect.top + elementDimensions.h/2 + linkDimensions.h/2 >= windowHeight,
900
- topExceed = rect.top - elementDimensions.h < 0,
901
- leftExceed = rect.left - elementDimensions.w < 0,
902
- bottomExceed = rect.top + elementDimensions.h + linkDimensions.h >= windowHeight,
903
- rightExceed = rect.left + elementDimensions.w + linkDimensions.w >= windowWidth;
904
- position = (position === 'left' || position === 'right') && leftExceed && rightExceed ? 'top' : position;
905
- position = position === 'top' && topExceed ? 'bottom' : position;
906
- position = position === 'bottom' && bottomExceed ? 'top' : position;
907
- position = position === 'left' && leftExceed ? 'right' : position;
908
- position = position === 'right' && rightExceed ? 'left' : position;
909
- var topPosition,
910
- leftPosition,
911
- arrowTop,
912
- arrowLeft,
913
- arrowWidth,
914
- arrowHeight;
915
- element.className.indexOf(position) === -1 && (element.className = element.className.replace(tipPositions,position));
916
- arrowWidth = arrow.offsetWidth; arrowHeight = arrow.offsetHeight;
917
- if ( position === 'left' || position === 'right' ) {
918
- if ( position === 'left' ) {
919
- leftPosition = rect.left + scroll.x - elementDimensions.w - ( isPopover ? arrowWidth : 0 );
920
- } else {
921
- leftPosition = rect.left + scroll.x + linkDimensions.w;
922
- }
923
- if (halfTopExceed) {
924
- topPosition = rect.top + scroll.y;
925
- arrowTop = linkDimensions.h/2 - arrowWidth;
926
- } else if (halfBottomExceed) {
927
- topPosition = rect.top + scroll.y - elementDimensions.h + linkDimensions.h;
928
- arrowTop = elementDimensions.h - linkDimensions.h/2 - arrowWidth;
929
- } else {
930
- topPosition = rect.top + scroll.y - elementDimensions.h/2 + linkDimensions.h/2;
931
- arrowTop = elementDimensions.h/2 - (isPopover ? arrowHeight*0.9 : arrowHeight/2);
932
- }
933
- } else if ( position === 'top' || position === 'bottom' ) {
934
- if ( position === 'top') {
935
- topPosition = rect.top + scroll.y - elementDimensions.h - ( isPopover ? arrowHeight : 0 );
936
- } else {
937
- topPosition = rect.top + scroll.y + linkDimensions.h;
938
- }
939
- if (halfLeftExceed) {
940
- leftPosition = 0;
941
- arrowLeft = rect.left + linkDimensions.w/2 - arrowWidth;
942
- } else if (halfRightExceed) {
943
- leftPosition = windowWidth - elementDimensions.w*1.01;
944
- arrowLeft = elementDimensions.w - ( windowWidth - rect.left ) + linkDimensions.w/2 - arrowWidth/2;
945
- } else {
946
- leftPosition = rect.left + scroll.x - elementDimensions.w/2 + linkDimensions.w/2;
947
- arrowLeft = elementDimensions.w/2 - ( isPopover ? arrowWidth : arrowWidth/2 );
948
- }
949
- }
950
- element.style.top = topPosition + 'px';
951
- element.style.left = leftPosition + 'px';
952
- arrowTop && (arrow.style.top = arrowTop + 'px');
953
- arrowLeft && (arrow.style.left = arrowLeft + 'px');
954
- }
955
-
956
- function Popover(element,options) {
957
- options = options || {};
958
- var self = this;
959
- var popover = null,
960
- timer = 0,
961
- isIphone = /(iPhone|iPod|iPad)/.test(navigator.userAgent),
962
- titleString,
963
- contentString,
964
- ops = {};
965
- var triggerData,
966
- animationData,
967
- placementData,
968
- dismissibleData,
969
- delayData,
970
- containerData,
971
- closeBtn,
972
- showCustomEvent,
973
- shownCustomEvent,
974
- hideCustomEvent,
975
- hiddenCustomEvent,
976
- containerElement,
977
- containerDataElement,
978
- modal,
979
- navbarFixedTop,
980
- navbarFixedBottom,
981
- placementClass;
982
- function dismissibleHandler(e) {
983
- if (popover !== null && e.target === queryElement('.close',popover)) {
984
- self.hide();
985
- }
986
- }
987
- function getContents() {
988
- return {
989
- 0 : options.title || element.getAttribute('data-title') || null,
990
- 1 : options.content || element.getAttribute('data-content') || null
991
- }
992
- }
993
- function removePopover() {
994
- ops.container.removeChild(popover);
995
- timer = null; popover = null;
996
- }
997
- function createPopover() {
998
- titleString = getContents()[0] || null;
999
- contentString = getContents()[1];
1000
- contentString = !!contentString ? contentString.trim() : null;
1001
- popover = document.createElement('div');
1002
- var popoverArrow = document.createElement('div');
1003
- popoverArrow.classList.add('arrow');
1004
- popover.appendChild(popoverArrow);
1005
- if ( contentString !== null && ops.template === null ) {
1006
- popover.setAttribute('role','tooltip');
1007
- if (titleString !== null) {
1008
- var popoverTitle = document.createElement('h3');
1009
- popoverTitle.classList.add('popover-header');
1010
- popoverTitle.innerHTML = ops.dismissible ? titleString + closeBtn : titleString;
1011
- popover.appendChild(popoverTitle);
1012
- }
1013
- var popoverBodyMarkup = document.createElement('div');
1014
- popoverBodyMarkup.classList.add('popover-body');
1015
- popoverBodyMarkup.innerHTML = ops.dismissible && titleString === null ? contentString + closeBtn : contentString;
1016
- popover.appendChild(popoverBodyMarkup);
1017
- } else {
1018
- var popoverTemplate = document.createElement('div');
1019
- popoverTemplate.innerHTML = ops.template.trim();
1020
- popover.className = popoverTemplate.firstChild.className;
1021
- popover.innerHTML = popoverTemplate.firstChild.innerHTML;
1022
- var popoverHeader = queryElement('.popover-header',popover),
1023
- popoverBody = queryElement('.popover-body',popover);
1024
- titleString && popoverHeader && (popoverHeader.innerHTML = titleString.trim());
1025
- contentString && popoverBody && (popoverBody.innerHTML = contentString.trim());
1026
- }
1027
- ops.container.appendChild(popover);
1028
- popover.style.display = 'block';
1029
- !popover.classList.contains( 'popover') && popover.classList.add('popover');
1030
- !popover.classList.contains( ops.animation) && popover.classList.add(ops.animation);
1031
- !popover.classList.contains( placementClass) && popover.classList.add(placementClass);
1032
- }
1033
- function showPopover() {
1034
- !popover.classList.contains('show') && ( popover.classList.add('show') );
1035
- }
1036
- function updatePopover() {
1037
- styleTip(element, popover, ops.placement, ops.container);
1038
- }
1039
- function forceFocus () {
1040
- if (popover === null) { element.focus(); }
1041
- }
1042
- function toggleEvents(action) {
1043
- action = action ? 'addEventListener' : 'removeEventListener';
1044
- if (ops.trigger === 'hover') {
1045
- element[action]( mouseClickEvents.down, self.show );
1046
- element[action]( mouseHoverEvents[0], self.show );
1047
- if (!ops.dismissible) { element[action]( mouseHoverEvents[1], self.hide ); }
1048
- } else if ('click' == ops.trigger) {
1049
- element[action]( ops.trigger, self.toggle );
1050
- } else if ('focus' == ops.trigger) {
1051
- isIphone && element[action]( 'click', forceFocus, false );
1052
- element[action]( ops.trigger, self.toggle );
1053
- }
1054
- }
1055
- function touchHandler(e){
1056
- if ( popover && popover.contains(e.target) || e.target === element || element.contains(e.target)) ; else {
1057
- self.hide();
1058
- }
1059
- }
1060
- function dismissHandlerToggle(action) {
1061
- action = action ? 'addEventListener' : 'removeEventListener';
1062
- if (ops.dismissible) {
1063
- document[action]('click', dismissibleHandler, false );
1064
- } else {
1065
- 'focus' == ops.trigger && element[action]( 'blur', self.hide );
1066
- 'hover' == ops.trigger && document[action]( 'touchstart', touchHandler, passiveHandler );
1067
- }
1068
- window[action]('resize', self.hide, passiveHandler );
1069
- }
1070
- function showTrigger() {
1071
- dismissHandlerToggle(1);
1072
- dispatchCustomEvent.call(element, shownCustomEvent);
1073
- }
1074
- function hideTrigger() {
1075
- dismissHandlerToggle();
1076
- removePopover();
1077
- dispatchCustomEvent.call(element, hiddenCustomEvent);
1078
- }
1079
- self.toggle = function () {
1080
- if (popover === null) { self.show(); }
1081
- else { self.hide(); }
1082
- };
1083
- self.show = function () {
1084
- clearTimeout(timer);
1085
- timer = setTimeout( function () {
1086
- if (popover === null) {
1087
- dispatchCustomEvent.call(element, showCustomEvent);
1088
- if ( showCustomEvent.defaultPrevented ) { return; }
1089
- createPopover();
1090
- updatePopover();
1091
- showPopover();
1092
- !!ops.animation ? emulateTransitionEnd(popover, showTrigger) : showTrigger();
1093
- }
1094
- }, 20 );
1095
- };
1096
- self.hide = function () {
1097
- clearTimeout(timer);
1098
- timer = setTimeout( function () {
1099
- if (popover && popover !== null && popover.classList.contains('show')) {
1100
- dispatchCustomEvent.call(element, hideCustomEvent);
1101
- if ( hideCustomEvent.defaultPrevented ) { return; }
1102
- popover.classList.remove('show');
1103
- !!ops.animation ? emulateTransitionEnd(popover, hideTrigger) : hideTrigger();
1104
- }
1105
- }, ops.delay );
1106
- };
1107
- self.dispose = function () {
1108
- self.hide();
1109
- toggleEvents();
1110
- delete element.Popover;
1111
- };
1112
- element = queryElement(element);
1113
- element.Popover && element.Popover.dispose();
1114
- triggerData = element.getAttribute('data-trigger');
1115
- animationData = element.getAttribute('data-animation');
1116
- placementData = element.getAttribute('data-placement');
1117
- dismissibleData = element.getAttribute('data-dismissible');
1118
- delayData = element.getAttribute('data-delay');
1119
- containerData = element.getAttribute('data-container');
1120
- closeBtn = '<button type="button" class="close">×</button>';
1121
- showCustomEvent = bootstrapCustomEvent('show', 'popover');
1122
- shownCustomEvent = bootstrapCustomEvent('shown', 'popover');
1123
- hideCustomEvent = bootstrapCustomEvent('hide', 'popover');
1124
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'popover');
1125
- containerElement = queryElement(options.container);
1126
- containerDataElement = queryElement(containerData);
1127
- modal = element.closest('.modal');
1128
- navbarFixedTop = element.closest('.fixed-top');
1129
- navbarFixedBottom = element.closest('.fixed-bottom');
1130
- ops.template = options.template ? options.template : null;
1131
- ops.trigger = options.trigger ? options.trigger : triggerData || 'hover';
1132
- ops.animation = options.animation && options.animation !== 'fade' ? options.animation : animationData || 'fade';
1133
- ops.placement = options.placement ? options.placement : placementData || 'top';
1134
- ops.delay = parseInt(options.delay || delayData) || 200;
1135
- ops.dismissible = options.dismissible || dismissibleData === 'true' ? true : false;
1136
- ops.container = containerElement ? containerElement
1137
- : containerDataElement ? containerDataElement
1138
- : navbarFixedTop ? navbarFixedTop
1139
- : navbarFixedBottom ? navbarFixedBottom
1140
- : modal ? modal : document.body;
1141
- placementClass = "bs-popover-" + (ops.placement);
1142
- var popoverContents = getContents();
1143
- titleString = popoverContents[0];
1144
- contentString = popoverContents[1];
1145
- if ( !contentString && !ops.template ) { return; }
1146
- if ( !element.Popover ) {
1147
- toggleEvents(1);
1148
- }
1149
- element.Popover = self;
1150
- }
1151
-
1152
- function ScrollSpy(element,options) {
1153
- options = options || {};
1154
- var self = this,
1155
- vars,
1156
- targetData,
1157
- offsetData,
1158
- spyTarget,
1159
- scrollTarget,
1160
- ops = {};
1161
- function updateTargets(){
1162
- var links = spyTarget.getElementsByTagName('A');
1163
- if (vars.length !== links.length) {
1164
- vars.items = [];
1165
- vars.targets = [];
1166
- Array.from(links).map(function (link){
1167
- var href = link.getAttribute('href'),
1168
- targetItem = href && href.charAt(0) === '#' && href.slice(-1) !== '#' && queryElement(href);
1169
- if ( targetItem ) {
1170
- vars.items.push(link);
1171
- vars.targets.push(targetItem);
1172
- }
1173
- });
1174
- vars.length = links.length;
1175
- }
1176
- }
1177
- function updateItem(index) {
1178
- var item = vars.items[index],
1179
- targetItem = vars.targets[index],
1180
- dropmenu = item.classList.contains('dropdown-item') && item.closest('.dropdown-menu'),
1181
- dropLink = dropmenu && dropmenu.previousElementSibling,
1182
- nextSibling = item.nextElementSibling,
1183
- activeSibling = nextSibling && nextSibling.getElementsByClassName('active').length,
1184
- targetRect = vars.isWindow && targetItem.getBoundingClientRect(),
1185
- isActive = item.classList.contains('active') || false,
1186
- topEdge = (vars.isWindow ? targetRect.top + vars.scrollOffset : targetItem.offsetTop) - ops.offset,
1187
- bottomEdge = vars.isWindow ? targetRect.bottom + vars.scrollOffset - ops.offset
1188
- : vars.targets[index+1] ? vars.targets[index+1].offsetTop - ops.offset
1189
- : element.scrollHeight,
1190
- inside = activeSibling || vars.scrollOffset >= topEdge && bottomEdge > vars.scrollOffset;
1191
- if ( !isActive && inside ) {
1192
- item.classList.add('active');
1193
- if (dropLink && !dropLink.classList.contains('active') ) {
1194
- dropLink.classList.add('active');
1195
- }
1196
- dispatchCustomEvent.call(element, bootstrapCustomEvent( 'activate', 'scrollspy', vars.items[index]));
1197
- } else if ( isActive && !inside ) {
1198
- item.classList.remove('active');
1199
- if (dropLink && dropLink.classList.contains('active') && !item.parentNode.getElementsByClassName('active').length ) {
1200
- dropLink.classList.remove('active');
1201
- }
1202
- } else if ( isActive && inside || !inside && !isActive ) {
1203
- return;
1204
- }
1205
- }
1206
- function updateItems() {
1207
- updateTargets();
1208
- vars.scrollOffset = vars.isWindow ? getScroll().y : element.scrollTop;
1209
- vars.items.map(function (l,idx){ return updateItem(idx); });
1210
- }
1211
- function toggleEvents(action) {
1212
- action = action ? 'addEventListener' : 'removeEventListener';
1213
- scrollTarget[action]('scroll', self.refresh, passiveHandler );
1214
- window[action]( 'resize', self.refresh, passiveHandler );
1215
- }
1216
- self.refresh = function () {
1217
- updateItems();
1218
- };
1219
- self.dispose = function () {
1220
- toggleEvents();
1221
- delete element.ScrollSpy;
1222
- };
1223
- element = queryElement(element);
1224
- element.ScrollSpy && element.ScrollSpy.dispose();
1225
- targetData = element.getAttribute('data-target');
1226
- offsetData = element.getAttribute('data-offset');
1227
- spyTarget = queryElement(options.target || targetData);
1228
- scrollTarget = element.offsetHeight < element.scrollHeight ? element : window;
1229
- if (!spyTarget) { return }
1230
- ops.target = spyTarget;
1231
- ops.offset = parseInt(options.offset || offsetData) || 10;
1232
- vars = {};
1233
- vars.length = 0;
1234
- vars.items = [];
1235
- vars.targets = [];
1236
- vars.isWindow = scrollTarget === window;
1237
- if ( !element.ScrollSpy ) {
1238
- toggleEvents(1);
1239
- }
1240
- self.refresh();
1241
- element.ScrollSpy = self;
1242
- }
1243
-
1244
- function Tab(element,options) {
1245
- options = options || {};
1246
- var self = this,
1247
- heightData,
1248
- tabs, dropdown,
1249
- showCustomEvent,
1250
- shownCustomEvent,
1251
- hideCustomEvent,
1252
- hiddenCustomEvent,
1253
- next,
1254
- tabsContentContainer = false,
1255
- activeTab,
1256
- activeContent,
1257
- nextContent,
1258
- containerHeight,
1259
- equalContents,
1260
- nextHeight,
1261
- animateHeight;
1262
- function triggerEnd() {
1263
- tabsContentContainer.style.height = '';
1264
- tabsContentContainer.classList.remove('collapsing');
1265
- tabs.isAnimating = false;
1266
- }
1267
- function triggerShow() {
1268
- if (tabsContentContainer) {
1269
- if ( equalContents ) {
1270
- triggerEnd();
1271
- } else {
1272
- setTimeout(function () {
1273
- tabsContentContainer.style.height = nextHeight + "px";
1274
- tabsContentContainer.offsetWidth;
1275
- emulateTransitionEnd(tabsContentContainer, triggerEnd);
1276
- },50);
1277
- }
1278
- } else {
1279
- tabs.isAnimating = false;
1280
- }
1281
- shownCustomEvent = bootstrapCustomEvent('shown', 'tab', activeTab);
1282
- dispatchCustomEvent.call(next, shownCustomEvent);
1283
- }
1284
- function triggerHide() {
1285
- if (tabsContentContainer) {
1286
- activeContent.style.float = 'left';
1287
- nextContent.style.float = 'left';
1288
- containerHeight = activeContent.scrollHeight;
1289
- }
1290
- showCustomEvent = bootstrapCustomEvent('show', 'tab', activeTab);
1291
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'tab', next);
1292
- dispatchCustomEvent.call(next, showCustomEvent);
1293
- if ( showCustomEvent.defaultPrevented ) { return; }
1294
- nextContent.classList.add('active');
1295
- activeContent.classList.remove('active');
1296
- if (tabsContentContainer) {
1297
- nextHeight = nextContent.scrollHeight;
1298
- equalContents = nextHeight === containerHeight;
1299
- tabsContentContainer.classList.add('collapsing');
1300
- tabsContentContainer.style.height = containerHeight + "px";
1301
- tabsContentContainer.offsetHeight;
1302
- activeContent.style.float = '';
1303
- nextContent.style.float = '';
1304
- }
1305
- if ( nextContent.classList.contains('fade') ) {
1306
- setTimeout(function () {
1307
- nextContent.classList.add('show');
1308
- emulateTransitionEnd(nextContent,triggerShow);
1309
- },20);
1310
- } else { triggerShow(); }
1311
- dispatchCustomEvent.call(activeTab, hiddenCustomEvent);
1312
- }
1313
- function getActiveTab() {
1314
- var activeTabs = tabs.getElementsByClassName('active'), activeTab;
1315
- if ( activeTabs.length === 1 && !activeTabs[0].parentNode.classList.contains('dropdown') ) {
1316
- activeTab = activeTabs[0];
1317
- } else if ( activeTabs.length > 1 ) {
1318
- activeTab = activeTabs[activeTabs.length-1];
1319
- }
1320
- return activeTab;
1321
- }
1322
- function getActiveContent() { return queryElement(getActiveTab().getAttribute('href')) }
1323
- function clickHandler(e) {
1324
- e.preventDefault();
1325
- next = e.currentTarget;
1326
- !tabs.isAnimating && self.show();
1327
- }
1328
- self.show = function () {
1329
- next = next || element;
1330
- if (!next.classList.contains('active')) {
1331
- nextContent = queryElement(next.getAttribute('href'));
1332
- activeTab = getActiveTab();
1333
- activeContent = getActiveContent();
1334
- hideCustomEvent = bootstrapCustomEvent( 'hide', 'tab', next);
1335
- dispatchCustomEvent.call(activeTab, hideCustomEvent);
1336
- if (hideCustomEvent.defaultPrevented) { return; }
1337
- tabs.isAnimating = true;
1338
- activeTab.classList.remove('active');
1339
- activeTab.setAttribute('aria-selected','false');
1340
- next.classList.add('active');
1341
- next.setAttribute('aria-selected','true');
1342
- if ( dropdown ) {
1343
- if ( !element.parentNode.classList.contains('dropdown-menu') ) {
1344
- if (dropdown.classList.contains('active')) { dropdown.classList.remove('active'); }
1345
- } else {
1346
- if (!dropdown.classList.contains('active')) { dropdown.classList.add('active'); }
1347
- }
1348
- }
1349
- if (activeContent.classList.contains('fade')) {
1350
- activeContent.classList.remove('show');
1351
- emulateTransitionEnd(activeContent, triggerHide);
1352
- } else { triggerHide(); }
1353
- }
1354
- };
1355
- self.dispose = function () {
1356
- element.removeEventListener('click',clickHandler,false);
1357
- delete element.Tab;
1358
- };
1359
- element = queryElement(element);
1360
- element.Tab && element.Tab.dispose();
1361
- heightData = element.getAttribute('data-height');
1362
- tabs = element.closest('.nav');
1363
- dropdown = tabs && queryElement('.dropdown-toggle',tabs);
1364
- animateHeight = !supportTransition || (options.height === false || heightData === 'false') ? false : true;
1365
- tabs.isAnimating = false;
1366
- if ( !element.Tab ) {
1367
- element.addEventListener('click',clickHandler,false);
1368
- }
1369
- if (animateHeight) { tabsContentContainer = getActiveContent().parentNode; }
1370
- element.Tab = self;
1371
- }
1372
-
1373
- function Toast(element,options) {
1374
- options = options || {};
1375
- var self = this,
1376
- toast, timer = 0,
1377
- animationData,
1378
- autohideData,
1379
- delayData,
1380
- showCustomEvent,
1381
- hideCustomEvent,
1382
- shownCustomEvent,
1383
- hiddenCustomEvent,
1384
- ops = {};
1385
- function showComplete() {
1386
- toast.classList.remove( 'showing' );
1387
- toast.classList.add( 'show' );
1388
- dispatchCustomEvent.call(toast,shownCustomEvent);
1389
- if (ops.autohide) { self.hide(); }
1390
- }
1391
- function hideComplete() {
1392
- toast.classList.add( 'hide' );
1393
- dispatchCustomEvent.call(toast,hiddenCustomEvent);
1394
- }
1395
- function close () {
1396
- toast.classList.remove('show' );
1397
- ops.animation ? emulateTransitionEnd(toast, hideComplete) : hideComplete();
1398
- }
1399
- function disposeComplete() {
1400
- clearTimeout(timer);
1401
- element.removeEventListener('click',self.hide,false);
1402
- delete element.Toast;
1403
- }
1404
- self.show = function () {
1405
- if (toast && !toast.classList.contains('show')) {
1406
- dispatchCustomEvent.call(toast,showCustomEvent);
1407
- if (showCustomEvent.defaultPrevented) { return; }
1408
- ops.animation && toast.classList.add( 'fade' );
1409
- toast.classList.remove('hide' );
1410
- toast.offsetWidth;
1411
- toast.classList.add('showing' );
1412
- ops.animation ? emulateTransitionEnd(toast, showComplete) : showComplete();
1413
- }
1414
- };
1415
- self.hide = function (noTimer) {
1416
- if (toast && toast.classList.contains('show')) {
1417
- dispatchCustomEvent.call(toast,hideCustomEvent);
1418
- if(hideCustomEvent.defaultPrevented) { return; }
1419
- noTimer ? close() : (timer = setTimeout( close, ops.delay));
1420
- }
1421
- };
1422
- self.dispose = function () {
1423
- ops.animation ? emulateTransitionEnd(toast, disposeComplete) : disposeComplete();
1424
- };
1425
- element = queryElement(element);
1426
- element.Toast && element.Toast.dispose();
1427
- toast = element.closest('.toast');
1428
- animationData = element.getAttribute('data-animation');
1429
- autohideData = element.getAttribute('data-autohide');
1430
- delayData = element.getAttribute('data-delay');
1431
- showCustomEvent = bootstrapCustomEvent('show', 'toast');
1432
- hideCustomEvent = bootstrapCustomEvent('hide', 'toast');
1433
- shownCustomEvent = bootstrapCustomEvent('shown', 'toast');
1434
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'toast');
1435
- ops.animation = options.animation === false || animationData === 'false' ? 0 : 1;
1436
- ops.autohide = options.autohide === false || autohideData === 'false' ? 0 : 1;
1437
- ops.delay = parseInt(options.delay || delayData) || 500;
1438
- if ( !element.Toast ) {
1439
- element.addEventListener('click',self.hide,false);
1440
- }
1441
- element.Toast = self;
1442
- }
1443
-
1444
- function Tooltip(element,options) {
1445
- options = options || {};
1446
- var self = this,
1447
- tooltip = null, timer = 0, titleString,
1448
- animationData,
1449
- placementData,
1450
- delayData,
1451
- containerData,
1452
- showCustomEvent,
1453
- shownCustomEvent,
1454
- hideCustomEvent,
1455
- hiddenCustomEvent,
1456
- containerElement,
1457
- containerDataElement,
1458
- modal,
1459
- navbarFixedTop,
1460
- navbarFixedBottom,
1461
- placementClass,
1462
- ops = {};
1463
- function getTitle() {
1464
- return element.getAttribute('title')
1465
- || element.getAttribute('data-title')
1466
- || element.getAttribute('data-original-title')
1467
- }
1468
- function removeToolTip() {
1469
- ops.container.removeChild(tooltip);
1470
- tooltip = null; timer = null;
1471
- }
1472
- function createToolTip() {
1473
- titleString = getTitle();
1474
- if ( titleString ) {
1475
- tooltip = document.createElement('div');
1476
- if (ops.template) {
1477
- var tooltipMarkup = document.createElement('div');
1478
- tooltipMarkup.innerHTML = ops.template.trim();
1479
- tooltip.className = tooltipMarkup.firstChild.className;
1480
- tooltip.innerHTML = tooltipMarkup.firstChild.innerHTML;
1481
- queryElement('.tooltip-inner',tooltip).innerHTML = titleString.trim();
1482
- } else {
1483
- var tooltipArrow = document.createElement('div');
1484
- tooltipArrow.classList.add('arrow');
1485
- tooltip.appendChild(tooltipArrow);
1486
- var tooltipInner = document.createElement('div');
1487
- tooltipInner.classList.add('tooltip-inner');
1488
- tooltip.appendChild(tooltipInner);
1489
- tooltipInner.innerHTML = titleString;
1490
- }
1491
- tooltip.style.left = '0';
1492
- tooltip.style.top = '0';
1493
- tooltip.setAttribute('role','tooltip');
1494
- !tooltip.classList.contains('tooltip') && tooltip.classList.add('tooltip');
1495
- !tooltip.classList.contains(ops.animation) && tooltip.classList.add(ops.animation);
1496
- !tooltip.classList.contains(placementClass) && tooltip.classList.add(placementClass);
1497
- ops.container.appendChild(tooltip);
1498
- }
1499
- }
1500
- function updateTooltip() {
1501
- styleTip(element, tooltip, ops.placement, ops.container);
1502
- }
1503
- function showTooltip() {
1504
- !tooltip.classList.contains('show') && ( tooltip.classList.add('show') );
1505
- }
1506
- function touchHandler(e){
1507
- if ( tooltip && tooltip.contains(e.target) || e.target === element || element.contains(e.target)) ; else {
1508
- self.hide();
1509
- }
1510
- }
1511
- function toggleAction(action){
1512
- action = action ? 'addEventListener' : 'removeEventListener';
1513
- document[action]( 'touchstart', touchHandler, passiveHandler );
1514
- window[action]( 'resize', self.hide, passiveHandler );
1515
- }
1516
- function showAction() {
1517
- toggleAction(1);
1518
- dispatchCustomEvent.call(element, shownCustomEvent);
1519
- }
1520
- function hideAction() {
1521
- toggleAction();
1522
- removeToolTip();
1523
- dispatchCustomEvent.call(element, hiddenCustomEvent);
1524
- }
1525
- function toggleEvents(action) {
1526
- action = action ? 'addEventListener' : 'removeEventListener';
1527
- element[action](mouseClickEvents.down, self.show,false);
1528
- element[action](mouseHoverEvents[0], self.show,false);
1529
- element[action](mouseHoverEvents[1], self.hide,false);
1530
- }
1531
- self.show = function () {
1532
- clearTimeout(timer);
1533
- timer = setTimeout( function () {
1534
- if (tooltip === null) {
1535
- dispatchCustomEvent.call(element, showCustomEvent);
1536
- if (showCustomEvent.defaultPrevented) { return; }
1537
- if(createToolTip() !== false) {
1538
- updateTooltip();
1539
- showTooltip();
1540
- !!ops.animation ? emulateTransitionEnd(tooltip, showAction) : showAction();
1541
- }
1542
- }
1543
- }, 20 );
1544
- };
1545
- self.hide = function () {
1546
- clearTimeout(timer);
1547
- timer = setTimeout( function () {
1548
- if (tooltip && tooltip.classList.contains('show')) {
1549
- dispatchCustomEvent.call(element, hideCustomEvent);
1550
- if (hideCustomEvent.defaultPrevented) { return; }
1551
- tooltip.classList.remove('show');
1552
- !!ops.animation ? emulateTransitionEnd(tooltip, hideAction) : hideAction();
1553
- }
1554
- }, ops.delay);
1555
- };
1556
- self.toggle = function () {
1557
- if (!tooltip) { self.show(); }
1558
- else { self.hide(); }
1559
- };
1560
- self.dispose = function () {
1561
- toggleEvents();
1562
- self.hide();
1563
- element.setAttribute('title', element.getAttribute('data-original-title'));
1564
- element.removeAttribute('data-original-title');
1565
- delete element.Tooltip;
1566
- };
1567
- element = queryElement(element);
1568
- element.Tooltip && element.Tooltip.dispose();
1569
- animationData = element.getAttribute('data-animation');
1570
- placementData = element.getAttribute('data-placement');
1571
- delayData = element.getAttribute('data-delay');
1572
- containerData = element.getAttribute('data-container');
1573
- showCustomEvent = bootstrapCustomEvent('show', 'tooltip');
1574
- shownCustomEvent = bootstrapCustomEvent('shown', 'tooltip');
1575
- hideCustomEvent = bootstrapCustomEvent('hide', 'tooltip');
1576
- hiddenCustomEvent = bootstrapCustomEvent('hidden', 'tooltip');
1577
- containerElement = queryElement(options.container);
1578
- containerDataElement = queryElement(containerData);
1579
- modal = element.closest('.modal');
1580
- navbarFixedTop = element.closest('.fixed-top');
1581
- navbarFixedBottom = element.closest('.fixed-bottom');
1582
- ops.animation = options.animation && options.animation !== 'fade' ? options.animation : animationData || 'fade';
1583
- ops.placement = options.placement ? options.placement : placementData || 'top';
1584
- ops.template = options.template ? options.template : null;
1585
- ops.delay = parseInt(options.delay || delayData) || 200;
1586
- ops.container = containerElement ? containerElement
1587
- : containerDataElement ? containerDataElement
1588
- : navbarFixedTop ? navbarFixedTop
1589
- : navbarFixedBottom ? navbarFixedBottom
1590
- : modal ? modal : document.body;
1591
- placementClass = "bs-tooltip-" + (ops.placement);
1592
- titleString = getTitle();
1593
- if ( !titleString ) { return; }
1594
- if (!element.Tooltip) {
1595
- element.setAttribute('data-original-title',titleString);
1596
- element.removeAttribute('title');
1597
- toggleEvents(1);
1598
- }
1599
- element.Tooltip = self;
1600
- }
1601
-
1602
- var componentsInit = {};
1603
-
1604
- function initializeDataAPI( Constructor, collection ){
1605
- Array.from(collection).map(function (x){ return new Constructor(x); });
1606
- }
1607
- function initCallback(lookUp){
1608
- lookUp = lookUp || document;
1609
- for (var component in componentsInit) {
1610
- initializeDataAPI( componentsInit[component][0], lookUp.querySelectorAll (componentsInit[component][1]) );
1611
- }
1612
- }
1613
-
1614
- componentsInit.Alert = [ Alert, '[data-dismiss="alert"]'];
1615
- componentsInit.Button = [ Button, '[data-toggle="buttons"]' ];
1616
- componentsInit.Carousel = [ Carousel, '[data-ride="carousel"]' ];
1617
- componentsInit.Collapse = [ Collapse, '[data-toggle="collapse"]' ];
1618
- componentsInit.Dropdown = [ Dropdown, '[data-toggle="dropdown"]'];
1619
- componentsInit.Modal = [ Modal, '[data-toggle="modal"]' ];
1620
- componentsInit.Popover = [ Popover, '[data-toggle="popover"],[data-tip="popover"]' ];
1621
- componentsInit.ScrollSpy = [ ScrollSpy, '[data-spy="scroll"]' ];
1622
- componentsInit.Tab = [ Tab, '[data-toggle="tab"]' ];
1623
- componentsInit.Toast = [ Toast, '[data-dismiss="toast"]' ];
1624
- componentsInit.Tooltip = [ Tooltip, '[data-toggle="tooltip"],[data-tip="tooltip"]' ];
1625
- document.body ? initCallback() : document.addEventListener( 'DOMContentLoaded', function initWrapper(){
1626
- initCallback();
1627
- document.removeEventListener('DOMContentLoaded',initWrapper,false);
1628
- }, false );
1629
-
1630
- function removeElementDataAPI( ConstructorName, collection ){
1631
- Array.from(collection).map(function (x){ return x[ConstructorName].dispose(); });
1632
- }
1633
- function removeDataAPI(lookUp) {
1634
- lookUp = lookUp || document;
1635
- for (var component in componentsInit) {
1636
- removeElementDataAPI( component, lookUp.querySelectorAll (componentsInit[component][1]) );
1637
- }
1638
- }
1639
-
1640
- var version = "3.0.10";
1641
-
1642
- var index = {
1643
- Alert: Alert,
1644
- Button: Button,
1645
- Carousel: Carousel,
1646
- Collapse: Collapse,
1647
- Dropdown: Dropdown,
1648
- Modal: Modal,
1649
- Popover: Popover,
1650
- ScrollSpy: ScrollSpy,
1651
- Tab: Tab,
1652
- Toast: Toast,
1653
- Tooltip: Tooltip,
1654
- initCallback: initCallback,
1655
- removeDataAPI: removeDataAPI,
1656
- componentsInit: componentsInit,
1657
- Version: version
1658
- };
1659
-
1660
- return index;
1661
-
1662
- })));