good_job 1.9.2 → 1.10.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +98 -1
- data/README.md +17 -0
- data/engine/app/assets/vendor/bootstrap/bootstrap.bundle.min.js +7 -0
- data/engine/app/assets/vendor/bootstrap/bootstrap.min.css +7 -0
- data/engine/app/controllers/good_job/assets_controller.rb +29 -0
- data/engine/app/controllers/good_job/dashboards_controller.rb +8 -6
- data/engine/app/controllers/good_job/jobs_controller.rb +9 -0
- data/engine/app/views/good_job/dashboards/index.html.erb +1 -1
- data/engine/app/views/layouts/good_job/base.html.erb +21 -12
- data/engine/app/views/shared/_chart.erb +3 -2
- data/engine/app/views/shared/_jobs_table.erb +13 -1
- data/engine/app/views/shared/icons/_check.html.erb +4 -0
- data/engine/app/views/shared/icons/_exclamation.html.erb +4 -0
- data/engine/app/views/shared/icons/_trash.html.erb +5 -0
- data/engine/config/routes.rb +10 -1
- data/lib/generators/good_job/install_generator.rb +5 -15
- data/lib/generators/good_job/templates/install/migrations/create_good_jobs.rb.erb +27 -0
- data/lib/generators/good_job/templates/{migration.rb.erb → update/migrations/01_create_good_jobs.rb} +3 -3
- data/lib/generators/good_job/templates/update/migrations/02_add_active_job_id_concurrency_key_cron_key_to_good_jobs.rb +15 -0
- data/lib/generators/good_job/templates/update/migrations/03_add_active_job_id_index_and_concurrency_key_index_to_good_jobs.rb +32 -0
- data/lib/generators/good_job/update_generator.rb +29 -0
- data/lib/good_job.rb +12 -8
- data/lib/good_job/adapter.rb +15 -11
- data/lib/good_job/configuration.rb +3 -3
- data/lib/good_job/current_execution.rb +0 -1
- data/lib/good_job/daemon.rb +6 -0
- data/lib/good_job/job.rb +38 -7
- data/lib/good_job/job_performer.rb +2 -2
- data/lib/good_job/lockable.rb +109 -56
- data/lib/good_job/log_subscriber.rb +15 -14
- data/lib/good_job/multi_scheduler.rb +9 -0
- data/lib/good_job/notifier.rb +4 -2
- data/lib/good_job/poller.rb +16 -7
- data/lib/good_job/scheduler.rb +12 -6
- data/lib/good_job/version.rb +1 -1
- metadata +28 -5
- data/engine/app/assets/vendor/bootstrap/bootstrap-native.js +0 -1662
- data/engine/app/assets/vendor/bootstrap/bootstrap.css +0 -10258
@@ -14,6 +14,7 @@ module GoodJob
|
|
14
14
|
|
15
15
|
# @!macro notification_responder
|
16
16
|
# Responds to the +$0.good_job+ notification.
|
17
|
+
# @param event [ActiveSupport::Notifications::Event]
|
17
18
|
# @return [void]
|
18
19
|
def create(event)
|
19
20
|
# FIXME: This method does not match any good_job notifications.
|
@@ -24,7 +25,7 @@ module GoodJob
|
|
24
25
|
end
|
25
26
|
end
|
26
27
|
|
27
|
-
#
|
28
|
+
# @!macro notification_responder
|
28
29
|
def finished_timer_task(event)
|
29
30
|
exception = event.payload[:error]
|
30
31
|
return unless exception
|
@@ -34,7 +35,7 @@ module GoodJob
|
|
34
35
|
end
|
35
36
|
end
|
36
37
|
|
37
|
-
#
|
38
|
+
# @!macro notification_responder
|
38
39
|
def finished_job_task(event)
|
39
40
|
exception = event.payload[:error]
|
40
41
|
return unless exception
|
@@ -44,7 +45,7 @@ module GoodJob
|
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
47
|
-
#
|
48
|
+
# @!macro notification_responder
|
48
49
|
def scheduler_create_pool(event)
|
49
50
|
max_threads = event.payload[:max_threads]
|
50
51
|
performer_name = event.payload[:performer_name]
|
@@ -55,7 +56,7 @@ module GoodJob
|
|
55
56
|
end
|
56
57
|
end
|
57
58
|
|
58
|
-
#
|
59
|
+
# @!macro notification_responder
|
59
60
|
def scheduler_shutdown_start(event)
|
60
61
|
process_id = event.payload[:process_id]
|
61
62
|
|
@@ -64,7 +65,7 @@ module GoodJob
|
|
64
65
|
end
|
65
66
|
end
|
66
67
|
|
67
|
-
#
|
68
|
+
# @!macro notification_responder
|
68
69
|
def scheduler_shutdown(event)
|
69
70
|
process_id = event.payload[:process_id]
|
70
71
|
|
@@ -73,7 +74,7 @@ module GoodJob
|
|
73
74
|
end
|
74
75
|
end
|
75
76
|
|
76
|
-
#
|
77
|
+
# @!macro notification_responder
|
77
78
|
def scheduler_restart_pools(event)
|
78
79
|
process_id = event.payload[:process_id]
|
79
80
|
|
@@ -82,7 +83,7 @@ module GoodJob
|
|
82
83
|
end
|
83
84
|
end
|
84
85
|
|
85
|
-
#
|
86
|
+
# @!macro notification_responder
|
86
87
|
def perform_job(event)
|
87
88
|
good_job = event.payload[:good_job]
|
88
89
|
process_id = event.payload[:process_id]
|
@@ -93,14 +94,14 @@ module GoodJob
|
|
93
94
|
end
|
94
95
|
end
|
95
96
|
|
96
|
-
#
|
97
|
-
def notifier_listen(
|
97
|
+
# @!macro notification_responder
|
98
|
+
def notifier_listen(event) # rubocop:disable Lint/UnusedMethodArgument
|
98
99
|
info do
|
99
100
|
"Notifier subscribed with LISTEN"
|
100
101
|
end
|
101
102
|
end
|
102
103
|
|
103
|
-
#
|
104
|
+
# @!macro notification_responder
|
104
105
|
def notifier_notified(event)
|
105
106
|
payload = event.payload[:payload]
|
106
107
|
|
@@ -109,7 +110,7 @@ module GoodJob
|
|
109
110
|
end
|
110
111
|
end
|
111
112
|
|
112
|
-
#
|
113
|
+
# @!macro notification_responder
|
113
114
|
def notifier_notify_error(event)
|
114
115
|
error = event.payload[:error]
|
115
116
|
|
@@ -118,14 +119,14 @@ module GoodJob
|
|
118
119
|
end
|
119
120
|
end
|
120
121
|
|
121
|
-
#
|
122
|
-
def notifier_unlisten(
|
122
|
+
# @!macro notification_responder
|
123
|
+
def notifier_unlisten(event) # rubocop:disable Lint/UnusedMethodArgument
|
123
124
|
info do
|
124
125
|
"Notifier unsubscribed with UNLISTEN"
|
125
126
|
end
|
126
127
|
end
|
127
128
|
|
128
|
-
#
|
129
|
+
# @!macro notification_responder
|
129
130
|
def cleanup_preserved_jobs(event)
|
130
131
|
timestamp = event.payload[:timestamp]
|
131
132
|
deleted_records_count = event.payload[:deleted_records_count]
|
@@ -4,31 +4,40 @@ module GoodJob
|
|
4
4
|
# @return [Array<Scheduler>] List of the scheduler delegates
|
5
5
|
attr_reader :schedulers
|
6
6
|
|
7
|
+
# @param schedulers [Array<Scheduler>]
|
7
8
|
def initialize(schedulers)
|
8
9
|
@schedulers = schedulers
|
9
10
|
end
|
10
11
|
|
11
12
|
# Delegates to {Scheduler#running?}.
|
13
|
+
# @return [Boolean, nil]
|
12
14
|
def running?
|
13
15
|
schedulers.all?(&:running?)
|
14
16
|
end
|
15
17
|
|
16
18
|
# Delegates to {Scheduler#shutdown?}.
|
19
|
+
# @return [Boolean, nil]
|
17
20
|
def shutdown?
|
18
21
|
schedulers.all?(&:shutdown?)
|
19
22
|
end
|
20
23
|
|
21
24
|
# Delegates to {Scheduler#shutdown}.
|
25
|
+
# @param timeout [Numeric, nil]
|
26
|
+
# @return [void]
|
22
27
|
def shutdown(timeout: -1)
|
23
28
|
GoodJob._shutdown_all(schedulers, timeout: timeout)
|
24
29
|
end
|
25
30
|
|
26
31
|
# Delegates to {Scheduler#restart}.
|
32
|
+
# @param timeout [Numeric, nil]
|
33
|
+
# @return [void]
|
27
34
|
def restart(timeout: -1)
|
28
35
|
GoodJob._shutdown_all(schedulers, :restart, timeout: timeout)
|
29
36
|
end
|
30
37
|
|
31
38
|
# Delegates to {Scheduler#create_thread}.
|
39
|
+
# @param state [Hash]
|
40
|
+
# @return [Boolean, nil]
|
32
41
|
def create_thread(state = nil)
|
33
42
|
results = []
|
34
43
|
|
data/lib/good_job/notifier.rb
CHANGED
@@ -30,7 +30,7 @@ module GoodJob # :nodoc:
|
|
30
30
|
# @!attribute [r] instances
|
31
31
|
# @!scope class
|
32
32
|
# List of all instantiated Notifiers in the current process.
|
33
|
-
# @return [Array<GoodJob::
|
33
|
+
# @return [Array<GoodJob::Notifier>, nil]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Send a message via Postgres NOTIFY
|
@@ -64,17 +64,19 @@ module GoodJob # :nodoc:
|
|
64
64
|
end
|
65
65
|
|
66
66
|
# Tests whether the notifier is running.
|
67
|
+
# @!method running?
|
67
68
|
# @return [true, false, nil]
|
68
69
|
delegate :running?, to: :executor, allow_nil: true
|
69
70
|
|
70
71
|
# Tests whether the scheduler is shutdown.
|
72
|
+
# @!method shutdown?
|
71
73
|
# @return [true, false, nil]
|
72
74
|
delegate :shutdown?, to: :executor, allow_nil: true
|
73
75
|
|
74
76
|
# Shut down the notifier.
|
75
77
|
# This stops the background LISTENing thread.
|
76
78
|
# Use {#shutdown?} to determine whether threads have stopped.
|
77
|
-
# @param timeout [
|
79
|
+
# @param timeout [Numeric, nil] Seconds to wait for active threads.
|
78
80
|
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
79
81
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
80
82
|
# * +0+, the scheduler will immediately shutdown and stop any threads.
|
data/lib/good_job/poller.rb
CHANGED
@@ -5,18 +5,20 @@ 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:
|
14
|
+
timeout_interval: TIMEOUT_INTERVAL,
|
13
15
|
run_now: true,
|
14
16
|
}.freeze
|
15
17
|
|
16
18
|
# @!attribute [r] instances
|
17
19
|
# @!scope class
|
18
20
|
# List of all instantiated Pollers in the current process.
|
19
|
-
# @return [Array<GoodJob::Poller
|
21
|
+
# @return [Array<GoodJob::Poller>, nil]
|
20
22
|
cattr_reader :instances, default: [], instance_reader: false
|
21
23
|
|
22
24
|
# Creates GoodJob::Poller from a GoodJob::Configuration instance.
|
@@ -30,8 +32,8 @@ module GoodJob # :nodoc:
|
|
30
32
|
# @return [Array<#call, Array(Object, Symbol)>]
|
31
33
|
attr_reader :recipients
|
32
34
|
|
33
|
-
# @param recipients [Array
|
34
|
-
# @param poll_interval [
|
35
|
+
# @param recipients [Array<Proc, #call, Array(Object, Symbol)>]
|
36
|
+
# @param poll_interval [Integer, nil] number of seconds between polls
|
35
37
|
def initialize(*recipients, poll_interval: nil)
|
36
38
|
@recipients = Concurrent::Array.new(recipients)
|
37
39
|
|
@@ -49,9 +51,11 @@ module GoodJob # :nodoc:
|
|
49
51
|
|
50
52
|
# Tests whether the timer is shutdown.
|
51
53
|
# @return [true, false, nil]
|
52
|
-
|
54
|
+
def shutdown?
|
55
|
+
timer ? timer.shutdown? : true
|
56
|
+
end
|
53
57
|
|
54
|
-
# Shut down the
|
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.
|
@@ -72,7 +76,7 @@ module GoodJob # :nodoc:
|
|
72
76
|
|
73
77
|
# Restart the poller.
|
74
78
|
# When shutdown, start; or shutdown and start.
|
75
|
-
# @param timeout [
|
79
|
+
# @param timeout [Numeric, nil] Seconds to wait; shares same values as {#shutdown}.
|
76
80
|
# @return [void]
|
77
81
|
def restart(timeout: -1)
|
78
82
|
shutdown(timeout: timeout) if running?
|
@@ -81,6 +85,9 @@ module GoodJob # :nodoc:
|
|
81
85
|
|
82
86
|
# Invoked on completion of TimerTask task.
|
83
87
|
# @!visibility private
|
88
|
+
# @param time [Integer]
|
89
|
+
# @param executed_task [Object, nil]
|
90
|
+
# @param thread_error [Exception, nil]
|
84
91
|
# @return [void]
|
85
92
|
def timer_observer(time, executed_task, thread_error)
|
86
93
|
GoodJob.on_thread_error.call(thread_error) if thread_error && GoodJob.on_thread_error.respond_to?(:call)
|
@@ -89,8 +96,10 @@ module GoodJob # :nodoc:
|
|
89
96
|
|
90
97
|
private
|
91
98
|
|
99
|
+
# @return [Concurrent::TimerTask]
|
92
100
|
attr_reader :timer
|
93
101
|
|
102
|
+
# @return [void]
|
94
103
|
def create_timer
|
95
104
|
return if @timer_options[:execution_interval] <= 0
|
96
105
|
|
data/lib/good_job/scheduler.rb
CHANGED
@@ -30,7 +30,7 @@ module GoodJob # :nodoc:
|
|
30
30
|
# @!attribute [r] instances
|
31
31
|
# @!scope class
|
32
32
|
# List of all instantiated Schedulers in the current process.
|
33
|
-
# @return [Array<GoodJob::Scheduler
|
33
|
+
# @return [Array<GoodJob::Scheduler>, nil]
|
34
34
|
cattr_reader :instances, default: [], instance_reader: false
|
35
35
|
|
36
36
|
# Creates GoodJob::Scheduler(s) and Performers from a GoodJob::Configuration instance.
|
@@ -82,17 +82,17 @@ module GoodJob # :nodoc:
|
|
82
82
|
end
|
83
83
|
|
84
84
|
# Tests whether the scheduler is running.
|
85
|
-
# @return [
|
85
|
+
# @return [Boolean, nil]
|
86
86
|
delegate :running?, to: :executor, allow_nil: true
|
87
87
|
|
88
88
|
# Tests whether the scheduler is shutdown.
|
89
|
-
# @return [
|
89
|
+
# @return [Boolean, nil]
|
90
90
|
delegate :shutdown?, to: :executor, allow_nil: true
|
91
91
|
|
92
92
|
# Shut down the scheduler.
|
93
93
|
# This stops all threads in the thread pool.
|
94
94
|
# Use {#shutdown?} to determine whether threads have stopped.
|
95
|
-
# @param timeout [
|
95
|
+
# @param timeout [Numeric, nil] Seconds to wait for actively executing jobs to finish
|
96
96
|
# * +nil+, the scheduler will trigger a shutdown but not wait for it to complete.
|
97
97
|
# * +-1+, the scheduler will wait until the shutdown is complete.
|
98
98
|
# * +0+, the scheduler will immediately shutdown and stop any active tasks.
|
@@ -128,8 +128,8 @@ module GoodJob # :nodoc:
|
|
128
128
|
end
|
129
129
|
|
130
130
|
# Wakes a thread to allow the performer to execute a task.
|
131
|
-
# @param state [
|
132
|
-
# @return [
|
131
|
+
# @param state [Hash, nil] Contextual information for the performer. See {JobPerformer#next?}.
|
132
|
+
# @return [Boolean, nil] Whether work was started.
|
133
133
|
#
|
134
134
|
# * +nil+ if the scheduler is unable to take new work, for example if the thread pool is shut down or at capacity.
|
135
135
|
# * +true+ if the performer started executing work.
|
@@ -215,6 +215,7 @@ module GoodJob # :nodoc:
|
|
215
215
|
|
216
216
|
attr_reader :performer, :executor, :timer_set
|
217
217
|
|
218
|
+
# @return [void]
|
218
219
|
def create_executor
|
219
220
|
instrument("scheduler_create_pool", { performer_name: performer.name, max_threads: @executor_options[:max_threads] }) do
|
220
221
|
@timer_set = TimerSet.new
|
@@ -222,6 +223,8 @@ module GoodJob # :nodoc:
|
|
222
223
|
end
|
223
224
|
end
|
224
225
|
|
226
|
+
# @param delay [Integer]
|
227
|
+
# @return [void]
|
225
228
|
def create_task(delay = 0)
|
226
229
|
future = Concurrent::ScheduledTask.new(delay, args: [performer], executor: executor, timer_set: timer_set) do |thr_performer|
|
227
230
|
Rails.application.executor.wrap do
|
@@ -232,6 +235,9 @@ module GoodJob # :nodoc:
|
|
232
235
|
future.execute
|
233
236
|
end
|
234
237
|
|
238
|
+
# @param name [String]
|
239
|
+
# @param payload [Hash]
|
240
|
+
# @return [void]
|
235
241
|
def instrument(name, payload = {}, &block)
|
236
242
|
payload = payload.reverse_merge({
|
237
243
|
scheduler: self,
|
data/lib/good_job/version.rb
CHANGED
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.
|
4
|
+
version: 1.10.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-
|
11
|
+
date: 2021-06-29 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,25 +333,34 @@ files:
|
|
319
333
|
- LICENSE.txt
|
320
334
|
- README.md
|
321
335
|
- engine/app/assets/style.css
|
322
|
-
- engine/app/assets/vendor/bootstrap/bootstrap
|
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/
|
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
|
342
365
|
- lib/good_job/adapter.rb
|
343
366
|
- lib/good_job/cli.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
|
-
})));
|