├── .gitattributes
├── .github
└── workflows
│ └── ci.yml
├── .gitignore
├── CHANGELOG.md
├── Gemfile
├── LICENSE
├── README.md
├── Rakefile
├── assets
├── javascripts
│ ├── bootstrap-global-this-define.js
│ ├── bootstrap-global-this-undefine.js
│ ├── bootstrap-sprockets.js
│ ├── bootstrap.js
│ ├── bootstrap.min.js
│ └── bootstrap
│ │ ├── alert.js
│ │ ├── base-component.js
│ │ ├── button.js
│ │ ├── carousel.js
│ │ ├── collapse.js
│ │ ├── dom
│ │ ├── data.js
│ │ ├── event-handler.js
│ │ ├── manipulator.js
│ │ └── selector-engine.js
│ │ ├── dropdown.js
│ │ ├── modal.js
│ │ ├── offcanvas.js
│ │ ├── popover.js
│ │ ├── scrollspy.js
│ │ ├── tab.js
│ │ ├── toast.js
│ │ ├── tooltip.js
│ │ └── util
│ │ ├── backdrop.js
│ │ ├── component-functions.js
│ │ ├── config.js
│ │ ├── focustrap.js
│ │ ├── index.js
│ │ ├── sanitizer.js
│ │ ├── scrollbar.js
│ │ ├── swipe.js
│ │ └── template-factory.js
└── stylesheets
│ ├── _bootstrap-grid.scss
│ ├── _bootstrap-reboot.scss
│ ├── _bootstrap-utilities.scss
│ ├── _bootstrap.scss
│ └── bootstrap
│ ├── _accordion.scss
│ ├── _alert.scss
│ ├── _badge.scss
│ ├── _breadcrumb.scss
│ ├── _button-group.scss
│ ├── _buttons.scss
│ ├── _card.scss
│ ├── _carousel.scss
│ ├── _close.scss
│ ├── _containers.scss
│ ├── _dropdown.scss
│ ├── _forms.scss
│ ├── _functions.scss
│ ├── _grid.scss
│ ├── _helpers.scss
│ ├── _images.scss
│ ├── _list-group.scss
│ ├── _maps.scss
│ ├── _mixins.scss
│ ├── _modal.scss
│ ├── _nav.scss
│ ├── _navbar.scss
│ ├── _offcanvas.scss
│ ├── _pagination.scss
│ ├── _placeholders.scss
│ ├── _popover.scss
│ ├── _progress.scss
│ ├── _reboot.scss
│ ├── _root.scss
│ ├── _spinners.scss
│ ├── _tables.scss
│ ├── _toasts.scss
│ ├── _tooltip.scss
│ ├── _transitions.scss
│ ├── _type.scss
│ ├── _utilities.scss
│ ├── _variables-dark.scss
│ ├── _variables.scss
│ ├── forms
│ ├── _floating-labels.scss
│ ├── _form-check.scss
│ ├── _form-control.scss
│ ├── _form-range.scss
│ ├── _form-select.scss
│ ├── _form-text.scss
│ ├── _input-group.scss
│ ├── _labels.scss
│ └── _validation.scss
│ ├── helpers
│ ├── _clearfix.scss
│ ├── _color-bg.scss
│ ├── _colored-links.scss
│ ├── _focus-ring.scss
│ ├── _icon-link.scss
│ ├── _position.scss
│ ├── _ratio.scss
│ ├── _stacks.scss
│ ├── _stretched-link.scss
│ ├── _text-truncation.scss
│ ├── _visually-hidden.scss
│ └── _vr.scss
│ ├── mixins
│ ├── _alert.scss
│ ├── _backdrop.scss
│ ├── _banner.scss
│ ├── _border-radius.scss
│ ├── _box-shadow.scss
│ ├── _breakpoints.scss
│ ├── _buttons.scss
│ ├── _caret.scss
│ ├── _clearfix.scss
│ ├── _color-mode.scss
│ ├── _color-scheme.scss
│ ├── _container.scss
│ ├── _deprecate.scss
│ ├── _forms.scss
│ ├── _gradients.scss
│ ├── _grid.scss
│ ├── _image.scss
│ ├── _list-group.scss
│ ├── _lists.scss
│ ├── _pagination.scss
│ ├── _reset-text.scss
│ ├── _resize.scss
│ ├── _table-variants.scss
│ ├── _text-truncate.scss
│ ├── _transition.scss
│ ├── _utilities.scss
│ └── _visually-hidden.scss
│ ├── utilities
│ └── _api.scss
│ └── vendor
│ └── _rfs.scss
├── bootstrap.gemspec
├── lib
├── bootstrap.rb
└── bootstrap
│ ├── engine.rb
│ └── version.rb
├── tasks
├── updater.rb
└── updater
│ ├── js.rb
│ ├── logger.rb
│ ├── network.rb
│ └── scss.rb
└── test
├── dummy_rails
├── README.rdoc
├── Rakefile
├── app
│ ├── assets
│ │ ├── config
│ │ │ └── manifest.js
│ │ ├── images
│ │ │ └── .keep
│ │ ├── javascripts
│ │ │ └── application.js
│ │ └── stylesheets
│ │ │ ├── .browserslistrc
│ │ │ └── application.sass
│ ├── controllers
│ │ ├── application_controller.rb
│ │ └── pages_controller.rb
│ ├── helpers
│ │ └── application_helper.rb
│ └── views
│ │ ├── layouts
│ │ └── application.html.erb
│ │ └── pages
│ │ └── root.html
├── config.ru
├── config
│ ├── application.rb
│ ├── boot.rb
│ ├── environment.rb
│ ├── environments
│ │ ├── development.rb
│ │ ├── production.rb
│ │ └── test.rb
│ ├── initializers
│ │ ├── backtrace_silencers.rb
│ │ ├── filter_parameter_logging.rb
│ │ ├── inflections.rb
│ │ ├── mime_types.rb
│ │ ├── secret_token.rb
│ │ ├── session_store.rb
│ │ └── wrap_parameters.rb
│ ├── locales
│ │ ├── en.yml
│ │ └── es.yml
│ └── routes.rb
├── log
│ └── .keep
└── public
│ └── favicon.ico
├── gemfiles
├── rails_4_2.gemfile
├── rails_5_0.gemfile
├── rails_5_1.gemfile
├── rails_5_2.gemfile
├── rails_6_0.gemfile
├── rails_6_1.gemfile
├── rails_7_0_dartsass.gemfile
└── rails_7_0_sassc.gemfile
├── rails_test.rb
├── support
├── dummy_rails_integration.rb
└── reporting.rb
├── test_helper.rb
└── test_helper_rails.rb
/.gitattributes:
--------------------------------------------------------------------------------
1 | .* text eol=lf
2 | Gemfile text eol=lf
3 | LICENSE text eol=lf
4 | Rakefile text eol=lf
5 | *.gemfile text eol=lf
6 | *.gemspec text eol=lf
7 | *.html.erb text eol=lf
8 | *.html.slim text eol=lf
9 | *.js text eol=lf
10 | *.rb text eol=lf
11 | *.ru text eol=lf
12 | *.sass text eol=lf
13 | *.scss text eol=lf
14 | *.yml text eol=lf
15 |
--------------------------------------------------------------------------------
/.github/workflows/ci.yml:
--------------------------------------------------------------------------------
1 | name: CI
2 |
3 | on:
4 | - push
5 | - pull_request
6 | - workflow_dispatch
7 |
8 | jobs:
9 | test:
10 | env:
11 | BUNDLE_GEMFILE: ${{ matrix.gemfile }}
12 | strategy:
13 | fail-fast: false
14 | matrix:
15 | ruby_version: ['2.5', '2.6', '2.7', '3.0', '3.1']
16 | gemfile:
17 | - test/gemfiles/rails_5_0.gemfile
18 | - test/gemfiles/rails_5_1.gemfile
19 | - test/gemfiles/rails_5_2.gemfile
20 | - test/gemfiles/rails_6_0.gemfile
21 | - test/gemfiles/rails_6_1.gemfile
22 | - test/gemfiles/rails_7_0_sassc.gemfile
23 | - test/gemfiles/rails_7_0_dartsass.gemfile
24 | include:
25 | - ruby_version: '2.5'
26 | gemfile: test/gemfiles/rails_4_2.gemfile
27 | - ruby_version: '2.6'
28 | gemfile: test/gemfiles/rails_4_2.gemfile
29 | exclude:
30 | - ruby_version: '2.5'
31 | gemfile: test/gemfiles/rails_7_0_sassc.gemfile
32 | - ruby_version: '2.5'
33 | gemfile: test/gemfiles/rails_7_0_dartsass.gemfile
34 | - ruby_version: '2.6'
35 | gemfile: test/gemfiles/rails_7_0_sassc.gemfile
36 | - ruby_version: '2.6'
37 | gemfile: test/gemfiles/rails_7_0_dartsass.gemfile
38 | - ruby_version: '3.0'
39 | gemfile: test/gemfiles/rails_5_0.gemfile
40 | - ruby_version: '3.0'
41 | gemfile: test/gemfiles/rails_5_1.gemfile
42 | - ruby_version: '3.0'
43 | gemfile: test/gemfiles/rails_5_2.gemfile
44 | - ruby_version: '3.1'
45 | gemfile: test/gemfiles/rails_5_0.gemfile
46 | - ruby_version: '3.1'
47 | gemfile: test/gemfiles/rails_5_1.gemfile
48 | - ruby_version: '3.1'
49 | gemfile: test/gemfiles/rails_5_2.gemfile
50 | - ruby_version: '3.1'
51 | gemfile: test/gemfiles/rails_6_0.gemfile
52 | runs-on: ubuntu-latest
53 | steps:
54 | - uses: actions/checkout@v3
55 | - name: Set up Ruby
56 | uses: ruby/setup-ruby@v1
57 | with:
58 | ruby-version: ${{ matrix.ruby_version }}
59 | bundler-cache: true # 'bundle install' and cache
60 | - name: Build and test with Rake
61 | run: bundle exec rake --trace
62 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | *.gem
2 | .sass-cache
3 | bootstrap.css
4 | bootstrap-responsive.css
5 | Gemfile.lock
6 | *.gemfile.lock
7 | .rvmrc
8 | .rbenv-version
9 |
10 | # Ignore bundler config
11 | /.bundle
12 | /vendor/cache
13 | /vendor/bundle
14 | tmp/
15 | test/screenshots/
16 | test/dummy_rails/log/*.log
17 | test/dummy_rails/public/assets/
18 | .DS_Store
19 | node_modules
20 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Changelog
2 |
3 | The changelog is tracked here but also in [the Releases section of the GitHub project](https://github.com/twbs/bootstrap-rubygem/releases).
4 | The changelog only includes changes specific to the RubyGem.
5 |
6 | The Bootstrap framework changes can be found in [the Releases section of twbs/bootstrap](https://github.com/twbs/bootstrap/releases).
7 | Release announcement posts on [the official Bootstrap blog](http://blog.getbootstrap.com) contain summaries of the most noteworthy changes made in each release of Bootstrap.
8 |
9 | # 5.3.4
10 |
11 | * Autoprefixer is now optional.
12 | [#283](https://github.com/twbs/bootstrap-rubygem/pull/283)
13 |
14 | # 5.3.3
15 |
16 | * Adds support for other Sass engines: dartsass-sprockets, dartsass-rails, and cssbundling-rails.
17 |
18 | # 4.2.1
19 |
20 | * Bootstrap rubygem now depends on SassC instead of Sass.
21 |
22 | # 4.0.0.beta2.1
23 |
24 | Fixes an extraneous `sourceMappingURL` in `bootstrap.js`.
25 | [#124](https://github.com/twbs/bootstrap-rubygem/issues/124)
26 |
27 | # 4.0.0.beta2
28 |
29 | Compass is no longer supported. Minimum required Sass version is now v3.5.2.
30 | [#122](https://github.com/twbs/bootstrap-rubygem/pull/122)
31 |
32 | # 4.0.0.alpha3.1
33 |
34 | This release corresponds to the upstream Bootstrap 4 Alpha 3.
35 |
--------------------------------------------------------------------------------
/Gemfile:
--------------------------------------------------------------------------------
1 | source 'https://rubygems.org'
2 |
3 | gemspec
4 |
5 | group :development do
6 | gem 'popper_js', '>= 1.12.3'
7 | gem 'dartsass-sprockets'
8 | end
9 |
10 | group :debug do
11 | gem 'byebug', platforms: [:mri], require: false
12 | end
13 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2016 Twitter, Inc
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in
13 | all copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 | THE SOFTWARE.
22 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | require 'bundler/gem_tasks'
2 | require 'bundler/setup'
3 |
4 | lib_path = File.join(File.dirname(__FILE__), 'lib')
5 | $:.unshift(lib_path) unless $:.include?(lib_path)
6 |
7 | require 'rake/testtask'
8 | Rake::TestTask.new do |t|
9 | t.libs << 'test'
10 | t.test_files = FileList['test/**/*_test.rb']
11 | t.verbose = false
12 | t.warning = false
13 | end
14 |
15 | desc 'Test all Gemfiles from test/*.gemfile'
16 | task :test_all_gemfiles do
17 | require 'term/ansicolor'
18 | require 'pty'
19 | require 'shellwords'
20 | cmd = 'bundle install --quiet && bundle exec rake --trace'
21 | statuses = Dir.glob('./test/gemfiles/*{[!.lock]}').map do |gemfile|
22 | env = {'BUNDLE_GEMFILE' => gemfile}
23 | cmd_with_env = " (#{env.map { |k, v| "export #{k}=#{Shellwords.escape v}" } * ' '}; #{cmd})"
24 | $stderr.puts Term::ANSIColor.cyan("Testing\n#{cmd_with_env}")
25 | Bundler.with_clean_env do
26 | PTY.spawn(env, cmd) do |r, _w, pid|
27 | begin
28 | r.each_line { |l| puts l }
29 | rescue Errno::EIO
30 | # Errno:EIO error means that the process has finished giving output.
31 | ensure
32 | ::Process.wait pid
33 | end
34 | end
35 | end
36 | [$? && $?.exitstatus == 0, cmd_with_env]
37 | end
38 | failed_cmds = statuses.reject(&:first).map { |(_status, cmd_with_env)| cmd_with_env }
39 | if failed_cmds.empty?
40 | $stderr.puts Term::ANSIColor.green('Tests pass with all gemfiles')
41 | else
42 | $stderr.puts Term::ANSIColor.red("Failing (#{failed_cmds.size} / #{statuses.size})\n#{failed_cmds * "\n"}")
43 | exit 1
44 | end
45 | end
46 |
47 | desc 'Dumps output to a CSS file for testing'
48 | task :debug do
49 | begin
50 | require 'sass-embedded'
51 | rescue LoadError
52 | begin
53 | require 'sassc'
54 | rescue LoadError
55 | raise LoadError.new("bootstrap-rubygem requires a Sass engine. Please add dartsass-sprockets or sassc-rails to your dependencies.")
56 | end
57 | end
58 | require './lib/bootstrap'
59 | require 'term/ansicolor'
60 | path = Bootstrap.stylesheets_path
61 | %w(_bootstrap _bootstrap-reboot _bootstrap-grid).each do |file|
62 | filename = "#{path}/#{file}.scss"
63 | css = if defined?(SassC::Engine)
64 | SassC::Engine.new(File.read(filename), filename: filename, syntax: :scss).render
65 | else
66 | Sass.compile(filename).css
67 | end
68 | out = File.join('tmp', "#{file[1..-1]}.css")
69 | File.write(out, css)
70 | $stderr.puts Term::ANSIColor.green "Compiled #{out}"
71 | end
72 | end
73 |
74 | desc 'Update bootstrap from upstream'
75 | task :update, :branch do |t, args|
76 | require './tasks/updater'
77 | Updater.new(branch: args[:branch]).update_bootstrap
78 | end
79 |
80 | desc 'Start a dummy Rails app server'
81 | task :rails_server do
82 | require 'rack'
83 | require 'term/ansicolor'
84 | port = ENV['PORT'] || 9292
85 | puts %Q(Starting on #{Term::ANSIColor.cyan "http://localhost:#{port}"})
86 | Rack::Server.start(
87 | config: 'test/dummy_rails/config.ru',
88 | Port: port)
89 | end
90 |
91 | task default: :test
92 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap-global-this-define.js:
--------------------------------------------------------------------------------
1 | // Set a `globalThis` so that bootstrap components are defined on window.bootstrap instead of window.
2 | window['bootstrap'] = {
3 | "@popperjs/core": window.Popper,
4 | _originalGlobalThis: window['globalThis']
5 | };
6 | window['globalThis'] = window['bootstrap'];
7 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap-global-this-undefine.js:
--------------------------------------------------------------------------------
1 | window['globalThis'] = window['bootstrap']._originalGlobalThis;
2 | window['bootstrap']._originalGlobalThis = null;
3 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap-sprockets.js:
--------------------------------------------------------------------------------
1 | //= require ./bootstrap-global-this-define
2 | //= require ./bootstrap/dom/data
3 | //= require ./bootstrap/util/index
4 | //= require ./bootstrap/dom/event-handler
5 | //= require ./bootstrap/dom/manipulator
6 | //= require ./bootstrap/util/config
7 | //= require ./bootstrap/base-component
8 | //= require ./bootstrap/button
9 | //= require ./bootstrap/dom/selector-engine
10 | //= require ./bootstrap/scrollspy
11 | //= require ./bootstrap/util/scrollbar
12 | //= require ./bootstrap/util/sanitizer
13 | //= require ./bootstrap/util/swipe
14 | //= require ./bootstrap/carousel
15 | //= require ./bootstrap/collapse
16 | //= require ./bootstrap/util/backdrop
17 | //= require ./bootstrap/util/component-functions
18 | //= require ./bootstrap/util/focustrap
19 | //= require ./bootstrap/modal
20 | //= require ./bootstrap/alert
21 | //= require ./bootstrap/util/template-factory
22 | //= require ./bootstrap/tooltip
23 | //= require ./bootstrap/popover
24 | //= require ./bootstrap/offcanvas
25 | //= require ./bootstrap/toast
26 | //= require ./bootstrap/dropdown
27 | //= require ./bootstrap/tab
28 | //= require ./bootstrap-global-this-undefine
29 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/alert.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap alert.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/component-functions.js'), require('./util/index.js')) :
8 | typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/component-functions', './util/index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Alert = factory(global.BaseComponent, global.EventHandler, global.ComponentFunctions, global.Index));
10 | })(this, (function (BaseComponent, EventHandler, componentFunctions_js, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap alert.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'alert';
25 | const DATA_KEY = 'bs.alert';
26 | const EVENT_KEY = `.${DATA_KEY}`;
27 | const EVENT_CLOSE = `close${EVENT_KEY}`;
28 | const EVENT_CLOSED = `closed${EVENT_KEY}`;
29 | const CLASS_NAME_FADE = 'fade';
30 | const CLASS_NAME_SHOW = 'show';
31 |
32 | /**
33 | * Class definition
34 | */
35 |
36 | class Alert extends BaseComponent {
37 | // Getters
38 | static get NAME() {
39 | return NAME;
40 | }
41 |
42 | // Public
43 | close() {
44 | const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE);
45 | if (closeEvent.defaultPrevented) {
46 | return;
47 | }
48 | this._element.classList.remove(CLASS_NAME_SHOW);
49 | const isAnimated = this._element.classList.contains(CLASS_NAME_FADE);
50 | this._queueCallback(() => this._destroyElement(), this._element, isAnimated);
51 | }
52 |
53 | // Private
54 | _destroyElement() {
55 | this._element.remove();
56 | EventHandler.trigger(this._element, EVENT_CLOSED);
57 | this.dispose();
58 | }
59 |
60 | // Static
61 | static jQueryInterface(config) {
62 | return this.each(function () {
63 | const data = Alert.getOrCreateInstance(this);
64 | if (typeof config !== 'string') {
65 | return;
66 | }
67 | if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
68 | throw new TypeError(`No method named "${config}"`);
69 | }
70 | data[config](this);
71 | });
72 | }
73 | }
74 |
75 | /**
76 | * Data API implementation
77 | */
78 |
79 | componentFunctions_js.enableDismissTrigger(Alert, 'close');
80 |
81 | /**
82 | * jQuery
83 | */
84 |
85 | index_js.defineJQueryPlugin(Alert);
86 |
87 | return Alert;
88 |
89 | }));
90 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/base-component.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap base-component.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./dom/data.js'), require('./dom/event-handler.js'), require('./util/config.js'), require('./util/index.js')) :
8 | typeof define === 'function' && define.amd ? define(['./dom/data', './dom/event-handler', './util/config', './util/index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.BaseComponent = factory(global.Data, global.EventHandler, global.Config, global.Index));
10 | })(this, (function (Data, EventHandler, Config, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap base-component.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const VERSION = '5.3.5';
25 |
26 | /**
27 | * Class definition
28 | */
29 |
30 | class BaseComponent extends Config {
31 | constructor(element, config) {
32 | super();
33 | element = index_js.getElement(element);
34 | if (!element) {
35 | return;
36 | }
37 | this._element = element;
38 | this._config = this._getConfig(config);
39 | Data.set(this._element, this.constructor.DATA_KEY, this);
40 | }
41 |
42 | // Public
43 | dispose() {
44 | Data.remove(this._element, this.constructor.DATA_KEY);
45 | EventHandler.off(this._element, this.constructor.EVENT_KEY);
46 | for (const propertyName of Object.getOwnPropertyNames(this)) {
47 | this[propertyName] = null;
48 | }
49 | }
50 | _queueCallback(callback, element, isAnimated = true) {
51 | index_js.executeAfterTransition(callback, element, isAnimated);
52 | }
53 | _getConfig(config) {
54 | config = this._mergeConfigObj(config, this._element);
55 | config = this._configAfterMerge(config);
56 | this._typeCheckConfig(config);
57 | return config;
58 | }
59 |
60 | // Static
61 | static getInstance(element) {
62 | return Data.get(index_js.getElement(element), this.DATA_KEY);
63 | }
64 | static getOrCreateInstance(element, config = {}) {
65 | return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null);
66 | }
67 | static get VERSION() {
68 | return VERSION;
69 | }
70 | static get DATA_KEY() {
71 | return `bs.${this.NAME}`;
72 | }
73 | static get EVENT_KEY() {
74 | return `.${this.DATA_KEY}`;
75 | }
76 | static eventName(name) {
77 | return `${name}${this.EVENT_KEY}`;
78 | }
79 | }
80 |
81 | return BaseComponent;
82 |
83 | }));
84 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/button.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap button.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./base-component.js'), require('./dom/event-handler.js'), require('./util/index.js')) :
8 | typeof define === 'function' && define.amd ? define(['./base-component', './dom/event-handler', './util/index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Button = factory(global.BaseComponent, global.EventHandler, global.Index));
10 | })(this, (function (BaseComponent, EventHandler, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap button.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'button';
25 | const DATA_KEY = 'bs.button';
26 | const EVENT_KEY = `.${DATA_KEY}`;
27 | const DATA_API_KEY = '.data-api';
28 | const CLASS_NAME_ACTIVE = 'active';
29 | const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="button"]';
30 | const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`;
31 |
32 | /**
33 | * Class definition
34 | */
35 |
36 | class Button extends BaseComponent {
37 | // Getters
38 | static get NAME() {
39 | return NAME;
40 | }
41 |
42 | // Public
43 | toggle() {
44 | // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
45 | this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE));
46 | }
47 |
48 | // Static
49 | static jQueryInterface(config) {
50 | return this.each(function () {
51 | const data = Button.getOrCreateInstance(this);
52 | if (config === 'toggle') {
53 | data[config]();
54 | }
55 | });
56 | }
57 | }
58 |
59 | /**
60 | * Data API implementation
61 | */
62 |
63 | EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
64 | event.preventDefault();
65 | const button = event.target.closest(SELECTOR_DATA_TOGGLE);
66 | const data = Button.getOrCreateInstance(button);
67 | data.toggle();
68 | });
69 |
70 | /**
71 | * jQuery
72 | */
73 |
74 | index_js.defineJQueryPlugin(Button);
75 |
76 | return Button;
77 |
78 | }));
79 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/dom/data.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap data.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/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 = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Data = factory());
10 | })(this, (function () { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap dom/data.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 | /**
20 | * Constants
21 | */
22 |
23 | const elementMap = new Map();
24 | const data = {
25 | set(element, key, instance) {
26 | if (!elementMap.has(element)) {
27 | elementMap.set(element, new Map());
28 | }
29 | const instanceMap = elementMap.get(element);
30 |
31 | // make it clear we only want one instance per element
32 | // can be removed later when multiple key/instances are fine to be used
33 | if (!instanceMap.has(key) && instanceMap.size !== 0) {
34 | // eslint-disable-next-line no-console
35 | console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`);
36 | return;
37 | }
38 | instanceMap.set(key, instance);
39 | },
40 | get(element, key) {
41 | if (elementMap.has(element)) {
42 | return elementMap.get(element).get(key) || null;
43 | }
44 | return null;
45 | },
46 | remove(element, key) {
47 | if (!elementMap.has(element)) {
48 | return;
49 | }
50 | const instanceMap = elementMap.get(element);
51 | instanceMap.delete(key);
52 |
53 | // free up element references if there are no instances left for an element
54 | if (instanceMap.size === 0) {
55 | elementMap.delete(element);
56 | }
57 | }
58 | };
59 |
60 | return data;
61 |
62 | }));
63 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/dom/manipulator.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap manipulator.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/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 = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Manipulator = factory());
10 | })(this, (function () { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap dom/manipulator.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 | function normalizeData(value) {
20 | if (value === 'true') {
21 | return true;
22 | }
23 | if (value === 'false') {
24 | return false;
25 | }
26 | if (value === Number(value).toString()) {
27 | return Number(value);
28 | }
29 | if (value === '' || value === 'null') {
30 | return null;
31 | }
32 | if (typeof value !== 'string') {
33 | return value;
34 | }
35 | try {
36 | return JSON.parse(decodeURIComponent(value));
37 | } catch (_unused) {
38 | return value;
39 | }
40 | }
41 | function normalizeDataKey(key) {
42 | return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`);
43 | }
44 | const Manipulator = {
45 | setDataAttribute(element, key, value) {
46 | element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value);
47 | },
48 | removeDataAttribute(element, key) {
49 | element.removeAttribute(`data-bs-${normalizeDataKey(key)}`);
50 | },
51 | getDataAttributes(element) {
52 | if (!element) {
53 | return {};
54 | }
55 | const attributes = {};
56 | const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'));
57 | for (const key of bsKeys) {
58 | let pureKey = key.replace(/^bs/, '');
59 | pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1);
60 | attributes[pureKey] = normalizeData(element.dataset[key]);
61 | }
62 | return attributes;
63 | },
64 | getDataAttribute(element, key) {
65 | return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`));
66 | }
67 | };
68 |
69 | return Manipulator;
70 |
71 | }));
72 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/dom/selector-engine.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap selector-engine.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../util/index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../util/index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.SelectorEngine = factory(global.Index));
10 | })(this, (function (index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap dom/selector-engine.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 | const getSelector = element => {
20 | let selector = element.getAttribute('data-bs-target');
21 | if (!selector || selector === '#') {
22 | let hrefAttribute = element.getAttribute('href');
23 |
24 | // The only valid content that could double as a selector are IDs or classes,
25 | // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
26 | // `document.querySelector` will rightfully complain it is invalid.
27 | // See https://github.com/twbs/bootstrap/issues/32273
28 | if (!hrefAttribute || !hrefAttribute.includes('#') && !hrefAttribute.startsWith('.')) {
29 | return null;
30 | }
31 |
32 | // Just in case some CMS puts out a full URL with the anchor appended
33 | if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
34 | hrefAttribute = `#${hrefAttribute.split('#')[1]}`;
35 | }
36 | selector = hrefAttribute && hrefAttribute !== '#' ? hrefAttribute.trim() : null;
37 | }
38 | return selector ? selector.split(',').map(sel => index_js.parseSelector(sel)).join(',') : null;
39 | };
40 | const SelectorEngine = {
41 | find(selector, element = document.documentElement) {
42 | return [].concat(...Element.prototype.querySelectorAll.call(element, selector));
43 | },
44 | findOne(selector, element = document.documentElement) {
45 | return Element.prototype.querySelector.call(element, selector);
46 | },
47 | children(element, selector) {
48 | return [].concat(...element.children).filter(child => child.matches(selector));
49 | },
50 | parents(element, selector) {
51 | const parents = [];
52 | let ancestor = element.parentNode.closest(selector);
53 | while (ancestor) {
54 | parents.push(ancestor);
55 | ancestor = ancestor.parentNode.closest(selector);
56 | }
57 | return parents;
58 | },
59 | prev(element, selector) {
60 | let previous = element.previousElementSibling;
61 | while (previous) {
62 | if (previous.matches(selector)) {
63 | return [previous];
64 | }
65 | previous = previous.previousElementSibling;
66 | }
67 | return [];
68 | },
69 | // TODO: this is now unused; remove later along with prev()
70 | next(element, selector) {
71 | let next = element.nextElementSibling;
72 | while (next) {
73 | if (next.matches(selector)) {
74 | return [next];
75 | }
76 | next = next.nextElementSibling;
77 | }
78 | return [];
79 | },
80 | focusableChildren(element) {
81 | const focusables = ['a', 'button', 'input', 'textarea', 'select', 'details', '[tabindex]', '[contenteditable="true"]'].map(selector => `${selector}:not([tabindex^="-"])`).join(',');
82 | return this.find(focusables, element).filter(el => !index_js.isDisabled(el) && index_js.isVisible(el));
83 | },
84 | getSelectorFromElement(element) {
85 | const selector = getSelector(element);
86 | if (selector) {
87 | return SelectorEngine.findOne(selector) ? selector : null;
88 | }
89 | return null;
90 | },
91 | getElementFromSelector(element) {
92 | const selector = getSelector(element);
93 | return selector ? SelectorEngine.findOne(selector) : null;
94 | },
95 | getMultipleElementsFromSelector(element) {
96 | const selector = getSelector(element);
97 | return selector ? SelectorEngine.find(selector) : [];
98 | }
99 | };
100 |
101 | return SelectorEngine;
102 |
103 | }));
104 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/popover.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap popover.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('./tooltip.js'), require('./util/index.js')) :
8 | typeof define === 'function' && define.amd ? define(['./tooltip', './util/index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Popover = factory(global.Tooltip, global.Index));
10 | })(this, (function (Tooltip, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap popover.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'popover';
25 | const SELECTOR_TITLE = '.popover-header';
26 | const SELECTOR_CONTENT = '.popover-body';
27 | const Default = {
28 | ...Tooltip.Default,
29 | content: '',
30 | offset: [0, 8],
31 | placement: 'right',
32 | template: '
',
33 | trigger: 'click'
34 | };
35 | const DefaultType = {
36 | ...Tooltip.DefaultType,
37 | content: '(null|string|element|function)'
38 | };
39 |
40 | /**
41 | * Class definition
42 | */
43 |
44 | class Popover extends Tooltip {
45 | // Getters
46 | static get Default() {
47 | return Default;
48 | }
49 | static get DefaultType() {
50 | return DefaultType;
51 | }
52 | static get NAME() {
53 | return NAME;
54 | }
55 |
56 | // Overrides
57 | _isWithContent() {
58 | return this._getTitle() || this._getContent();
59 | }
60 |
61 | // Private
62 | _getContentForTemplate() {
63 | return {
64 | [SELECTOR_TITLE]: this._getTitle(),
65 | [SELECTOR_CONTENT]: this._getContent()
66 | };
67 | }
68 | _getContent() {
69 | return this._resolvePossibleFunction(this._config.content);
70 | }
71 |
72 | // Static
73 | static jQueryInterface(config) {
74 | return this.each(function () {
75 | const data = Popover.getOrCreateInstance(this, config);
76 | if (typeof config !== 'string') {
77 | return;
78 | }
79 | if (typeof data[config] === 'undefined') {
80 | throw new TypeError(`No method named "${config}"`);
81 | }
82 | data[config]();
83 | });
84 | }
85 | }
86 |
87 | /**
88 | * jQuery
89 | */
90 |
91 | index_js.defineJQueryPlugin(Popover);
92 |
93 | return Popover;
94 |
95 | }));
96 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/backdrop.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap backdrop.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('./config.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/event-handler', './config', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Backdrop = factory(global.EventHandler, global.Config, global.Index));
10 | })(this, (function (EventHandler, Config, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/backdrop.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'backdrop';
25 | const CLASS_NAME_FADE = 'fade';
26 | const CLASS_NAME_SHOW = 'show';
27 | const EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`;
28 | const Default = {
29 | className: 'modal-backdrop',
30 | clickCallback: null,
31 | isAnimated: false,
32 | isVisible: true,
33 | // if false, we use the backdrop helper without adding any element to the dom
34 | rootElement: 'body' // give the choice to place backdrop under different elements
35 | };
36 | const DefaultType = {
37 | className: 'string',
38 | clickCallback: '(function|null)',
39 | isAnimated: 'boolean',
40 | isVisible: 'boolean',
41 | rootElement: '(element|string)'
42 | };
43 |
44 | /**
45 | * Class definition
46 | */
47 |
48 | class Backdrop extends Config {
49 | constructor(config) {
50 | super();
51 | this._config = this._getConfig(config);
52 | this._isAppended = false;
53 | this._element = null;
54 | }
55 |
56 | // Getters
57 | static get Default() {
58 | return Default;
59 | }
60 | static get DefaultType() {
61 | return DefaultType;
62 | }
63 | static get NAME() {
64 | return NAME;
65 | }
66 |
67 | // Public
68 | show(callback) {
69 | if (!this._config.isVisible) {
70 | index_js.execute(callback);
71 | return;
72 | }
73 | this._append();
74 | const element = this._getElement();
75 | if (this._config.isAnimated) {
76 | index_js.reflow(element);
77 | }
78 | element.classList.add(CLASS_NAME_SHOW);
79 | this._emulateAnimation(() => {
80 | index_js.execute(callback);
81 | });
82 | }
83 | hide(callback) {
84 | if (!this._config.isVisible) {
85 | index_js.execute(callback);
86 | return;
87 | }
88 | this._getElement().classList.remove(CLASS_NAME_SHOW);
89 | this._emulateAnimation(() => {
90 | this.dispose();
91 | index_js.execute(callback);
92 | });
93 | }
94 | dispose() {
95 | if (!this._isAppended) {
96 | return;
97 | }
98 | EventHandler.off(this._element, EVENT_MOUSEDOWN);
99 | this._element.remove();
100 | this._isAppended = false;
101 | }
102 |
103 | // Private
104 | _getElement() {
105 | if (!this._element) {
106 | const backdrop = document.createElement('div');
107 | backdrop.className = this._config.className;
108 | if (this._config.isAnimated) {
109 | backdrop.classList.add(CLASS_NAME_FADE);
110 | }
111 | this._element = backdrop;
112 | }
113 | return this._element;
114 | }
115 | _configAfterMerge(config) {
116 | // use getElement() with the default "body" to get a fresh Element on each instantiation
117 | config.rootElement = index_js.getElement(config.rootElement);
118 | return config;
119 | }
120 | _append() {
121 | if (this._isAppended) {
122 | return;
123 | }
124 | const element = this._getElement();
125 | this._config.rootElement.append(element);
126 | EventHandler.on(element, EVENT_MOUSEDOWN, () => {
127 | index_js.execute(this._config.clickCallback);
128 | });
129 | this._isAppended = true;
130 | }
131 | _emulateAnimation(callback) {
132 | index_js.executeAfterTransition(callback, this._getElement(), this._config.isAnimated);
133 | }
134 | }
135 |
136 | return Backdrop;
137 |
138 | }));
139 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/component-functions.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap component-functions.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('../dom/event-handler.js'), require('../dom/selector-engine.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['exports', '../dom/event-handler', '../dom/selector-engine', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.ComponentFunctions = {}, global.EventHandler, global.SelectorEngine, global.Index));
10 | })(this, (function (exports, EventHandler, SelectorEngine, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/component-functions.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 | const enableDismissTrigger = (component, method = 'hide') => {
20 | const clickEvent = `click.dismiss${component.EVENT_KEY}`;
21 | const name = component.NAME;
22 | EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
23 | if (['A', 'AREA'].includes(this.tagName)) {
24 | event.preventDefault();
25 | }
26 | if (index_js.isDisabled(this)) {
27 | return;
28 | }
29 | const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`);
30 | const instance = component.getOrCreateInstance(target);
31 |
32 | // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
33 | instance[method]();
34 | });
35 | };
36 |
37 | exports.enableDismissTrigger = enableDismissTrigger;
38 |
39 | Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
40 |
41 | }));
42 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/config.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap config.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/manipulator.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/manipulator', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Config = factory(global.Manipulator, global.Index));
10 | })(this, (function (Manipulator, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/config.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Class definition
22 | */
23 |
24 | class Config {
25 | // Getters
26 | static get Default() {
27 | return {};
28 | }
29 | static get DefaultType() {
30 | return {};
31 | }
32 | static get NAME() {
33 | throw new Error('You have to implement the static method "NAME", for each component!');
34 | }
35 | _getConfig(config) {
36 | config = this._mergeConfigObj(config);
37 | config = this._configAfterMerge(config);
38 | this._typeCheckConfig(config);
39 | return config;
40 | }
41 | _configAfterMerge(config) {
42 | return config;
43 | }
44 | _mergeConfigObj(config, element) {
45 | const jsonConfig = index_js.isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {}; // try to parse
46 |
47 | return {
48 | ...this.constructor.Default,
49 | ...(typeof jsonConfig === 'object' ? jsonConfig : {}),
50 | ...(index_js.isElement(element) ? Manipulator.getDataAttributes(element) : {}),
51 | ...(typeof config === 'object' ? config : {})
52 | };
53 | }
54 | _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
55 | for (const [property, expectedTypes] of Object.entries(configTypes)) {
56 | const value = config[property];
57 | const valueType = index_js.isElement(value) ? 'element' : index_js.toType(value);
58 | if (!new RegExp(expectedTypes).test(valueType)) {
59 | throw new TypeError(`${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`);
60 | }
61 | }
62 | }
63 | }
64 |
65 | return Config;
66 |
67 | }));
68 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/focustrap.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap focustrap.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('../dom/selector-engine.js'), require('./config.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/event-handler', '../dom/selector-engine', './config'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Focustrap = factory(global.EventHandler, global.SelectorEngine, global.Config));
10 | })(this, (function (EventHandler, SelectorEngine, Config) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/focustrap.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'focustrap';
25 | const DATA_KEY = 'bs.focustrap';
26 | const EVENT_KEY = `.${DATA_KEY}`;
27 | const EVENT_FOCUSIN = `focusin${EVENT_KEY}`;
28 | const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`;
29 | const TAB_KEY = 'Tab';
30 | const TAB_NAV_FORWARD = 'forward';
31 | const TAB_NAV_BACKWARD = 'backward';
32 | const Default = {
33 | autofocus: true,
34 | trapElement: null // The element to trap focus inside of
35 | };
36 | const DefaultType = {
37 | autofocus: 'boolean',
38 | trapElement: 'element'
39 | };
40 |
41 | /**
42 | * Class definition
43 | */
44 |
45 | class FocusTrap extends Config {
46 | constructor(config) {
47 | super();
48 | this._config = this._getConfig(config);
49 | this._isActive = false;
50 | this._lastTabNavDirection = null;
51 | }
52 |
53 | // Getters
54 | static get Default() {
55 | return Default;
56 | }
57 | static get DefaultType() {
58 | return DefaultType;
59 | }
60 | static get NAME() {
61 | return NAME;
62 | }
63 |
64 | // Public
65 | activate() {
66 | if (this._isActive) {
67 | return;
68 | }
69 | if (this._config.autofocus) {
70 | this._config.trapElement.focus();
71 | }
72 | EventHandler.off(document, EVENT_KEY); // guard against infinite focus loop
73 | EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event));
74 | EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event));
75 | this._isActive = true;
76 | }
77 | deactivate() {
78 | if (!this._isActive) {
79 | return;
80 | }
81 | this._isActive = false;
82 | EventHandler.off(document, EVENT_KEY);
83 | }
84 |
85 | // Private
86 | _handleFocusin(event) {
87 | const {
88 | trapElement
89 | } = this._config;
90 | if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
91 | return;
92 | }
93 | const elements = SelectorEngine.focusableChildren(trapElement);
94 | if (elements.length === 0) {
95 | trapElement.focus();
96 | } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
97 | elements[elements.length - 1].focus();
98 | } else {
99 | elements[0].focus();
100 | }
101 | }
102 | _handleKeydown(event) {
103 | if (event.key !== TAB_KEY) {
104 | return;
105 | }
106 | this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD;
107 | }
108 | }
109 |
110 | return FocusTrap;
111 |
112 | }));
113 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/sanitizer.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap sanitizer.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
8 | typeof define === 'function' && define.amd ? define(['exports'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.Sanitizer = {}));
10 | })(this, (function (exports) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/sanitizer.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 | // js-docs-start allow-list
20 | const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i;
21 | const DefaultAllowlist = {
22 | // Global attributes allowed on any supplied element below.
23 | '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
24 | a: ['target', 'href', 'title', 'rel'],
25 | area: [],
26 | b: [],
27 | br: [],
28 | col: [],
29 | code: [],
30 | dd: [],
31 | div: [],
32 | dl: [],
33 | dt: [],
34 | em: [],
35 | hr: [],
36 | h1: [],
37 | h2: [],
38 | h3: [],
39 | h4: [],
40 | h5: [],
41 | h6: [],
42 | i: [],
43 | img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
44 | li: [],
45 | ol: [],
46 | p: [],
47 | pre: [],
48 | s: [],
49 | small: [],
50 | span: [],
51 | sub: [],
52 | sup: [],
53 | strong: [],
54 | u: [],
55 | ul: []
56 | };
57 | // js-docs-end allow-list
58 |
59 | const uriAttributes = new Set(['background', 'cite', 'href', 'itemtype', 'longdesc', 'poster', 'src', 'xlink:href']);
60 |
61 | /**
62 | * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
63 | * contexts.
64 | *
65 | * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
66 | */
67 | // eslint-disable-next-line unicorn/better-regex
68 | const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i;
69 | const allowedAttribute = (attribute, allowedAttributeList) => {
70 | const attributeName = attribute.nodeName.toLowerCase();
71 | if (allowedAttributeList.includes(attributeName)) {
72 | if (uriAttributes.has(attributeName)) {
73 | return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue));
74 | }
75 | return true;
76 | }
77 |
78 | // Check if a regular expression validates the attribute.
79 | return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp).some(regex => regex.test(attributeName));
80 | };
81 | function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
82 | if (!unsafeHtml.length) {
83 | return unsafeHtml;
84 | }
85 | if (sanitizeFunction && typeof sanitizeFunction === 'function') {
86 | return sanitizeFunction(unsafeHtml);
87 | }
88 | const domParser = new window.DOMParser();
89 | const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html');
90 | const elements = [].concat(...createdDocument.body.querySelectorAll('*'));
91 | for (const element of elements) {
92 | const elementName = element.nodeName.toLowerCase();
93 | if (!Object.keys(allowList).includes(elementName)) {
94 | element.remove();
95 | continue;
96 | }
97 | const attributeList = [].concat(...element.attributes);
98 | const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || []);
99 | for (const attribute of attributeList) {
100 | if (!allowedAttribute(attribute, allowedAttributes)) {
101 | element.removeAttribute(attribute.nodeName);
102 | }
103 | }
104 | }
105 | return createdDocument.body.innerHTML;
106 | }
107 |
108 | exports.DefaultAllowlist = DefaultAllowlist;
109 | exports.sanitizeHtml = sanitizeHtml;
110 |
111 | Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
112 |
113 | }));
114 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/scrollbar.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap scrollbar.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/manipulator.js'), require('../dom/selector-engine.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/manipulator', '../dom/selector-engine', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Scrollbar = factory(global.Manipulator, global.SelectorEngine, global.Index));
10 | })(this, (function (Manipulator, SelectorEngine, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/scrollBar.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top';
25 | const SELECTOR_STICKY_CONTENT = '.sticky-top';
26 | const PROPERTY_PADDING = 'padding-right';
27 | const PROPERTY_MARGIN = 'margin-right';
28 |
29 | /**
30 | * Class definition
31 | */
32 |
33 | class ScrollBarHelper {
34 | constructor() {
35 | this._element = document.body;
36 | }
37 |
38 | // Public
39 | getWidth() {
40 | // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
41 | const documentWidth = document.documentElement.clientWidth;
42 | return Math.abs(window.innerWidth - documentWidth);
43 | }
44 | hide() {
45 | const width = this.getWidth();
46 | this._disableOverFlow();
47 | // give padding to element to balance the hidden scrollbar width
48 | this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
49 | // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
50 | this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width);
51 | this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width);
52 | }
53 | reset() {
54 | this._resetElementAttributes(this._element, 'overflow');
55 | this._resetElementAttributes(this._element, PROPERTY_PADDING);
56 | this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING);
57 | this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN);
58 | }
59 | isOverflowing() {
60 | return this.getWidth() > 0;
61 | }
62 |
63 | // Private
64 | _disableOverFlow() {
65 | this._saveInitialAttribute(this._element, 'overflow');
66 | this._element.style.overflow = 'hidden';
67 | }
68 | _setElementAttributes(selector, styleProperty, callback) {
69 | const scrollbarWidth = this.getWidth();
70 | const manipulationCallBack = element => {
71 | if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
72 | return;
73 | }
74 | this._saveInitialAttribute(element, styleProperty);
75 | const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty);
76 | element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`);
77 | };
78 | this._applyManipulationCallback(selector, manipulationCallBack);
79 | }
80 | _saveInitialAttribute(element, styleProperty) {
81 | const actualValue = element.style.getPropertyValue(styleProperty);
82 | if (actualValue) {
83 | Manipulator.setDataAttribute(element, styleProperty, actualValue);
84 | }
85 | }
86 | _resetElementAttributes(selector, styleProperty) {
87 | const manipulationCallBack = element => {
88 | const value = Manipulator.getDataAttribute(element, styleProperty);
89 | // We only want to remove the property if the value is `null`; the value can also be zero
90 | if (value === null) {
91 | element.style.removeProperty(styleProperty);
92 | return;
93 | }
94 | Manipulator.removeDataAttribute(element, styleProperty);
95 | element.style.setProperty(styleProperty, value);
96 | };
97 | this._applyManipulationCallback(selector, manipulationCallBack);
98 | }
99 | _applyManipulationCallback(selector, callBack) {
100 | if (index_js.isElement(selector)) {
101 | callBack(selector);
102 | return;
103 | }
104 | for (const sel of SelectorEngine.find(selector, this._element)) {
105 | callBack(sel);
106 | }
107 | }
108 | }
109 |
110 | return ScrollBarHelper;
111 |
112 | }));
113 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/swipe.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap swipe.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/event-handler.js'), require('./config.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/event-handler', './config', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.Swipe = factory(global.EventHandler, global.Config, global.Index));
10 | })(this, (function (EventHandler, Config, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/swipe.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'swipe';
25 | const EVENT_KEY = '.bs.swipe';
26 | const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`;
27 | const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`;
28 | const EVENT_TOUCHEND = `touchend${EVENT_KEY}`;
29 | const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`;
30 | const EVENT_POINTERUP = `pointerup${EVENT_KEY}`;
31 | const POINTER_TYPE_TOUCH = 'touch';
32 | const POINTER_TYPE_PEN = 'pen';
33 | const CLASS_NAME_POINTER_EVENT = 'pointer-event';
34 | const SWIPE_THRESHOLD = 40;
35 | const Default = {
36 | endCallback: null,
37 | leftCallback: null,
38 | rightCallback: null
39 | };
40 | const DefaultType = {
41 | endCallback: '(function|null)',
42 | leftCallback: '(function|null)',
43 | rightCallback: '(function|null)'
44 | };
45 |
46 | /**
47 | * Class definition
48 | */
49 |
50 | class Swipe extends Config {
51 | constructor(element, config) {
52 | super();
53 | this._element = element;
54 | if (!element || !Swipe.isSupported()) {
55 | return;
56 | }
57 | this._config = this._getConfig(config);
58 | this._deltaX = 0;
59 | this._supportPointerEvents = Boolean(window.PointerEvent);
60 | this._initEvents();
61 | }
62 |
63 | // Getters
64 | static get Default() {
65 | return Default;
66 | }
67 | static get DefaultType() {
68 | return DefaultType;
69 | }
70 | static get NAME() {
71 | return NAME;
72 | }
73 |
74 | // Public
75 | dispose() {
76 | EventHandler.off(this._element, EVENT_KEY);
77 | }
78 |
79 | // Private
80 | _start(event) {
81 | if (!this._supportPointerEvents) {
82 | this._deltaX = event.touches[0].clientX;
83 | return;
84 | }
85 | if (this._eventIsPointerPenTouch(event)) {
86 | this._deltaX = event.clientX;
87 | }
88 | }
89 | _end(event) {
90 | if (this._eventIsPointerPenTouch(event)) {
91 | this._deltaX = event.clientX - this._deltaX;
92 | }
93 | this._handleSwipe();
94 | index_js.execute(this._config.endCallback);
95 | }
96 | _move(event) {
97 | this._deltaX = event.touches && event.touches.length > 1 ? 0 : event.touches[0].clientX - this._deltaX;
98 | }
99 | _handleSwipe() {
100 | const absDeltaX = Math.abs(this._deltaX);
101 | if (absDeltaX <= SWIPE_THRESHOLD) {
102 | return;
103 | }
104 | const direction = absDeltaX / this._deltaX;
105 | this._deltaX = 0;
106 | if (!direction) {
107 | return;
108 | }
109 | index_js.execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback);
110 | }
111 | _initEvents() {
112 | if (this._supportPointerEvents) {
113 | EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event));
114 | EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event));
115 | this._element.classList.add(CLASS_NAME_POINTER_EVENT);
116 | } else {
117 | EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event));
118 | EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event));
119 | EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event));
120 | }
121 | }
122 | _eventIsPointerPenTouch(event) {
123 | return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH);
124 | }
125 |
126 | // Static
127 | static isSupported() {
128 | return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0;
129 | }
130 | }
131 |
132 | return Swipe;
133 |
134 | }));
135 |
--------------------------------------------------------------------------------
/assets/javascripts/bootstrap/util/template-factory.js:
--------------------------------------------------------------------------------
1 | /*!
2 | * Bootstrap template-factory.js v5.3.5 (https://getbootstrap.com/)
3 | * Copyright 2011-2025 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
4 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
5 | */
6 | (function (global, factory) {
7 | typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(require('../dom/selector-engine.js'), require('./config.js'), require('./sanitizer.js'), require('./index.js')) :
8 | typeof define === 'function' && define.amd ? define(['../dom/selector-engine', './config', './sanitizer', './index'], factory) :
9 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, global.TemplateFactory = factory(global.SelectorEngine, global.Config, global.Sanitizer, global.Index));
10 | })(this, (function (SelectorEngine, Config, sanitizer_js, index_js) { 'use strict';
11 |
12 | /**
13 | * --------------------------------------------------------------------------
14 | * Bootstrap util/template-factory.js
15 | * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
16 | * --------------------------------------------------------------------------
17 | */
18 |
19 |
20 | /**
21 | * Constants
22 | */
23 |
24 | const NAME = 'TemplateFactory';
25 | const Default = {
26 | allowList: sanitizer_js.DefaultAllowlist,
27 | content: {},
28 | // { selector : text , selector2 : text2 , }
29 | extraClass: '',
30 | html: false,
31 | sanitize: true,
32 | sanitizeFn: null,
33 | template: ''
34 | };
35 | const DefaultType = {
36 | allowList: 'object',
37 | content: 'object',
38 | extraClass: '(string|function)',
39 | html: 'boolean',
40 | sanitize: 'boolean',
41 | sanitizeFn: '(null|function)',
42 | template: 'string'
43 | };
44 | const DefaultContentType = {
45 | entry: '(string|element|function|null)',
46 | selector: '(string|element)'
47 | };
48 |
49 | /**
50 | * Class definition
51 | */
52 |
53 | class TemplateFactory extends Config {
54 | constructor(config) {
55 | super();
56 | this._config = this._getConfig(config);
57 | }
58 |
59 | // Getters
60 | static get Default() {
61 | return Default;
62 | }
63 | static get DefaultType() {
64 | return DefaultType;
65 | }
66 | static get NAME() {
67 | return NAME;
68 | }
69 |
70 | // Public
71 | getContent() {
72 | return Object.values(this._config.content).map(config => this._resolvePossibleFunction(config)).filter(Boolean);
73 | }
74 | hasContent() {
75 | return this.getContent().length > 0;
76 | }
77 | changeContent(content) {
78 | this._checkContent(content);
79 | this._config.content = {
80 | ...this._config.content,
81 | ...content
82 | };
83 | return this;
84 | }
85 | toHtml() {
86 | const templateWrapper = document.createElement('div');
87 | templateWrapper.innerHTML = this._maybeSanitize(this._config.template);
88 | for (const [selector, text] of Object.entries(this._config.content)) {
89 | this._setContent(templateWrapper, text, selector);
90 | }
91 | const template = templateWrapper.children[0];
92 | const extraClass = this._resolvePossibleFunction(this._config.extraClass);
93 | if (extraClass) {
94 | template.classList.add(...extraClass.split(' '));
95 | }
96 | return template;
97 | }
98 |
99 | // Private
100 | _typeCheckConfig(config) {
101 | super._typeCheckConfig(config);
102 | this._checkContent(config.content);
103 | }
104 | _checkContent(arg) {
105 | for (const [selector, content] of Object.entries(arg)) {
106 | super._typeCheckConfig({
107 | selector,
108 | entry: content
109 | }, DefaultContentType);
110 | }
111 | }
112 | _setContent(template, content, selector) {
113 | const templateElement = SelectorEngine.findOne(selector, template);
114 | if (!templateElement) {
115 | return;
116 | }
117 | content = this._resolvePossibleFunction(content);
118 | if (!content) {
119 | templateElement.remove();
120 | return;
121 | }
122 | if (index_js.isElement(content)) {
123 | this._putElementInTemplate(index_js.getElement(content), templateElement);
124 | return;
125 | }
126 | if (this._config.html) {
127 | templateElement.innerHTML = this._maybeSanitize(content);
128 | return;
129 | }
130 | templateElement.textContent = content;
131 | }
132 | _maybeSanitize(arg) {
133 | return this._config.sanitize ? sanitizer_js.sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg;
134 | }
135 | _resolvePossibleFunction(arg) {
136 | return index_js.execute(arg, [undefined, this]);
137 | }
138 | _putElementInTemplate(element, templateElement) {
139 | if (this._config.html) {
140 | templateElement.innerHTML = '';
141 | templateElement.append(element);
142 | return;
143 | }
144 | templateElement.textContent = element.textContent;
145 | }
146 | }
147 |
148 | return TemplateFactory;
149 |
150 | }));
151 |
--------------------------------------------------------------------------------
/assets/stylesheets/_bootstrap-grid.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap/mixins/banner";
2 | @include bsBanner(Grid);
3 |
4 | $include-column-box-sizing: true !default;
5 |
6 | @import "bootstrap/functions";
7 | @import "bootstrap/variables";
8 | @import "bootstrap/variables-dark";
9 | @import "bootstrap/maps";
10 |
11 | @import "bootstrap/mixins/breakpoints";
12 | @import "bootstrap/mixins/container";
13 | @import "bootstrap/mixins/grid";
14 | @import "bootstrap/mixins/utilities";
15 |
16 | @import "bootstrap/vendor/rfs";
17 |
18 | @import "bootstrap/containers";
19 | @import "bootstrap/grid";
20 |
21 | @import "bootstrap/utilities";
22 | // Only use the utilities we need
23 | // stylelint-disable-next-line scss/dollar-variable-default
24 | $utilities: map-get-multiple(
25 | $utilities,
26 | (
27 | "bootstrap/display",
28 | "bootstrap/order",
29 | "bootstrap/flex",
30 | "bootstrap/flex-direction",
31 | "bootstrap/flex-grow",
32 | "bootstrap/flex-shrink",
33 | "bootstrap/flex-wrap",
34 | "bootstrap/justify-content",
35 | "bootstrap/align-items",
36 | "bootstrap/align-content",
37 | "bootstrap/align-self",
38 | "bootstrap/margin",
39 | "bootstrap/margin-x",
40 | "bootstrap/margin-y",
41 | "bootstrap/margin-top",
42 | "bootstrap/margin-end",
43 | "bootstrap/margin-bottom",
44 | "bootstrap/margin-start",
45 | "bootstrap/negative-margin",
46 | "bootstrap/negative-margin-x",
47 | "bootstrap/negative-margin-y",
48 | "bootstrap/negative-margin-top",
49 | "bootstrap/negative-margin-end",
50 | "bootstrap/negative-margin-bottom",
51 | "bootstrap/negative-margin-start",
52 | "bootstrap/padding",
53 | "bootstrap/padding-x",
54 | "bootstrap/padding-y",
55 | "bootstrap/padding-top",
56 | "bootstrap/padding-end",
57 | "bootstrap/padding-bottom",
58 | "bootstrap/padding-start",
59 | )
60 | );
61 |
62 | @import "bootstrap/utilities/api";
63 |
--------------------------------------------------------------------------------
/assets/stylesheets/_bootstrap-reboot.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap/mixins/banner";
2 | @include bsBanner(Reboot);
3 |
4 | @import "bootstrap/functions";
5 | @import "bootstrap/variables";
6 | @import "bootstrap/variables-dark";
7 | @import "bootstrap/maps";
8 | @import "bootstrap/mixins";
9 | @import "bootstrap/root";
10 | @import "bootstrap/reboot";
11 |
--------------------------------------------------------------------------------
/assets/stylesheets/_bootstrap-utilities.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap/mixins/banner";
2 | @include bsBanner(Utilities);
3 |
4 | // Configuration
5 | @import "bootstrap/functions";
6 | @import "bootstrap/variables";
7 | @import "bootstrap/variables-dark";
8 | @import "bootstrap/maps";
9 | @import "bootstrap/mixins";
10 | @import "bootstrap/utilities";
11 |
12 | // Layout & components
13 | @import "bootstrap/root";
14 |
15 | // Helpers
16 | @import "bootstrap/helpers";
17 |
18 | // Utilities
19 | @import "bootstrap/utilities/api";
20 |
--------------------------------------------------------------------------------
/assets/stylesheets/_bootstrap.scss:
--------------------------------------------------------------------------------
1 | @import "bootstrap/mixins/banner";
2 | @include bsBanner("");
3 |
4 |
5 | // scss-docs-start import-stack
6 | // Configuration
7 | @import "bootstrap/functions";
8 | @import "bootstrap/variables";
9 | @import "bootstrap/variables-dark";
10 | @import "bootstrap/maps";
11 | @import "bootstrap/mixins";
12 | @import "bootstrap/utilities";
13 |
14 | // Layout & components
15 | @import "bootstrap/root";
16 | @import "bootstrap/reboot";
17 | @import "bootstrap/type";
18 | @import "bootstrap/images";
19 | @import "bootstrap/containers";
20 | @import "bootstrap/grid";
21 | @import "bootstrap/tables";
22 | @import "bootstrap/forms";
23 | @import "bootstrap/buttons";
24 | @import "bootstrap/transitions";
25 | @import "bootstrap/dropdown";
26 | @import "bootstrap/button-group";
27 | @import "bootstrap/nav";
28 | @import "bootstrap/navbar";
29 | @import "bootstrap/card";
30 | @import "bootstrap/accordion";
31 | @import "bootstrap/breadcrumb";
32 | @import "bootstrap/pagination";
33 | @import "bootstrap/badge";
34 | @import "bootstrap/alert";
35 | @import "bootstrap/progress";
36 | @import "bootstrap/list-group";
37 | @import "bootstrap/close";
38 | @import "bootstrap/toasts";
39 | @import "bootstrap/modal";
40 | @import "bootstrap/tooltip";
41 | @import "bootstrap/popover";
42 | @import "bootstrap/carousel";
43 | @import "bootstrap/spinners";
44 | @import "bootstrap/offcanvas";
45 | @import "bootstrap/placeholders";
46 |
47 | // Helpers
48 | @import "bootstrap/helpers";
49 |
50 | // Utilities
51 | @import "bootstrap/utilities/api";
52 | // scss-docs-end import-stack
53 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_alert.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Base styles
3 | //
4 |
5 | .alert {
6 | // scss-docs-start alert-css-vars
7 | --#{$prefix}alert-bg: transparent;
8 | --#{$prefix}alert-padding-x: #{$alert-padding-x};
9 | --#{$prefix}alert-padding-y: #{$alert-padding-y};
10 | --#{$prefix}alert-margin-bottom: #{$alert-margin-bottom};
11 | --#{$prefix}alert-color: inherit;
12 | --#{$prefix}alert-border-color: transparent;
13 | --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);
14 | --#{$prefix}alert-border-radius: #{$alert-border-radius};
15 | --#{$prefix}alert-link-color: inherit;
16 | // scss-docs-end alert-css-vars
17 |
18 | position: relative;
19 | padding: var(--#{$prefix}alert-padding-y) var(--#{$prefix}alert-padding-x);
20 | margin-bottom: var(--#{$prefix}alert-margin-bottom);
21 | color: var(--#{$prefix}alert-color);
22 | background-color: var(--#{$prefix}alert-bg);
23 | border: var(--#{$prefix}alert-border);
24 | @include border-radius(var(--#{$prefix}alert-border-radius));
25 | }
26 |
27 | // Headings for larger alerts
28 | .alert-heading {
29 | // Specified to prevent conflicts of changing $headings-color
30 | color: inherit;
31 | }
32 |
33 | // Provide class for links that match alerts
34 | .alert-link {
35 | font-weight: $alert-link-font-weight;
36 | color: var(--#{$prefix}alert-link-color);
37 | }
38 |
39 |
40 | // Dismissible alerts
41 | //
42 | // Expand the right padding and account for the close button's positioning.
43 |
44 | .alert-dismissible {
45 | padding-right: $alert-dismissible-padding-r;
46 |
47 | // Adjust close link position
48 | .btn-close {
49 | position: absolute;
50 | top: 0;
51 | right: 0;
52 | z-index: $stretched-link-z-index + 1;
53 | padding: $alert-padding-y * 1.25 $alert-padding-x;
54 | }
55 | }
56 |
57 |
58 | // scss-docs-start alert-modifiers
59 | // Generate contextual modifier classes for colorizing the alert
60 | @each $state in map-keys($theme-colors) {
61 | .alert-#{$state} {
62 | --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis);
63 | --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);
64 | --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);
65 | --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis);
66 | }
67 | }
68 | // scss-docs-end alert-modifiers
69 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_badge.scss:
--------------------------------------------------------------------------------
1 | // Base class
2 | //
3 | // Requires one of the contextual, color modifier classes for `color` and
4 | // `background-color`.
5 |
6 | .badge {
7 | // scss-docs-start badge-css-vars
8 | --#{$prefix}badge-padding-x: #{$badge-padding-x};
9 | --#{$prefix}badge-padding-y: #{$badge-padding-y};
10 | @include rfs($badge-font-size, --#{$prefix}badge-font-size);
11 | --#{$prefix}badge-font-weight: #{$badge-font-weight};
12 | --#{$prefix}badge-color: #{$badge-color};
13 | --#{$prefix}badge-border-radius: #{$badge-border-radius};
14 | // scss-docs-end badge-css-vars
15 |
16 | display: inline-block;
17 | padding: var(--#{$prefix}badge-padding-y) var(--#{$prefix}badge-padding-x);
18 | @include font-size(var(--#{$prefix}badge-font-size));
19 | font-weight: var(--#{$prefix}badge-font-weight);
20 | line-height: 1;
21 | color: var(--#{$prefix}badge-color);
22 | text-align: center;
23 | white-space: nowrap;
24 | vertical-align: baseline;
25 | @include border-radius(var(--#{$prefix}badge-border-radius));
26 | @include gradient-bg();
27 |
28 | // Empty badges collapse automatically
29 | &:empty {
30 | display: none;
31 | }
32 | }
33 |
34 | // Quick fix for badges in buttons
35 | .btn .badge {
36 | position: relative;
37 | top: -1px;
38 | }
39 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_breadcrumb.scss:
--------------------------------------------------------------------------------
1 | .breadcrumb {
2 | // scss-docs-start breadcrumb-css-vars
3 | --#{$prefix}breadcrumb-padding-x: #{$breadcrumb-padding-x};
4 | --#{$prefix}breadcrumb-padding-y: #{$breadcrumb-padding-y};
5 | --#{$prefix}breadcrumb-margin-bottom: #{$breadcrumb-margin-bottom};
6 | @include rfs($breadcrumb-font-size, --#{$prefix}breadcrumb-font-size);
7 | --#{$prefix}breadcrumb-bg: #{$breadcrumb-bg};
8 | --#{$prefix}breadcrumb-border-radius: #{$breadcrumb-border-radius};
9 | --#{$prefix}breadcrumb-divider-color: #{$breadcrumb-divider-color};
10 | --#{$prefix}breadcrumb-item-padding-x: #{$breadcrumb-item-padding-x};
11 | --#{$prefix}breadcrumb-item-active-color: #{$breadcrumb-active-color};
12 | // scss-docs-end breadcrumb-css-vars
13 |
14 | display: flex;
15 | flex-wrap: wrap;
16 | padding: var(--#{$prefix}breadcrumb-padding-y) var(--#{$prefix}breadcrumb-padding-x);
17 | margin-bottom: var(--#{$prefix}breadcrumb-margin-bottom);
18 | @include font-size(var(--#{$prefix}breadcrumb-font-size));
19 | list-style: none;
20 | background-color: var(--#{$prefix}breadcrumb-bg);
21 | @include border-radius(var(--#{$prefix}breadcrumb-border-radius));
22 | }
23 |
24 | .breadcrumb-item {
25 | // The separator between breadcrumbs (by default, a forward-slash: "/")
26 | + .breadcrumb-item {
27 | padding-left: var(--#{$prefix}breadcrumb-item-padding-x);
28 |
29 | &::before {
30 | float: left; // Suppress inline spacings and underlining of the separator
31 | padding-right: var(--#{$prefix}breadcrumb-item-padding-x);
32 | color: var(--#{$prefix}breadcrumb-divider-color);
33 | content: var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider)) #{"/* rtl:"} var(--#{$prefix}breadcrumb-divider, escape-svg($breadcrumb-divider-flipped)) #{"*/"};
34 | }
35 | }
36 |
37 | &.active {
38 | color: var(--#{$prefix}breadcrumb-item-active-color);
39 | }
40 | }
41 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_button-group.scss:
--------------------------------------------------------------------------------
1 | // Make the div behave like a button
2 | .btn-group,
3 | .btn-group-vertical {
4 | position: relative;
5 | display: inline-flex;
6 | vertical-align: middle; // match .btn alignment given font-size hack above
7 |
8 | > .btn {
9 | position: relative;
10 | flex: 1 1 auto;
11 | }
12 |
13 | // Bring the hover, focused, and "active" buttons to the front to overlay
14 | // the borders properly
15 | > .btn-check:checked + .btn,
16 | > .btn-check:focus + .btn,
17 | > .btn:hover,
18 | > .btn:focus,
19 | > .btn:active,
20 | > .btn.active {
21 | z-index: 1;
22 | }
23 | }
24 |
25 | // Optional: Group multiple button groups together for a toolbar
26 | .btn-toolbar {
27 | display: flex;
28 | flex-wrap: wrap;
29 | justify-content: flex-start;
30 |
31 | .input-group {
32 | width: auto;
33 | }
34 | }
35 |
36 | .btn-group {
37 | @include border-radius($btn-border-radius);
38 |
39 | // Prevent double borders when buttons are next to each other
40 | > :not(.btn-check:first-child) + .btn,
41 | > .btn-group:not(:first-child) {
42 | margin-left: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
43 | }
44 |
45 | // Reset rounded corners
46 | > .btn:not(:last-child):not(.dropdown-toggle),
47 | > .btn.dropdown-toggle-split:first-child,
48 | > .btn-group:not(:last-child) > .btn {
49 | @include border-end-radius(0);
50 | }
51 |
52 | // The left radius should be 0 if the button is:
53 | // - the "third or more" child
54 | // - the second child and the previous element isn't `.btn-check` (making it the first child visually)
55 | // - part of a btn-group which isn't the first child
56 | > .btn:nth-child(n + 3),
57 | > :not(.btn-check) + .btn,
58 | > .btn-group:not(:first-child) > .btn {
59 | @include border-start-radius(0);
60 | }
61 | }
62 |
63 | // Sizing
64 | //
65 | // Remix the default button sizing classes into new ones for easier manipulation.
66 |
67 | .btn-group-sm > .btn { @extend .btn-sm; }
68 | .btn-group-lg > .btn { @extend .btn-lg; }
69 |
70 |
71 | //
72 | // Split button dropdowns
73 | //
74 |
75 | .dropdown-toggle-split {
76 | padding-right: $btn-padding-x * .75;
77 | padding-left: $btn-padding-x * .75;
78 |
79 | &::after,
80 | .dropup &::after,
81 | .dropend &::after {
82 | margin-left: 0;
83 | }
84 |
85 | .dropstart &::before {
86 | margin-right: 0;
87 | }
88 | }
89 |
90 | .btn-sm + .dropdown-toggle-split {
91 | padding-right: $btn-padding-x-sm * .75;
92 | padding-left: $btn-padding-x-sm * .75;
93 | }
94 |
95 | .btn-lg + .dropdown-toggle-split {
96 | padding-right: $btn-padding-x-lg * .75;
97 | padding-left: $btn-padding-x-lg * .75;
98 | }
99 |
100 |
101 | // The clickable button for toggling the menu
102 | // Set the same inset shadow as the :active state
103 | .btn-group.show .dropdown-toggle {
104 | @include box-shadow($btn-active-box-shadow);
105 |
106 | // Show no shadow for `.btn-link` since it has no other button styles.
107 | &.btn-link {
108 | @include box-shadow(none);
109 | }
110 | }
111 |
112 |
113 | //
114 | // Vertical button groups
115 | //
116 |
117 | .btn-group-vertical {
118 | flex-direction: column;
119 | align-items: flex-start;
120 | justify-content: center;
121 |
122 | > .btn,
123 | > .btn-group {
124 | width: 100%;
125 | }
126 |
127 | > .btn:not(:first-child),
128 | > .btn-group:not(:first-child) {
129 | margin-top: calc(-1 * #{$btn-border-width}); // stylelint-disable-line function-disallowed-list
130 | }
131 |
132 | // Reset rounded corners
133 | > .btn:not(:last-child):not(.dropdown-toggle),
134 | > .btn-group:not(:last-child) > .btn {
135 | @include border-bottom-radius(0);
136 | }
137 |
138 | // The top radius should be 0 if the button is:
139 | // - the "third or more" child
140 | // - the second child and the previous element isn't `.btn-check` (making it the first child visually)
141 | // - part of a btn-group which isn't the first child
142 | > .btn:nth-child(n + 3),
143 | > :not(.btn-check) + .btn,
144 | > .btn-group:not(:first-child) > .btn {
145 | @include border-top-radius(0);
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_close.scss:
--------------------------------------------------------------------------------
1 | // Transparent background and border properties included for button version.
2 | // iOS requires the button element instead of an anchor tag.
3 | // If you want the anchor version, it requires `href="#"`.
4 | // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
5 |
6 | .btn-close {
7 | // scss-docs-start close-css-vars
8 | --#{$prefix}btn-close-color: #{$btn-close-color};
9 | --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };
10 | --#{$prefix}btn-close-opacity: #{$btn-close-opacity};
11 | --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};
12 | --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};
13 | --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};
14 | --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};
15 | // scss-docs-end close-css-vars
16 |
17 | box-sizing: content-box;
18 | width: $btn-close-width;
19 | height: $btn-close-height;
20 | padding: $btn-close-padding-y $btn-close-padding-x;
21 | color: var(--#{$prefix}btn-close-color);
22 | background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
23 | filter: var(--#{$prefix}btn-close-filter);
24 | border: 0; // for button elements
25 | @include border-radius();
26 | opacity: var(--#{$prefix}btn-close-opacity);
27 |
28 | // Override 's hover style
29 | &:hover {
30 | color: var(--#{$prefix}btn-close-color);
31 | text-decoration: none;
32 | opacity: var(--#{$prefix}btn-close-hover-opacity);
33 | }
34 |
35 | &:focus {
36 | outline: 0;
37 | box-shadow: var(--#{$prefix}btn-close-focus-shadow);
38 | opacity: var(--#{$prefix}btn-close-focus-opacity);
39 | }
40 |
41 | &:disabled,
42 | &.disabled {
43 | pointer-events: none;
44 | user-select: none;
45 | opacity: var(--#{$prefix}btn-close-disabled-opacity);
46 | }
47 | }
48 |
49 | @mixin btn-close-white() {
50 | --#{$prefix}btn-close-filter: #{$btn-close-filter-dark};
51 | }
52 |
53 | .btn-close-white {
54 | @include btn-close-white();
55 | }
56 |
57 | :root,
58 | [data-bs-theme="light"] {
59 | --#{$prefix}btn-close-filter: #{$btn-close-filter};
60 | }
61 |
62 | @if $enable-dark-mode {
63 | @include color-mode(dark, true) {
64 | @include btn-close-white();
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_containers.scss:
--------------------------------------------------------------------------------
1 | // Container widths
2 | //
3 | // Set the container width, and override it for fixed navbars in media queries.
4 |
5 | @if $enable-container-classes {
6 | // Single container class with breakpoint max-widths
7 | .container,
8 | // 100% wide container at all breakpoints
9 | .container-fluid {
10 | @include make-container();
11 | }
12 |
13 | // Responsive containers that are 100% wide until a breakpoint
14 | @each $breakpoint, $container-max-width in $container-max-widths {
15 | .container-#{$breakpoint} {
16 | @extend .container-fluid;
17 | }
18 |
19 | @include media-breakpoint-up($breakpoint, $grid-breakpoints) {
20 | %responsive-container-#{$breakpoint} {
21 | max-width: $container-max-width;
22 | }
23 |
24 | // Extend each breakpoint which is smaller or equal to the current breakpoint
25 | $extend-breakpoint: true;
26 |
27 | @each $name, $width in $grid-breakpoints {
28 | @if ($extend-breakpoint) {
29 | .container#{breakpoint-infix($name, $grid-breakpoints)} {
30 | @extend %responsive-container-#{$breakpoint};
31 | }
32 |
33 | // Once the current breakpoint is reached, stop extending
34 | @if ($breakpoint == $name) {
35 | $extend-breakpoint: false;
36 | }
37 | }
38 | }
39 | }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_forms.scss:
--------------------------------------------------------------------------------
1 | @import "forms/labels";
2 | @import "forms/form-text";
3 | @import "forms/form-control";
4 | @import "forms/form-select";
5 | @import "forms/form-check";
6 | @import "forms/form-range";
7 | @import "forms/floating-labels";
8 | @import "forms/input-group";
9 | @import "forms/validation";
10 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_grid.scss:
--------------------------------------------------------------------------------
1 | // Row
2 | //
3 | // Rows contain your columns.
4 |
5 | :root {
6 | @each $name, $value in $grid-breakpoints {
7 | --#{$prefix}breakpoint-#{$name}: #{$value};
8 | }
9 | }
10 |
11 | @if $enable-grid-classes {
12 | .row {
13 | @include make-row();
14 |
15 | > * {
16 | @include make-col-ready();
17 | }
18 | }
19 | }
20 |
21 | @if $enable-cssgrid {
22 | .grid {
23 | display: grid;
24 | grid-template-rows: repeat(var(--#{$prefix}rows, 1), 1fr);
25 | grid-template-columns: repeat(var(--#{$prefix}columns, #{$grid-columns}), 1fr);
26 | gap: var(--#{$prefix}gap, #{$grid-gutter-width});
27 |
28 | @include make-cssgrid();
29 | }
30 | }
31 |
32 |
33 | // Columns
34 | //
35 | // Common styles for small and large grid columns
36 |
37 | @if $enable-grid-classes {
38 | @include make-grid-columns();
39 | }
40 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_helpers.scss:
--------------------------------------------------------------------------------
1 | @import "helpers/clearfix";
2 | @import "helpers/color-bg";
3 | @import "helpers/colored-links";
4 | @import "helpers/focus-ring";
5 | @import "helpers/icon-link";
6 | @import "helpers/ratio";
7 | @import "helpers/position";
8 | @import "helpers/stacks";
9 | @import "helpers/visually-hidden";
10 | @import "helpers/stretched-link";
11 | @import "helpers/text-truncation";
12 | @import "helpers/vr";
13 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_images.scss:
--------------------------------------------------------------------------------
1 | // Responsive images (ensure images don't scale beyond their parents)
2 | //
3 | // This is purposefully opt-in via an explicit class rather than being the default for all `
`s.
4 | // We previously tried the "images are responsive by default" approach in Bootstrap v2,
5 | // and abandoned it in Bootstrap v3 because it breaks lots of third-party widgets (including Google Maps)
6 | // which weren't expecting the images within themselves to be involuntarily resized.
7 | // See also https://github.com/twbs/bootstrap/issues/18178
8 | .img-fluid {
9 | @include img-fluid();
10 | }
11 |
12 |
13 | // Image thumbnails
14 | .img-thumbnail {
15 | padding: $thumbnail-padding;
16 | background-color: $thumbnail-bg;
17 | border: $thumbnail-border-width solid $thumbnail-border-color;
18 | @include border-radius($thumbnail-border-radius);
19 | @include box-shadow($thumbnail-box-shadow);
20 |
21 | // Keep them at most 100% wide
22 | @include img-fluid();
23 | }
24 |
25 | //
26 | // Figures
27 | //
28 |
29 | .figure {
30 | // Ensures the caption's text aligns with the image.
31 | display: inline-block;
32 | }
33 |
34 | .figure-img {
35 | margin-bottom: $spacer * .5;
36 | line-height: 1;
37 | }
38 |
39 | .figure-caption {
40 | @include font-size($figure-caption-font-size);
41 | color: $figure-caption-color;
42 | }
43 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_mixins.scss:
--------------------------------------------------------------------------------
1 | // Toggles
2 | //
3 | // Used in conjunction with global variables to enable certain theme features.
4 |
5 | // Vendor
6 | @import "vendor/rfs";
7 |
8 | // Deprecate
9 | @import "mixins/deprecate";
10 |
11 | // Helpers
12 | @import "mixins/breakpoints";
13 | @import "mixins/color-mode";
14 | @import "mixins/color-scheme";
15 | @import "mixins/image";
16 | @import "mixins/resize";
17 | @import "mixins/visually-hidden";
18 | @import "mixins/reset-text";
19 | @import "mixins/text-truncate";
20 |
21 | // Utilities
22 | @import "mixins/utilities";
23 |
24 | // Components
25 | @import "mixins/backdrop";
26 | @import "mixins/buttons";
27 | @import "mixins/caret";
28 | @import "mixins/pagination";
29 | @import "mixins/lists";
30 | @import "mixins/forms";
31 | @import "mixins/table-variants";
32 |
33 | // Skins
34 | @import "mixins/border-radius";
35 | @import "mixins/box-shadow";
36 | @import "mixins/gradients";
37 | @import "mixins/transition";
38 |
39 | // Layout
40 | @import "mixins/clearfix";
41 | @import "mixins/container";
42 | @import "mixins/grid";
43 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_pagination.scss:
--------------------------------------------------------------------------------
1 | .pagination {
2 | // scss-docs-start pagination-css-vars
3 | --#{$prefix}pagination-padding-x: #{$pagination-padding-x};
4 | --#{$prefix}pagination-padding-y: #{$pagination-padding-y};
5 | @include rfs($pagination-font-size, --#{$prefix}pagination-font-size);
6 | --#{$prefix}pagination-color: #{$pagination-color};
7 | --#{$prefix}pagination-bg: #{$pagination-bg};
8 | --#{$prefix}pagination-border-width: #{$pagination-border-width};
9 | --#{$prefix}pagination-border-color: #{$pagination-border-color};
10 | --#{$prefix}pagination-border-radius: #{$pagination-border-radius};
11 | --#{$prefix}pagination-hover-color: #{$pagination-hover-color};
12 | --#{$prefix}pagination-hover-bg: #{$pagination-hover-bg};
13 | --#{$prefix}pagination-hover-border-color: #{$pagination-hover-border-color};
14 | --#{$prefix}pagination-focus-color: #{$pagination-focus-color};
15 | --#{$prefix}pagination-focus-bg: #{$pagination-focus-bg};
16 | --#{$prefix}pagination-focus-box-shadow: #{$pagination-focus-box-shadow};
17 | --#{$prefix}pagination-active-color: #{$pagination-active-color};
18 | --#{$prefix}pagination-active-bg: #{$pagination-active-bg};
19 | --#{$prefix}pagination-active-border-color: #{$pagination-active-border-color};
20 | --#{$prefix}pagination-disabled-color: #{$pagination-disabled-color};
21 | --#{$prefix}pagination-disabled-bg: #{$pagination-disabled-bg};
22 | --#{$prefix}pagination-disabled-border-color: #{$pagination-disabled-border-color};
23 | // scss-docs-end pagination-css-vars
24 |
25 | display: flex;
26 | @include list-unstyled();
27 | }
28 |
29 | .page-link {
30 | position: relative;
31 | display: block;
32 | padding: var(--#{$prefix}pagination-padding-y) var(--#{$prefix}pagination-padding-x);
33 | @include font-size(var(--#{$prefix}pagination-font-size));
34 | color: var(--#{$prefix}pagination-color);
35 | text-decoration: if($link-decoration == none, null, none);
36 | background-color: var(--#{$prefix}pagination-bg);
37 | border: var(--#{$prefix}pagination-border-width) solid var(--#{$prefix}pagination-border-color);
38 | @include transition($pagination-transition);
39 |
40 | &:hover {
41 | z-index: 2;
42 | color: var(--#{$prefix}pagination-hover-color);
43 | text-decoration: if($link-hover-decoration == underline, none, null);
44 | background-color: var(--#{$prefix}pagination-hover-bg);
45 | border-color: var(--#{$prefix}pagination-hover-border-color);
46 | }
47 |
48 | &:focus {
49 | z-index: 3;
50 | color: var(--#{$prefix}pagination-focus-color);
51 | background-color: var(--#{$prefix}pagination-focus-bg);
52 | outline: $pagination-focus-outline;
53 | box-shadow: var(--#{$prefix}pagination-focus-box-shadow);
54 | }
55 |
56 | &.active,
57 | .active > & {
58 | z-index: 3;
59 | color: var(--#{$prefix}pagination-active-color);
60 | @include gradient-bg(var(--#{$prefix}pagination-active-bg));
61 | border-color: var(--#{$prefix}pagination-active-border-color);
62 | }
63 |
64 | &.disabled,
65 | .disabled > & {
66 | color: var(--#{$prefix}pagination-disabled-color);
67 | pointer-events: none;
68 | background-color: var(--#{$prefix}pagination-disabled-bg);
69 | border-color: var(--#{$prefix}pagination-disabled-border-color);
70 | }
71 | }
72 |
73 | .page-item {
74 | &:not(:first-child) .page-link {
75 | margin-left: $pagination-margin-start;
76 | }
77 |
78 | @if $pagination-margin-start == calc(-1 * #{$pagination-border-width}) {
79 | &:first-child {
80 | .page-link {
81 | @include border-start-radius(var(--#{$prefix}pagination-border-radius));
82 | }
83 | }
84 |
85 | &:last-child {
86 | .page-link {
87 | @include border-end-radius(var(--#{$prefix}pagination-border-radius));
88 | }
89 | }
90 | } @else {
91 | // Add border-radius to all pageLinks in case they have left margin
92 | .page-link {
93 | @include border-radius(var(--#{$prefix}pagination-border-radius));
94 | }
95 | }
96 | }
97 |
98 |
99 | //
100 | // Sizing
101 | //
102 |
103 | .pagination-lg {
104 | @include pagination-size($pagination-padding-y-lg, $pagination-padding-x-lg, $font-size-lg, $pagination-border-radius-lg);
105 | }
106 |
107 | .pagination-sm {
108 | @include pagination-size($pagination-padding-y-sm, $pagination-padding-x-sm, $font-size-sm, $pagination-border-radius-sm);
109 | }
110 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_placeholders.scss:
--------------------------------------------------------------------------------
1 | .placeholder {
2 | display: inline-block;
3 | min-height: 1em;
4 | vertical-align: middle;
5 | cursor: wait;
6 | background-color: currentcolor;
7 | opacity: $placeholder-opacity-max;
8 |
9 | &.btn::before {
10 | display: inline-block;
11 | content: "";
12 | }
13 | }
14 |
15 | // Sizing
16 | .placeholder-xs {
17 | min-height: .6em;
18 | }
19 |
20 | .placeholder-sm {
21 | min-height: .8em;
22 | }
23 |
24 | .placeholder-lg {
25 | min-height: 1.2em;
26 | }
27 |
28 | // Animation
29 | .placeholder-glow {
30 | .placeholder {
31 | animation: placeholder-glow 2s ease-in-out infinite;
32 | }
33 | }
34 |
35 | @keyframes placeholder-glow {
36 | 50% {
37 | opacity: $placeholder-opacity-min;
38 | }
39 | }
40 |
41 | .placeholder-wave {
42 | mask-image: linear-gradient(130deg, $black 55%, rgba(0, 0, 0, (1 - $placeholder-opacity-min)) 75%, $black 95%);
43 | mask-size: 200% 100%;
44 | animation: placeholder-wave 2s linear infinite;
45 | }
46 |
47 | @keyframes placeholder-wave {
48 | 100% {
49 | mask-position: -200% 0%;
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_progress.scss:
--------------------------------------------------------------------------------
1 | // Disable animation if transitions are disabled
2 |
3 | // scss-docs-start progress-keyframes
4 | @if $enable-transitions {
5 | @keyframes progress-bar-stripes {
6 | 0% { background-position-x: var(--#{$prefix}progress-height); }
7 | }
8 | }
9 | // scss-docs-end progress-keyframes
10 |
11 | .progress,
12 | .progress-stacked {
13 | // scss-docs-start progress-css-vars
14 | --#{$prefix}progress-height: #{$progress-height};
15 | @include rfs($progress-font-size, --#{$prefix}progress-font-size);
16 | --#{$prefix}progress-bg: #{$progress-bg};
17 | --#{$prefix}progress-border-radius: #{$progress-border-radius};
18 | --#{$prefix}progress-box-shadow: #{$progress-box-shadow};
19 | --#{$prefix}progress-bar-color: #{$progress-bar-color};
20 | --#{$prefix}progress-bar-bg: #{$progress-bar-bg};
21 | --#{$prefix}progress-bar-transition: #{$progress-bar-transition};
22 | // scss-docs-end progress-css-vars
23 |
24 | display: flex;
25 | height: var(--#{$prefix}progress-height);
26 | overflow: hidden; // force rounded corners by cropping it
27 | @include font-size(var(--#{$prefix}progress-font-size));
28 | background-color: var(--#{$prefix}progress-bg);
29 | @include border-radius(var(--#{$prefix}progress-border-radius));
30 | @include box-shadow(var(--#{$prefix}progress-box-shadow));
31 | }
32 |
33 | .progress-bar {
34 | display: flex;
35 | flex-direction: column;
36 | justify-content: center;
37 | overflow: hidden;
38 | color: var(--#{$prefix}progress-bar-color);
39 | text-align: center;
40 | white-space: nowrap;
41 | background-color: var(--#{$prefix}progress-bar-bg);
42 | @include transition(var(--#{$prefix}progress-bar-transition));
43 | }
44 |
45 | .progress-bar-striped {
46 | @include gradient-striped();
47 | background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height);
48 | }
49 |
50 | .progress-stacked > .progress {
51 | overflow: visible;
52 | }
53 |
54 | .progress-stacked > .progress > .progress-bar {
55 | width: 100%;
56 | }
57 |
58 | @if $enable-transitions {
59 | .progress-bar-animated {
60 | animation: $progress-bar-animation-timing progress-bar-stripes;
61 |
62 | @if $enable-reduced-motion {
63 | @media (prefers-reduced-motion: reduce) {
64 | animation: none;
65 | }
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_spinners.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Rotating border
3 | //
4 |
5 | .spinner-grow,
6 | .spinner-border {
7 | display: inline-block;
8 | width: var(--#{$prefix}spinner-width);
9 | height: var(--#{$prefix}spinner-height);
10 | vertical-align: var(--#{$prefix}spinner-vertical-align);
11 | // stylelint-disable-next-line property-disallowed-list
12 | border-radius: 50%;
13 | animation: var(--#{$prefix}spinner-animation-speed) linear infinite var(--#{$prefix}spinner-animation-name);
14 | }
15 |
16 | // scss-docs-start spinner-border-keyframes
17 | @keyframes spinner-border {
18 | to { transform: rotate(360deg) #{"/* rtl:ignore */"}; }
19 | }
20 | // scss-docs-end spinner-border-keyframes
21 |
22 | .spinner-border {
23 | // scss-docs-start spinner-border-css-vars
24 | --#{$prefix}spinner-width: #{$spinner-width};
25 | --#{$prefix}spinner-height: #{$spinner-height};
26 | --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
27 | --#{$prefix}spinner-border-width: #{$spinner-border-width};
28 | --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
29 | --#{$prefix}spinner-animation-name: spinner-border;
30 | // scss-docs-end spinner-border-css-vars
31 |
32 | border: var(--#{$prefix}spinner-border-width) solid currentcolor;
33 | border-right-color: transparent;
34 | }
35 |
36 | .spinner-border-sm {
37 | // scss-docs-start spinner-border-sm-css-vars
38 | --#{$prefix}spinner-width: #{$spinner-width-sm};
39 | --#{$prefix}spinner-height: #{$spinner-height-sm};
40 | --#{$prefix}spinner-border-width: #{$spinner-border-width-sm};
41 | // scss-docs-end spinner-border-sm-css-vars
42 | }
43 |
44 | //
45 | // Growing circle
46 | //
47 |
48 | // scss-docs-start spinner-grow-keyframes
49 | @keyframes spinner-grow {
50 | 0% {
51 | transform: scale(0);
52 | }
53 | 50% {
54 | opacity: 1;
55 | transform: none;
56 | }
57 | }
58 | // scss-docs-end spinner-grow-keyframes
59 |
60 | .spinner-grow {
61 | // scss-docs-start spinner-grow-css-vars
62 | --#{$prefix}spinner-width: #{$spinner-width};
63 | --#{$prefix}spinner-height: #{$spinner-height};
64 | --#{$prefix}spinner-vertical-align: #{$spinner-vertical-align};
65 | --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed};
66 | --#{$prefix}spinner-animation-name: spinner-grow;
67 | // scss-docs-end spinner-grow-css-vars
68 |
69 | background-color: currentcolor;
70 | opacity: 0;
71 | }
72 |
73 | .spinner-grow-sm {
74 | --#{$prefix}spinner-width: #{$spinner-width-sm};
75 | --#{$prefix}spinner-height: #{$spinner-height-sm};
76 | }
77 |
78 | @if $enable-reduced-motion {
79 | @media (prefers-reduced-motion: reduce) {
80 | .spinner-border,
81 | .spinner-grow {
82 | --#{$prefix}spinner-animation-speed: #{$spinner-animation-speed * 2};
83 | }
84 | }
85 | }
86 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_toasts.scss:
--------------------------------------------------------------------------------
1 | .toast {
2 | // scss-docs-start toast-css-vars
3 | --#{$prefix}toast-zindex: #{$zindex-toast};
4 | --#{$prefix}toast-padding-x: #{$toast-padding-x};
5 | --#{$prefix}toast-padding-y: #{$toast-padding-y};
6 | --#{$prefix}toast-spacing: #{$toast-spacing};
7 | --#{$prefix}toast-max-width: #{$toast-max-width};
8 | @include rfs($toast-font-size, --#{$prefix}toast-font-size);
9 | --#{$prefix}toast-color: #{$toast-color};
10 | --#{$prefix}toast-bg: #{$toast-background-color};
11 | --#{$prefix}toast-border-width: #{$toast-border-width};
12 | --#{$prefix}toast-border-color: #{$toast-border-color};
13 | --#{$prefix}toast-border-radius: #{$toast-border-radius};
14 | --#{$prefix}toast-box-shadow: #{$toast-box-shadow};
15 | --#{$prefix}toast-header-color: #{$toast-header-color};
16 | --#{$prefix}toast-header-bg: #{$toast-header-background-color};
17 | --#{$prefix}toast-header-border-color: #{$toast-header-border-color};
18 | // scss-docs-end toast-css-vars
19 |
20 | width: var(--#{$prefix}toast-max-width);
21 | max-width: 100%;
22 | @include font-size(var(--#{$prefix}toast-font-size));
23 | color: var(--#{$prefix}toast-color);
24 | pointer-events: auto;
25 | background-color: var(--#{$prefix}toast-bg);
26 | background-clip: padding-box;
27 | border: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-border-color);
28 | box-shadow: var(--#{$prefix}toast-box-shadow);
29 | @include border-radius(var(--#{$prefix}toast-border-radius));
30 |
31 | &.showing {
32 | opacity: 0;
33 | }
34 |
35 | &:not(.show) {
36 | display: none;
37 | }
38 | }
39 |
40 | .toast-container {
41 | --#{$prefix}toast-zindex: #{$zindex-toast};
42 |
43 | position: absolute;
44 | z-index: var(--#{$prefix}toast-zindex);
45 | width: max-content;
46 | max-width: 100%;
47 | pointer-events: none;
48 |
49 | > :not(:last-child) {
50 | margin-bottom: var(--#{$prefix}toast-spacing);
51 | }
52 | }
53 |
54 | .toast-header {
55 | display: flex;
56 | align-items: center;
57 | padding: var(--#{$prefix}toast-padding-y) var(--#{$prefix}toast-padding-x);
58 | color: var(--#{$prefix}toast-header-color);
59 | background-color: var(--#{$prefix}toast-header-bg);
60 | background-clip: padding-box;
61 | border-bottom: var(--#{$prefix}toast-border-width) solid var(--#{$prefix}toast-header-border-color);
62 | @include border-top-radius(calc(var(--#{$prefix}toast-border-radius) - var(--#{$prefix}toast-border-width)));
63 |
64 | .btn-close {
65 | margin-right: calc(-.5 * var(--#{$prefix}toast-padding-x)); // stylelint-disable-line function-disallowed-list
66 | margin-left: var(--#{$prefix}toast-padding-x);
67 | }
68 | }
69 |
70 | .toast-body {
71 | padding: var(--#{$prefix}toast-padding-x);
72 | word-wrap: break-word;
73 | }
74 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_tooltip.scss:
--------------------------------------------------------------------------------
1 | // Base class
2 | .tooltip {
3 | // scss-docs-start tooltip-css-vars
4 | --#{$prefix}tooltip-zindex: #{$zindex-tooltip};
5 | --#{$prefix}tooltip-max-width: #{$tooltip-max-width};
6 | --#{$prefix}tooltip-padding-x: #{$tooltip-padding-x};
7 | --#{$prefix}tooltip-padding-y: #{$tooltip-padding-y};
8 | --#{$prefix}tooltip-margin: #{$tooltip-margin};
9 | @include rfs($tooltip-font-size, --#{$prefix}tooltip-font-size);
10 | --#{$prefix}tooltip-color: #{$tooltip-color};
11 | --#{$prefix}tooltip-bg: #{$tooltip-bg};
12 | --#{$prefix}tooltip-border-radius: #{$tooltip-border-radius};
13 | --#{$prefix}tooltip-opacity: #{$tooltip-opacity};
14 | --#{$prefix}tooltip-arrow-width: #{$tooltip-arrow-width};
15 | --#{$prefix}tooltip-arrow-height: #{$tooltip-arrow-height};
16 | // scss-docs-end tooltip-css-vars
17 |
18 | z-index: var(--#{$prefix}tooltip-zindex);
19 | display: block;
20 | margin: var(--#{$prefix}tooltip-margin);
21 | @include deprecate("`$tooltip-margin`", "v5", "v5.x", true);
22 | // Our parent element can be arbitrary since tooltips are by default inserted as a sibling of their target element.
23 | // So reset our font and text properties to avoid inheriting weird values.
24 | @include reset-text();
25 | @include font-size(var(--#{$prefix}tooltip-font-size));
26 | // Allow breaking very long words so they don't overflow the tooltip's bounds
27 | word-wrap: break-word;
28 | opacity: 0;
29 |
30 | &.show { opacity: var(--#{$prefix}tooltip-opacity); }
31 |
32 | .tooltip-arrow {
33 | display: block;
34 | width: var(--#{$prefix}tooltip-arrow-width);
35 | height: var(--#{$prefix}tooltip-arrow-height);
36 |
37 | &::before {
38 | position: absolute;
39 | content: "";
40 | border-color: transparent;
41 | border-style: solid;
42 | }
43 | }
44 | }
45 |
46 | .bs-tooltip-top .tooltip-arrow {
47 | bottom: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
48 |
49 | &::before {
50 | top: -1px;
51 | border-width: var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
52 | border-top-color: var(--#{$prefix}tooltip-bg);
53 | }
54 | }
55 |
56 | /* rtl:begin:ignore */
57 | .bs-tooltip-end .tooltip-arrow {
58 | left: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
59 | width: var(--#{$prefix}tooltip-arrow-height);
60 | height: var(--#{$prefix}tooltip-arrow-width);
61 |
62 | &::before {
63 | right: -1px;
64 | border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height) calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0; // stylelint-disable-line function-disallowed-list
65 | border-right-color: var(--#{$prefix}tooltip-bg);
66 | }
67 | }
68 |
69 | /* rtl:end:ignore */
70 |
71 | .bs-tooltip-bottom .tooltip-arrow {
72 | top: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
73 |
74 | &::before {
75 | bottom: -1px;
76 | border-width: 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
77 | border-bottom-color: var(--#{$prefix}tooltip-bg);
78 | }
79 | }
80 |
81 | /* rtl:begin:ignore */
82 | .bs-tooltip-start .tooltip-arrow {
83 | right: calc(-1 * var(--#{$prefix}tooltip-arrow-height)); // stylelint-disable-line function-disallowed-list
84 | width: var(--#{$prefix}tooltip-arrow-height);
85 | height: var(--#{$prefix}tooltip-arrow-width);
86 |
87 | &::before {
88 | left: -1px;
89 | border-width: calc(var(--#{$prefix}tooltip-arrow-width) * .5) 0 calc(var(--#{$prefix}tooltip-arrow-width) * .5) var(--#{$prefix}tooltip-arrow-height); // stylelint-disable-line function-disallowed-list
90 | border-left-color: var(--#{$prefix}tooltip-bg);
91 | }
92 | }
93 |
94 | /* rtl:end:ignore */
95 |
96 | .bs-tooltip-auto {
97 | &[data-popper-placement^="top"] {
98 | @extend .bs-tooltip-top;
99 | }
100 | &[data-popper-placement^="right"] {
101 | @extend .bs-tooltip-end;
102 | }
103 | &[data-popper-placement^="bottom"] {
104 | @extend .bs-tooltip-bottom;
105 | }
106 | &[data-popper-placement^="left"] {
107 | @extend .bs-tooltip-start;
108 | }
109 | }
110 |
111 | // Wrapper for the tooltip content
112 | .tooltip-inner {
113 | max-width: var(--#{$prefix}tooltip-max-width);
114 | padding: var(--#{$prefix}tooltip-padding-y) var(--#{$prefix}tooltip-padding-x);
115 | color: var(--#{$prefix}tooltip-color);
116 | text-align: center;
117 | background-color: var(--#{$prefix}tooltip-bg);
118 | @include border-radius(var(--#{$prefix}tooltip-border-radius));
119 | }
120 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_transitions.scss:
--------------------------------------------------------------------------------
1 | .fade {
2 | @include transition($transition-fade);
3 |
4 | &:not(.show) {
5 | opacity: 0;
6 | }
7 | }
8 |
9 | // scss-docs-start collapse-classes
10 | .collapse {
11 | &:not(.show) {
12 | display: none;
13 | }
14 | }
15 |
16 | .collapsing {
17 | height: 0;
18 | overflow: hidden;
19 | @include transition($transition-collapse);
20 |
21 | &.collapse-horizontal {
22 | width: 0;
23 | height: auto;
24 | @include transition($transition-collapse-width);
25 | }
26 | }
27 | // scss-docs-end collapse-classes
28 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/_type.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Headings
3 | //
4 | .h1 {
5 | @extend h1;
6 | }
7 |
8 | .h2 {
9 | @extend h2;
10 | }
11 |
12 | .h3 {
13 | @extend h3;
14 | }
15 |
16 | .h4 {
17 | @extend h4;
18 | }
19 |
20 | .h5 {
21 | @extend h5;
22 | }
23 |
24 | .h6 {
25 | @extend h6;
26 | }
27 |
28 |
29 | .lead {
30 | @include font-size($lead-font-size);
31 | font-weight: $lead-font-weight;
32 | }
33 |
34 | // Type display classes
35 | @each $display, $font-size in $display-font-sizes {
36 | .display-#{$display} {
37 | font-family: $display-font-family;
38 | font-style: $display-font-style;
39 | font-weight: $display-font-weight;
40 | line-height: $display-line-height;
41 | @include font-size($font-size);
42 | }
43 | }
44 |
45 | //
46 | // Emphasis
47 | //
48 | .small {
49 | @extend small;
50 | }
51 |
52 | .mark {
53 | @extend mark;
54 | }
55 |
56 | //
57 | // Lists
58 | //
59 |
60 | .list-unstyled {
61 | @include list-unstyled();
62 | }
63 |
64 | // Inline turns list items into inline-block
65 | .list-inline {
66 | @include list-unstyled();
67 | }
68 | .list-inline-item {
69 | display: inline-block;
70 |
71 | &:not(:last-child) {
72 | margin-right: $list-inline-padding;
73 | }
74 | }
75 |
76 |
77 | //
78 | // Misc
79 | //
80 |
81 | // Builds on `abbr`
82 | .initialism {
83 | @include font-size($initialism-font-size);
84 | text-transform: uppercase;
85 | }
86 |
87 | // Blockquotes
88 | .blockquote {
89 | margin-bottom: $blockquote-margin-y;
90 | @include font-size($blockquote-font-size);
91 |
92 | > :last-child {
93 | margin-bottom: 0;
94 | }
95 | }
96 |
97 | .blockquote-footer {
98 | margin-top: -$blockquote-margin-y;
99 | margin-bottom: $blockquote-margin-y;
100 | @include font-size($blockquote-footer-font-size);
101 | color: $blockquote-footer-color;
102 |
103 | &::before {
104 | content: "\2014\00A0"; // em dash, nbsp
105 | }
106 | }
107 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_floating-labels.scss:
--------------------------------------------------------------------------------
1 | .form-floating {
2 | position: relative;
3 |
4 | > .form-control,
5 | > .form-control-plaintext,
6 | > .form-select {
7 | height: $form-floating-height;
8 | min-height: $form-floating-height;
9 | line-height: $form-floating-line-height;
10 | }
11 |
12 | > label {
13 | position: absolute;
14 | top: 0;
15 | left: 0;
16 | z-index: 2;
17 | max-width: 100%;
18 | height: 100%; // allow textareas
19 | padding: $form-floating-padding-y $form-floating-padding-x;
20 | overflow: hidden;
21 | color: rgba(var(--#{$prefix}body-color-rgb), #{$form-floating-label-opacity});
22 | text-align: start;
23 | text-overflow: ellipsis;
24 | white-space: nowrap;
25 | pointer-events: none;
26 | border: $input-border-width solid transparent; // Required for aligning label's text with the input as it affects inner box model
27 | transform-origin: 0 0;
28 | @include transition($form-floating-transition);
29 | }
30 |
31 | > .form-control,
32 | > .form-control-plaintext {
33 | padding: $form-floating-padding-y $form-floating-padding-x;
34 |
35 | &::placeholder {
36 | color: transparent;
37 | }
38 |
39 | &:focus,
40 | &:not(:placeholder-shown) {
41 | padding-top: $form-floating-input-padding-t;
42 | padding-bottom: $form-floating-input-padding-b;
43 | }
44 | // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
45 | &:-webkit-autofill {
46 | padding-top: $form-floating-input-padding-t;
47 | padding-bottom: $form-floating-input-padding-b;
48 | }
49 | }
50 |
51 | > .form-select {
52 | padding-top: $form-floating-input-padding-t;
53 | padding-bottom: $form-floating-input-padding-b;
54 | padding-left: $form-floating-padding-x;
55 | }
56 |
57 | > .form-control:focus,
58 | > .form-control:not(:placeholder-shown),
59 | > .form-control-plaintext,
60 | > .form-select {
61 | ~ label {
62 | transform: $form-floating-label-transform;
63 | }
64 | }
65 | // Duplicated because `:-webkit-autofill` invalidates other selectors when grouped
66 | > .form-control:-webkit-autofill {
67 | ~ label {
68 | transform: $form-floating-label-transform;
69 | }
70 | }
71 | > textarea:focus,
72 | > textarea:not(:placeholder-shown) {
73 | ~ label::after {
74 | position: absolute;
75 | inset: $form-floating-padding-y ($form-floating-padding-x * .5);
76 | z-index: -1;
77 | height: $form-floating-label-height;
78 | content: "";
79 | background-color: $input-bg;
80 | @include border-radius($input-border-radius);
81 | }
82 | }
83 | > textarea:disabled ~ label::after {
84 | background-color: $input-disabled-bg;
85 | }
86 |
87 | > .form-control-plaintext {
88 | ~ label {
89 | border-width: $input-border-width 0; // Required to properly position label text - as explained above
90 | }
91 | }
92 |
93 | > :disabled ~ label,
94 | > .form-control:disabled ~ label { // Required for `.form-control`s because of specificity
95 | color: $form-floating-label-disabled-color;
96 | }
97 | }
98 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_form-range.scss:
--------------------------------------------------------------------------------
1 | // Range
2 | //
3 | // Style range inputs the same across browsers. Vendor-specific rules for pseudo
4 | // elements cannot be mixed. As such, there are no shared styles for focus or
5 | // active states on prefixed selectors.
6 |
7 | .form-range {
8 | width: 100%;
9 | height: add($form-range-thumb-height, $form-range-thumb-focus-box-shadow-width * 2);
10 | padding: 0; // Need to reset padding
11 | appearance: none;
12 | background-color: transparent;
13 |
14 | &:focus {
15 | outline: 0;
16 |
17 | // Pseudo-elements must be split across multiple rulesets to have an effect.
18 | // No box-shadow() mixin for focus accessibility.
19 | &::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
20 | &::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; }
21 | }
22 |
23 | &::-moz-focus-outer {
24 | border: 0;
25 | }
26 |
27 | &::-webkit-slider-thumb {
28 | width: $form-range-thumb-width;
29 | height: $form-range-thumb-height;
30 | margin-top: ($form-range-track-height - $form-range-thumb-height) * .5; // Webkit specific
31 | appearance: none;
32 | @include gradient-bg($form-range-thumb-bg);
33 | border: $form-range-thumb-border;
34 | @include border-radius($form-range-thumb-border-radius);
35 | @include box-shadow($form-range-thumb-box-shadow);
36 | @include transition($form-range-thumb-transition);
37 |
38 | &:active {
39 | @include gradient-bg($form-range-thumb-active-bg);
40 | }
41 | }
42 |
43 | &::-webkit-slider-runnable-track {
44 | width: $form-range-track-width;
45 | height: $form-range-track-height;
46 | color: transparent; // Why?
47 | cursor: $form-range-track-cursor;
48 | background-color: $form-range-track-bg;
49 | border-color: transparent;
50 | @include border-radius($form-range-track-border-radius);
51 | @include box-shadow($form-range-track-box-shadow);
52 | }
53 |
54 | &::-moz-range-thumb {
55 | width: $form-range-thumb-width;
56 | height: $form-range-thumb-height;
57 | appearance: none;
58 | @include gradient-bg($form-range-thumb-bg);
59 | border: $form-range-thumb-border;
60 | @include border-radius($form-range-thumb-border-radius);
61 | @include box-shadow($form-range-thumb-box-shadow);
62 | @include transition($form-range-thumb-transition);
63 |
64 | &:active {
65 | @include gradient-bg($form-range-thumb-active-bg);
66 | }
67 | }
68 |
69 | &::-moz-range-track {
70 | width: $form-range-track-width;
71 | height: $form-range-track-height;
72 | color: transparent;
73 | cursor: $form-range-track-cursor;
74 | background-color: $form-range-track-bg;
75 | border-color: transparent; // Firefox specific?
76 | @include border-radius($form-range-track-border-radius);
77 | @include box-shadow($form-range-track-box-shadow);
78 | }
79 |
80 | &:disabled {
81 | pointer-events: none;
82 |
83 | &::-webkit-slider-thumb {
84 | background-color: $form-range-thumb-disabled-bg;
85 | }
86 |
87 | &::-moz-range-thumb {
88 | background-color: $form-range-thumb-disabled-bg;
89 | }
90 | }
91 | }
92 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_form-select.scss:
--------------------------------------------------------------------------------
1 | // Select
2 | //
3 | // Replaces the browser default select with a custom one, mostly pulled from
4 | // https://primer.github.io/.
5 |
6 | .form-select {
7 | --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator)};
8 |
9 | display: block;
10 | width: 100%;
11 | padding: $form-select-padding-y $form-select-indicator-padding $form-select-padding-y $form-select-padding-x;
12 | font-family: $form-select-font-family;
13 | @include font-size($form-select-font-size);
14 | font-weight: $form-select-font-weight;
15 | line-height: $form-select-line-height;
16 | color: $form-select-color;
17 | appearance: none;
18 | background-color: $form-select-bg;
19 | background-image: var(--#{$prefix}form-select-bg-img), var(--#{$prefix}form-select-bg-icon, none);
20 | background-repeat: no-repeat;
21 | background-position: $form-select-bg-position;
22 | background-size: $form-select-bg-size;
23 | border: $form-select-border-width solid $form-select-border-color;
24 | @include border-radius($form-select-border-radius, 0);
25 | @include box-shadow($form-select-box-shadow);
26 | @include transition($form-select-transition);
27 |
28 | &:focus {
29 | border-color: $form-select-focus-border-color;
30 | outline: 0;
31 | @if $enable-shadows {
32 | @include box-shadow($form-select-box-shadow, $form-select-focus-box-shadow);
33 | } @else {
34 | // Avoid using mixin so we can pass custom focus shadow properly
35 | box-shadow: $form-select-focus-box-shadow;
36 | }
37 | }
38 |
39 | &[multiple],
40 | &[size]:not([size="1"]) {
41 | padding-right: $form-select-padding-x;
42 | background-image: none;
43 | }
44 |
45 | &:disabled {
46 | color: $form-select-disabled-color;
47 | background-color: $form-select-disabled-bg;
48 | border-color: $form-select-disabled-border-color;
49 | }
50 |
51 | // Remove outline from select box in FF
52 | &:-moz-focusring {
53 | color: transparent;
54 | text-shadow: 0 0 0 $form-select-color;
55 | }
56 | }
57 |
58 | .form-select-sm {
59 | padding-top: $form-select-padding-y-sm;
60 | padding-bottom: $form-select-padding-y-sm;
61 | padding-left: $form-select-padding-x-sm;
62 | @include font-size($form-select-font-size-sm);
63 | @include border-radius($form-select-border-radius-sm);
64 | }
65 |
66 | .form-select-lg {
67 | padding-top: $form-select-padding-y-lg;
68 | padding-bottom: $form-select-padding-y-lg;
69 | padding-left: $form-select-padding-x-lg;
70 | @include font-size($form-select-font-size-lg);
71 | @include border-radius($form-select-border-radius-lg);
72 | }
73 |
74 | @if $enable-dark-mode {
75 | @include color-mode(dark) {
76 | .form-select {
77 | --#{$prefix}form-select-bg-img: #{escape-svg($form-select-indicator-dark)};
78 | }
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_form-text.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Form text
3 | //
4 |
5 | .form-text {
6 | margin-top: $form-text-margin-top;
7 | @include font-size($form-text-font-size);
8 | font-style: $form-text-font-style;
9 | font-weight: $form-text-font-weight;
10 | color: $form-text-color;
11 | }
12 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_input-group.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Base styles
3 | //
4 |
5 | .input-group {
6 | position: relative;
7 | display: flex;
8 | flex-wrap: wrap; // For form validation feedback
9 | align-items: stretch;
10 | width: 100%;
11 |
12 | > .form-control,
13 | > .form-select,
14 | > .form-floating {
15 | position: relative; // For focus state's z-index
16 | flex: 1 1 auto;
17 | width: 1%;
18 | min-width: 0; // https://stackoverflow.com/questions/36247140/why-dont-flex-items-shrink-past-content-size
19 | }
20 |
21 | // Bring the "active" form control to the top of surrounding elements
22 | > .form-control:focus,
23 | > .form-select:focus,
24 | > .form-floating:focus-within {
25 | z-index: 5;
26 | }
27 |
28 | // Ensure buttons are always above inputs for more visually pleasing borders.
29 | // This isn't needed for `.input-group-text` since it shares the same border-color
30 | // as our inputs.
31 | .btn {
32 | position: relative;
33 | z-index: 2;
34 |
35 | &:focus {
36 | z-index: 5;
37 | }
38 | }
39 | }
40 |
41 |
42 | // Textual addons
43 | //
44 | // Serves as a catch-all element for any text or radio/checkbox input you wish
45 | // to prepend or append to an input.
46 |
47 | .input-group-text {
48 | display: flex;
49 | align-items: center;
50 | padding: $input-group-addon-padding-y $input-group-addon-padding-x;
51 | @include font-size($input-font-size); // Match inputs
52 | font-weight: $input-group-addon-font-weight;
53 | line-height: $input-line-height;
54 | color: $input-group-addon-color;
55 | text-align: center;
56 | white-space: nowrap;
57 | background-color: $input-group-addon-bg;
58 | border: $input-border-width solid $input-group-addon-border-color;
59 | @include border-radius($input-border-radius);
60 | }
61 |
62 |
63 | // Sizing
64 | //
65 | // Remix the default form control sizing classes into new ones for easier
66 | // manipulation.
67 |
68 | .input-group-lg > .form-control,
69 | .input-group-lg > .form-select,
70 | .input-group-lg > .input-group-text,
71 | .input-group-lg > .btn {
72 | padding: $input-padding-y-lg $input-padding-x-lg;
73 | @include font-size($input-font-size-lg);
74 | @include border-radius($input-border-radius-lg);
75 | }
76 |
77 | .input-group-sm > .form-control,
78 | .input-group-sm > .form-select,
79 | .input-group-sm > .input-group-text,
80 | .input-group-sm > .btn {
81 | padding: $input-padding-y-sm $input-padding-x-sm;
82 | @include font-size($input-font-size-sm);
83 | @include border-radius($input-border-radius-sm);
84 | }
85 |
86 | .input-group-lg > .form-select,
87 | .input-group-sm > .form-select {
88 | padding-right: $form-select-padding-x + $form-select-indicator-padding;
89 | }
90 |
91 |
92 | // Rounded corners
93 | //
94 | // These rulesets must come after the sizing ones to properly override sm and lg
95 | // border-radius values when extending. They're more specific than we'd like
96 | // with the `.input-group >` part, but without it, we cannot override the sizing.
97 |
98 | // stylelint-disable-next-line no-duplicate-selectors
99 | .input-group {
100 | &:not(.has-validation) {
101 | > :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
102 | > .dropdown-toggle:nth-last-child(n + 3),
103 | > .form-floating:not(:last-child) > .form-control,
104 | > .form-floating:not(:last-child) > .form-select {
105 | @include border-end-radius(0);
106 | }
107 | }
108 |
109 | &.has-validation {
110 | > :nth-last-child(n + 3):not(.dropdown-toggle):not(.dropdown-menu):not(.form-floating),
111 | > .dropdown-toggle:nth-last-child(n + 4),
112 | > .form-floating:nth-last-child(n + 3) > .form-control,
113 | > .form-floating:nth-last-child(n + 3) > .form-select {
114 | @include border-end-radius(0);
115 | }
116 | }
117 |
118 | $validation-messages: "";
119 | @each $state in map-keys($form-validation-states) {
120 | $validation-messages: $validation-messages + ":not(." + unquote($state) + "-tooltip)" + ":not(." + unquote($state) + "-feedback)";
121 | }
122 |
123 | > :not(:first-child):not(.dropdown-menu)#{$validation-messages} {
124 | margin-left: calc(-1 * #{$input-border-width}); // stylelint-disable-line function-disallowed-list
125 | @include border-start-radius(0);
126 | }
127 |
128 | > .form-floating:not(:first-child) > .form-control,
129 | > .form-floating:not(:first-child) > .form-select {
130 | @include border-start-radius(0);
131 | }
132 | }
133 |
--------------------------------------------------------------------------------
/assets/stylesheets/bootstrap/forms/_labels.scss:
--------------------------------------------------------------------------------
1 | //
2 | // Labels
3 | //
4 |
5 | .form-label {
6 | margin-bottom: $form-label-margin-bottom;
7 | @include font-size($form-label-font-size);
8 | font-style: $form-label-font-style;
9 | font-weight: $form-label-font-weight;
10 | color: $form-label-color;
11 | }
12 |
13 | // For use with horizontal and inline forms, when you need the label (or legend)
14 | // text to align with the form controls.
15 | .col-form-label {
16 | padding-top: add($input-padding-y, $input-border-width);
17 | padding-bottom: add($input-padding-y, $input-border-width);
18 | margin-bottom: 0; // Override the `