瀏覽代碼

Upgrade to Bootstrap 5.3.2 (#596)

Fixes #594
Vince Salvino 1 年之前
父節點
當前提交
8aca72d12d
共有 100 個文件被更改,包括 7519 次插入4721 次删除
  1. 3 3
      coderedcms/project_template/sass/website/static/website/src/_variables.scss
  2. 1 2
      coderedcms/static/coderedcms/vendor/bootstrap/LICENSE
  3. 1 1
      coderedcms/static/coderedcms/vendor/bootstrap/README.txt
  4. 105 144
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.css
  5. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.css.map
  6. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.min.css
  7. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.min.css.map
  8. 105 144
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.css
  9. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.css.map
  10. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.min.css
  11. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map
  12. 125 16
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.css
  13. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.css.map
  14. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.min.css
  15. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.min.css.map
  16. 125 16
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.css
  17. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.css.map
  18. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.min.css
  19. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map
  20. 741 44
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.css
  21. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.css.map
  22. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.min.css
  23. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.min.css.map
  24. 741 44
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.css
  25. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.css.map
  26. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.min.css
  27. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map
  28. 277 149
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.css
  29. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.css.map
  30. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.min.css
  31. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.min.css.map
  32. 277 149
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.css
  33. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.css.map
  34. 2 3
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.min.css
  35. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.min.css.map
  36. 208 269
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.js
  37. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.js.map
  38. 2 2
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.min.js
  39. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.min.js.map
  40. 208 269
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.js
  41. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.js.map
  42. 2 2
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.min.js
  43. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.min.js.map
  44. 210 272
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.js
  45. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.js.map
  46. 2 2
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.min.js
  47. 0 0
      coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.min.js.map
  48. 30 116
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/alert.js
  49. 85 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/base-component.js
  50. 20 157
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/button.js
  51. 252 391
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/carousel.js
  52. 128 223
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/collapse.js
  53. 55 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/data.js
  54. 317 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/event-handler.js
  55. 71 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/manipulator.js
  56. 126 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/selector-engine.js
  57. 250 333
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/dropdown.js
  58. 0 34
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/index.js
  59. 185 438
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/modal.js
  60. 282 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/offcanvas.js
  61. 33 118
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/popover.js
  62. 182 212
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/scrollspy.js
  63. 210 150
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/tab.js
  64. 95 100
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/toast.js
  65. 0 127
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/tools/sanitizer.js
  66. 340 447
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/tooltip.js
  67. 0 198
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util.js
  68. 149 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/backdrop.js
  69. 35 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/component-functions.js
  70. 65 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/config.js
  71. 115 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/focustrap.js
  72. 306 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/index.js
  73. 114 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/sanitizer.js
  74. 114 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/scrollbar.js
  75. 146 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/swipe.js
  76. 160 0
      coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/template-factory.js
  77. 16 4
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_accordion.scss
  78. 8 11
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_alert.scss
  79. 3 3
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_button-group.scss
  80. 31 10
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_buttons.scss
  81. 5 0
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_card.scss
  82. 20 5
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_carousel.scss
  83. 32 9
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_close.scss
  84. 3 1
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_dropdown.scss
  85. 3 3
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_functions.scss
  86. 6 0
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_grid.scss
  87. 2 0
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_helpers.scss
  88. 18 12
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_list-group.scss
  89. 120 0
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_maps.scss
  90. 1 2
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_mixins.scss
  91. 1 1
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_modal.scss
  92. 44 19
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_nav.scss
  93. 17 4
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_navbar.scss
  94. 9 6
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_offcanvas.scss
  95. 1 1
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_pagination.scss
  96. 5 5
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_popover.scss
  97. 10 1
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_progress.scss
  98. 8 7
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_reboot.scss
  99. 124 10
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_root.scss
  100. 18 11
      coderedcms/static/coderedcms/vendor/bootstrap/scss/_tables.scss

+ 3 - 3
coderedcms/project_template/sass/website/static/website/src/_variables.scss

@@ -3,10 +3,10 @@
 /// Uncomment and change, or add more variables here to match your brand.
 ///
 /// All variables can be found here:
-///   https://github.com/twbs/bootstrap/blob/v5.2.0/scss/_variables.scss
+///   https://github.com/twbs/bootstrap/blob/v5.3.2/scss/_variables.scss
 ///
 /// Bootstrap themeing guide can be found here:
-///   https://getbootstrap.com/docs/5.2/customize/overview/
+///   https://getbootstrap.com/docs/5.3/customize/overview/
 
 
 /// Color system
@@ -17,7 +17,7 @@
 ///
 ///     $primary: #00ff00
 ///
-/// See: https://getbootstrap.com/docs/5.2/customize/color/
+/// See: https://getbootstrap.com/docs/5.3/customize/color/
 
 // $primary:       $blue;
 // $secondary:     $gray-600;

+ 1 - 2
coderedcms/static/coderedcms/vendor/bootstrap/LICENSE

@@ -1,7 +1,6 @@
 The MIT License (MIT)
 
-Copyright (c) 2011-2022 Twitter, Inc.
-Copyright (c) 2011-2022 The Bootstrap Authors
+Copyright (c) 2011-2023 The Bootstrap Authors
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal

+ 1 - 1
coderedcms/static/coderedcms/vendor/bootstrap/README.txt

@@ -1,2 +1,2 @@
-Minimal redistribution of Bootstrap 5.2.0 for Wagtail CRX.
+Minimal redistribution of Bootstrap 5.3.2 for Wagtail CRX.
 Full source and documentation available at: https://getbootstrap.com/.

+ 105 - 144
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.css

@@ -1,78 +1,8 @@
 /*!
- * Bootstrap Grid v5.2.0 (https://getbootstrap.com/)
- * Copyright 2011-2022 The Bootstrap Authors
- * Copyright 2011-2022 Twitter, Inc.
+ * Bootstrap Grid v5.3.2 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  */
-:root {
-  --bs-blue: #0d6efd;
-  --bs-indigo: #6610f2;
-  --bs-purple: #6f42c1;
-  --bs-pink: #d63384;
-  --bs-red: #dc3545;
-  --bs-orange: #fd7e14;
-  --bs-yellow: #ffc107;
-  --bs-green: #198754;
-  --bs-teal: #20c997;
-  --bs-cyan: #0dcaf0;
-  --bs-black: #000;
-  --bs-white: #fff;
-  --bs-gray: #6c757d;
-  --bs-gray-dark: #343a40;
-  --bs-gray-100: #f8f9fa;
-  --bs-gray-200: #e9ecef;
-  --bs-gray-300: #dee2e6;
-  --bs-gray-400: #ced4da;
-  --bs-gray-500: #adb5bd;
-  --bs-gray-600: #6c757d;
-  --bs-gray-700: #495057;
-  --bs-gray-800: #343a40;
-  --bs-gray-900: #212529;
-  --bs-primary: #0d6efd;
-  --bs-secondary: #6c757d;
-  --bs-success: #198754;
-  --bs-info: #0dcaf0;
-  --bs-warning: #ffc107;
-  --bs-danger: #dc3545;
-  --bs-light: #f8f9fa;
-  --bs-dark: #212529;
-  --bs-primary-rgb: 13, 110, 253;
-  --bs-secondary-rgb: 108, 117, 125;
-  --bs-success-rgb: 25, 135, 84;
-  --bs-info-rgb: 13, 202, 240;
-  --bs-warning-rgb: 255, 193, 7;
-  --bs-danger-rgb: 220, 53, 69;
-  --bs-light-rgb: 248, 249, 250;
-  --bs-dark-rgb: 33, 37, 41;
-  --bs-white-rgb: 255, 255, 255;
-  --bs-black-rgb: 0, 0, 0;
-  --bs-body-color-rgb: 33, 37, 41;
-  --bs-body-bg-rgb: 255, 255, 255;
-  --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-  --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
-  --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
-  --bs-body-font-family: var(--bs-font-sans-serif);
-  --bs-body-font-size: 1rem;
-  --bs-body-font-weight: 400;
-  --bs-body-line-height: 1.5;
-  --bs-body-color: #212529;
-  --bs-body-bg: #fff;
-  --bs-border-width: 1px;
-  --bs-border-style: solid;
-  --bs-border-color: #dee2e6;
-  --bs-border-color-translucent: rgba(0, 0, 0, 0.175);
-  --bs-border-radius: 0.375rem;
-  --bs-border-radius-sm: 0.25rem;
-  --bs-border-radius-lg: 0.5rem;
-  --bs-border-radius-xl: 1rem;
-  --bs-border-radius-2xl: 2rem;
-  --bs-border-radius-pill: 50rem;
-  --bs-link-color: #0d6efd;
-  --bs-link-hover-color: #0a58ca;
-  --bs-code-color: #d63384;
-  --bs-highlight-bg: #fff3cd;
-}
-
 .container,
 .container-fluid,
 .container-xxl,
@@ -114,6 +44,15 @@
     max-width: 1320px;
   }
 }
+:root {
+  --bs-breakpoint-xs: 0;
+  --bs-breakpoint-sm: 576px;
+  --bs-breakpoint-md: 768px;
+  --bs-breakpoint-lg: 992px;
+  --bs-breakpoint-xl: 1200px;
+  --bs-breakpoint-xxl: 1400px;
+}
+
 .row {
   --bs-gutter-x: 1.5rem;
   --bs-gutter-y: 0;
@@ -154,7 +93,7 @@
 
 .row-cols-3 > * {
   flex: 0 0 auto;
-  width: 33.3333333333%;
+  width: 33.33333333%;
 }
 
 .row-cols-4 > * {
@@ -169,7 +108,7 @@
 
 .row-cols-6 > * {
   flex: 0 0 auto;
-  width: 16.6666666667%;
+  width: 16.66666667%;
 }
 
 .col-auto {
@@ -359,7 +298,7 @@
   }
   .row-cols-sm-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-sm-4 > * {
     flex: 0 0 auto;
@@ -371,7 +310,7 @@
   }
   .row-cols-sm-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-sm-auto {
     flex: 0 0 auto;
@@ -462,51 +401,51 @@
     margin-left: 91.66666667%;
   }
   .g-sm-0,
-.gx-sm-0 {
+  .gx-sm-0 {
     --bs-gutter-x: 0;
   }
   .g-sm-0,
-.gy-sm-0 {
+  .gy-sm-0 {
     --bs-gutter-y: 0;
   }
   .g-sm-1,
-.gx-sm-1 {
+  .gx-sm-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-sm-1,
-.gy-sm-1 {
+  .gy-sm-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-sm-2,
-.gx-sm-2 {
+  .gx-sm-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-sm-2,
-.gy-sm-2 {
+  .gy-sm-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-sm-3,
-.gx-sm-3 {
+  .gx-sm-3 {
     --bs-gutter-x: 1rem;
   }
   .g-sm-3,
-.gy-sm-3 {
+  .gy-sm-3 {
     --bs-gutter-y: 1rem;
   }
   .g-sm-4,
-.gx-sm-4 {
+  .gx-sm-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-sm-4,
-.gy-sm-4 {
+  .gy-sm-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-sm-5,
-.gx-sm-5 {
+  .gx-sm-5 {
     --bs-gutter-x: 3rem;
   }
   .g-sm-5,
-.gy-sm-5 {
+  .gy-sm-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -528,7 +467,7 @@
   }
   .row-cols-md-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-md-4 > * {
     flex: 0 0 auto;
@@ -540,7 +479,7 @@
   }
   .row-cols-md-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-md-auto {
     flex: 0 0 auto;
@@ -631,51 +570,51 @@
     margin-left: 91.66666667%;
   }
   .g-md-0,
-.gx-md-0 {
+  .gx-md-0 {
     --bs-gutter-x: 0;
   }
   .g-md-0,
-.gy-md-0 {
+  .gy-md-0 {
     --bs-gutter-y: 0;
   }
   .g-md-1,
-.gx-md-1 {
+  .gx-md-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-md-1,
-.gy-md-1 {
+  .gy-md-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-md-2,
-.gx-md-2 {
+  .gx-md-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-md-2,
-.gy-md-2 {
+  .gy-md-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-md-3,
-.gx-md-3 {
+  .gx-md-3 {
     --bs-gutter-x: 1rem;
   }
   .g-md-3,
-.gy-md-3 {
+  .gy-md-3 {
     --bs-gutter-y: 1rem;
   }
   .g-md-4,
-.gx-md-4 {
+  .gx-md-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-md-4,
-.gy-md-4 {
+  .gy-md-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-md-5,
-.gx-md-5 {
+  .gx-md-5 {
     --bs-gutter-x: 3rem;
   }
   .g-md-5,
-.gy-md-5 {
+  .gy-md-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -697,7 +636,7 @@
   }
   .row-cols-lg-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-lg-4 > * {
     flex: 0 0 auto;
@@ -709,7 +648,7 @@
   }
   .row-cols-lg-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-lg-auto {
     flex: 0 0 auto;
@@ -800,51 +739,51 @@
     margin-left: 91.66666667%;
   }
   .g-lg-0,
-.gx-lg-0 {
+  .gx-lg-0 {
     --bs-gutter-x: 0;
   }
   .g-lg-0,
-.gy-lg-0 {
+  .gy-lg-0 {
     --bs-gutter-y: 0;
   }
   .g-lg-1,
-.gx-lg-1 {
+  .gx-lg-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-lg-1,
-.gy-lg-1 {
+  .gy-lg-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-lg-2,
-.gx-lg-2 {
+  .gx-lg-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-lg-2,
-.gy-lg-2 {
+  .gy-lg-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-lg-3,
-.gx-lg-3 {
+  .gx-lg-3 {
     --bs-gutter-x: 1rem;
   }
   .g-lg-3,
-.gy-lg-3 {
+  .gy-lg-3 {
     --bs-gutter-y: 1rem;
   }
   .g-lg-4,
-.gx-lg-4 {
+  .gx-lg-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-lg-4,
-.gy-lg-4 {
+  .gy-lg-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-lg-5,
-.gx-lg-5 {
+  .gx-lg-5 {
     --bs-gutter-x: 3rem;
   }
   .g-lg-5,
-.gy-lg-5 {
+  .gy-lg-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -866,7 +805,7 @@
   }
   .row-cols-xl-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-xl-4 > * {
     flex: 0 0 auto;
@@ -878,7 +817,7 @@
   }
   .row-cols-xl-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-xl-auto {
     flex: 0 0 auto;
@@ -969,51 +908,51 @@
     margin-left: 91.66666667%;
   }
   .g-xl-0,
-.gx-xl-0 {
+  .gx-xl-0 {
     --bs-gutter-x: 0;
   }
   .g-xl-0,
-.gy-xl-0 {
+  .gy-xl-0 {
     --bs-gutter-y: 0;
   }
   .g-xl-1,
-.gx-xl-1 {
+  .gx-xl-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-xl-1,
-.gy-xl-1 {
+  .gy-xl-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-xl-2,
-.gx-xl-2 {
+  .gx-xl-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-xl-2,
-.gy-xl-2 {
+  .gy-xl-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-xl-3,
-.gx-xl-3 {
+  .gx-xl-3 {
     --bs-gutter-x: 1rem;
   }
   .g-xl-3,
-.gy-xl-3 {
+  .gy-xl-3 {
     --bs-gutter-y: 1rem;
   }
   .g-xl-4,
-.gx-xl-4 {
+  .gx-xl-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-xl-4,
-.gy-xl-4 {
+  .gy-xl-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-xl-5,
-.gx-xl-5 {
+  .gx-xl-5 {
     --bs-gutter-x: 3rem;
   }
   .g-xl-5,
-.gy-xl-5 {
+  .gy-xl-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -1035,7 +974,7 @@
   }
   .row-cols-xxl-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-xxl-4 > * {
     flex: 0 0 auto;
@@ -1047,7 +986,7 @@
   }
   .row-cols-xxl-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-xxl-auto {
     flex: 0 0 auto;
@@ -1138,51 +1077,51 @@
     margin-left: 91.66666667%;
   }
   .g-xxl-0,
-.gx-xxl-0 {
+  .gx-xxl-0 {
     --bs-gutter-x: 0;
   }
   .g-xxl-0,
-.gy-xxl-0 {
+  .gy-xxl-0 {
     --bs-gutter-y: 0;
   }
   .g-xxl-1,
-.gx-xxl-1 {
+  .gx-xxl-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-xxl-1,
-.gy-xxl-1 {
+  .gy-xxl-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-xxl-2,
-.gx-xxl-2 {
+  .gx-xxl-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-xxl-2,
-.gy-xxl-2 {
+  .gy-xxl-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-xxl-3,
-.gx-xxl-3 {
+  .gx-xxl-3 {
     --bs-gutter-x: 1rem;
   }
   .g-xxl-3,
-.gy-xxl-3 {
+  .gy-xxl-3 {
     --bs-gutter-y: 1rem;
   }
   .g-xxl-4,
-.gx-xxl-4 {
+  .gx-xxl-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-xxl-4,
-.gy-xxl-4 {
+  .gy-xxl-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-xxl-5,
-.gx-xxl-5 {
+  .gx-xxl-5 {
     --bs-gutter-x: 3rem;
   }
   .g-xxl-5,
-.gy-xxl-5 {
+  .gy-xxl-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -1202,6 +1141,10 @@
   display: grid !important;
 }
 
+.d-inline-grid {
+  display: inline-grid !important;
+}
+
 .d-table {
   display: table !important;
 }
@@ -1801,6 +1744,9 @@
   .d-sm-grid {
     display: grid !important;
   }
+  .d-sm-inline-grid {
+    display: inline-grid !important;
+  }
   .d-sm-table {
     display: table !important;
   }
@@ -2261,6 +2207,9 @@
   .d-md-grid {
     display: grid !important;
   }
+  .d-md-inline-grid {
+    display: inline-grid !important;
+  }
   .d-md-table {
     display: table !important;
   }
@@ -2721,6 +2670,9 @@
   .d-lg-grid {
     display: grid !important;
   }
+  .d-lg-inline-grid {
+    display: inline-grid !important;
+  }
   .d-lg-table {
     display: table !important;
   }
@@ -3181,6 +3133,9 @@
   .d-xl-grid {
     display: grid !important;
   }
+  .d-xl-inline-grid {
+    display: inline-grid !important;
+  }
   .d-xl-table {
     display: table !important;
   }
@@ -3641,6 +3596,9 @@
   .d-xxl-grid {
     display: grid !important;
   }
+  .d-xxl-inline-grid {
+    display: inline-grid !important;
+  }
   .d-xxl-table {
     display: table !important;
   }
@@ -4101,6 +4059,9 @@
   .d-print-grid {
     display: grid !important;
   }
+  .d-print-inline-grid {
+    display: inline-grid !important;
+  }
   .d-print-table {
     display: table !important;
   }

文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.min.css.map


+ 105 - 144
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.css

@@ -1,78 +1,8 @@
 /*!
- * Bootstrap Grid v5.2.0 (https://getbootstrap.com/)
- * Copyright 2011-2022 The Bootstrap Authors
- * Copyright 2011-2022 Twitter, Inc.
+ * Bootstrap Grid v5.3.2 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  */
-:root {
-  --bs-blue: #0d6efd;
-  --bs-indigo: #6610f2;
-  --bs-purple: #6f42c1;
-  --bs-pink: #d63384;
-  --bs-red: #dc3545;
-  --bs-orange: #fd7e14;
-  --bs-yellow: #ffc107;
-  --bs-green: #198754;
-  --bs-teal: #20c997;
-  --bs-cyan: #0dcaf0;
-  --bs-black: #000;
-  --bs-white: #fff;
-  --bs-gray: #6c757d;
-  --bs-gray-dark: #343a40;
-  --bs-gray-100: #f8f9fa;
-  --bs-gray-200: #e9ecef;
-  --bs-gray-300: #dee2e6;
-  --bs-gray-400: #ced4da;
-  --bs-gray-500: #adb5bd;
-  --bs-gray-600: #6c757d;
-  --bs-gray-700: #495057;
-  --bs-gray-800: #343a40;
-  --bs-gray-900: #212529;
-  --bs-primary: #0d6efd;
-  --bs-secondary: #6c757d;
-  --bs-success: #198754;
-  --bs-info: #0dcaf0;
-  --bs-warning: #ffc107;
-  --bs-danger: #dc3545;
-  --bs-light: #f8f9fa;
-  --bs-dark: #212529;
-  --bs-primary-rgb: 13, 110, 253;
-  --bs-secondary-rgb: 108, 117, 125;
-  --bs-success-rgb: 25, 135, 84;
-  --bs-info-rgb: 13, 202, 240;
-  --bs-warning-rgb: 255, 193, 7;
-  --bs-danger-rgb: 220, 53, 69;
-  --bs-light-rgb: 248, 249, 250;
-  --bs-dark-rgb: 33, 37, 41;
-  --bs-white-rgb: 255, 255, 255;
-  --bs-black-rgb: 0, 0, 0;
-  --bs-body-color-rgb: 33, 37, 41;
-  --bs-body-bg-rgb: 255, 255, 255;
-  --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
-  --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
-  --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
-  --bs-body-font-family: var(--bs-font-sans-serif);
-  --bs-body-font-size: 1rem;
-  --bs-body-font-weight: 400;
-  --bs-body-line-height: 1.5;
-  --bs-body-color: #212529;
-  --bs-body-bg: #fff;
-  --bs-border-width: 1px;
-  --bs-border-style: solid;
-  --bs-border-color: #dee2e6;
-  --bs-border-color-translucent: rgba(0, 0, 0, 0.175);
-  --bs-border-radius: 0.375rem;
-  --bs-border-radius-sm: 0.25rem;
-  --bs-border-radius-lg: 0.5rem;
-  --bs-border-radius-xl: 1rem;
-  --bs-border-radius-2xl: 2rem;
-  --bs-border-radius-pill: 50rem;
-  --bs-link-color: #0d6efd;
-  --bs-link-hover-color: #0a58ca;
-  --bs-code-color: #d63384;
-  --bs-highlight-bg: #fff3cd;
-}
-
 .container,
 .container-fluid,
 .container-xxl,
@@ -114,6 +44,15 @@
     max-width: 1320px;
   }
 }
+:root {
+  --bs-breakpoint-xs: 0;
+  --bs-breakpoint-sm: 576px;
+  --bs-breakpoint-md: 768px;
+  --bs-breakpoint-lg: 992px;
+  --bs-breakpoint-xl: 1200px;
+  --bs-breakpoint-xxl: 1400px;
+}
+
 .row {
   --bs-gutter-x: 1.5rem;
   --bs-gutter-y: 0;
@@ -154,7 +93,7 @@
 
 .row-cols-3 > * {
   flex: 0 0 auto;
-  width: 33.3333333333%;
+  width: 33.33333333%;
 }
 
 .row-cols-4 > * {
@@ -169,7 +108,7 @@
 
 .row-cols-6 > * {
   flex: 0 0 auto;
-  width: 16.6666666667%;
+  width: 16.66666667%;
 }
 
 .col-auto {
@@ -359,7 +298,7 @@
   }
   .row-cols-sm-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-sm-4 > * {
     flex: 0 0 auto;
@@ -371,7 +310,7 @@
   }
   .row-cols-sm-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-sm-auto {
     flex: 0 0 auto;
@@ -462,51 +401,51 @@
     margin-right: 91.66666667%;
   }
   .g-sm-0,
-.gx-sm-0 {
+  .gx-sm-0 {
     --bs-gutter-x: 0;
   }
   .g-sm-0,
-.gy-sm-0 {
+  .gy-sm-0 {
     --bs-gutter-y: 0;
   }
   .g-sm-1,
-.gx-sm-1 {
+  .gx-sm-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-sm-1,
-.gy-sm-1 {
+  .gy-sm-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-sm-2,
-.gx-sm-2 {
+  .gx-sm-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-sm-2,
-.gy-sm-2 {
+  .gy-sm-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-sm-3,
-.gx-sm-3 {
+  .gx-sm-3 {
     --bs-gutter-x: 1rem;
   }
   .g-sm-3,
-.gy-sm-3 {
+  .gy-sm-3 {
     --bs-gutter-y: 1rem;
   }
   .g-sm-4,
-.gx-sm-4 {
+  .gx-sm-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-sm-4,
-.gy-sm-4 {
+  .gy-sm-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-sm-5,
-.gx-sm-5 {
+  .gx-sm-5 {
     --bs-gutter-x: 3rem;
   }
   .g-sm-5,
-.gy-sm-5 {
+  .gy-sm-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -528,7 +467,7 @@
   }
   .row-cols-md-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-md-4 > * {
     flex: 0 0 auto;
@@ -540,7 +479,7 @@
   }
   .row-cols-md-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-md-auto {
     flex: 0 0 auto;
@@ -631,51 +570,51 @@
     margin-right: 91.66666667%;
   }
   .g-md-0,
-.gx-md-0 {
+  .gx-md-0 {
     --bs-gutter-x: 0;
   }
   .g-md-0,
-.gy-md-0 {
+  .gy-md-0 {
     --bs-gutter-y: 0;
   }
   .g-md-1,
-.gx-md-1 {
+  .gx-md-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-md-1,
-.gy-md-1 {
+  .gy-md-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-md-2,
-.gx-md-2 {
+  .gx-md-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-md-2,
-.gy-md-2 {
+  .gy-md-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-md-3,
-.gx-md-3 {
+  .gx-md-3 {
     --bs-gutter-x: 1rem;
   }
   .g-md-3,
-.gy-md-3 {
+  .gy-md-3 {
     --bs-gutter-y: 1rem;
   }
   .g-md-4,
-.gx-md-4 {
+  .gx-md-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-md-4,
-.gy-md-4 {
+  .gy-md-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-md-5,
-.gx-md-5 {
+  .gx-md-5 {
     --bs-gutter-x: 3rem;
   }
   .g-md-5,
-.gy-md-5 {
+  .gy-md-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -697,7 +636,7 @@
   }
   .row-cols-lg-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-lg-4 > * {
     flex: 0 0 auto;
@@ -709,7 +648,7 @@
   }
   .row-cols-lg-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-lg-auto {
     flex: 0 0 auto;
@@ -800,51 +739,51 @@
     margin-right: 91.66666667%;
   }
   .g-lg-0,
-.gx-lg-0 {
+  .gx-lg-0 {
     --bs-gutter-x: 0;
   }
   .g-lg-0,
-.gy-lg-0 {
+  .gy-lg-0 {
     --bs-gutter-y: 0;
   }
   .g-lg-1,
-.gx-lg-1 {
+  .gx-lg-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-lg-1,
-.gy-lg-1 {
+  .gy-lg-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-lg-2,
-.gx-lg-2 {
+  .gx-lg-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-lg-2,
-.gy-lg-2 {
+  .gy-lg-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-lg-3,
-.gx-lg-3 {
+  .gx-lg-3 {
     --bs-gutter-x: 1rem;
   }
   .g-lg-3,
-.gy-lg-3 {
+  .gy-lg-3 {
     --bs-gutter-y: 1rem;
   }
   .g-lg-4,
-.gx-lg-4 {
+  .gx-lg-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-lg-4,
-.gy-lg-4 {
+  .gy-lg-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-lg-5,
-.gx-lg-5 {
+  .gx-lg-5 {
     --bs-gutter-x: 3rem;
   }
   .g-lg-5,
-.gy-lg-5 {
+  .gy-lg-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -866,7 +805,7 @@
   }
   .row-cols-xl-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-xl-4 > * {
     flex: 0 0 auto;
@@ -878,7 +817,7 @@
   }
   .row-cols-xl-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-xl-auto {
     flex: 0 0 auto;
@@ -969,51 +908,51 @@
     margin-right: 91.66666667%;
   }
   .g-xl-0,
-.gx-xl-0 {
+  .gx-xl-0 {
     --bs-gutter-x: 0;
   }
   .g-xl-0,
-.gy-xl-0 {
+  .gy-xl-0 {
     --bs-gutter-y: 0;
   }
   .g-xl-1,
-.gx-xl-1 {
+  .gx-xl-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-xl-1,
-.gy-xl-1 {
+  .gy-xl-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-xl-2,
-.gx-xl-2 {
+  .gx-xl-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-xl-2,
-.gy-xl-2 {
+  .gy-xl-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-xl-3,
-.gx-xl-3 {
+  .gx-xl-3 {
     --bs-gutter-x: 1rem;
   }
   .g-xl-3,
-.gy-xl-3 {
+  .gy-xl-3 {
     --bs-gutter-y: 1rem;
   }
   .g-xl-4,
-.gx-xl-4 {
+  .gx-xl-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-xl-4,
-.gy-xl-4 {
+  .gy-xl-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-xl-5,
-.gx-xl-5 {
+  .gx-xl-5 {
     --bs-gutter-x: 3rem;
   }
   .g-xl-5,
-.gy-xl-5 {
+  .gy-xl-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -1035,7 +974,7 @@
   }
   .row-cols-xxl-3 > * {
     flex: 0 0 auto;
-    width: 33.3333333333%;
+    width: 33.33333333%;
   }
   .row-cols-xxl-4 > * {
     flex: 0 0 auto;
@@ -1047,7 +986,7 @@
   }
   .row-cols-xxl-6 > * {
     flex: 0 0 auto;
-    width: 16.6666666667%;
+    width: 16.66666667%;
   }
   .col-xxl-auto {
     flex: 0 0 auto;
@@ -1138,51 +1077,51 @@
     margin-right: 91.66666667%;
   }
   .g-xxl-0,
-.gx-xxl-0 {
+  .gx-xxl-0 {
     --bs-gutter-x: 0;
   }
   .g-xxl-0,
-.gy-xxl-0 {
+  .gy-xxl-0 {
     --bs-gutter-y: 0;
   }
   .g-xxl-1,
-.gx-xxl-1 {
+  .gx-xxl-1 {
     --bs-gutter-x: 0.25rem;
   }
   .g-xxl-1,
-.gy-xxl-1 {
+  .gy-xxl-1 {
     --bs-gutter-y: 0.25rem;
   }
   .g-xxl-2,
-.gx-xxl-2 {
+  .gx-xxl-2 {
     --bs-gutter-x: 0.5rem;
   }
   .g-xxl-2,
-.gy-xxl-2 {
+  .gy-xxl-2 {
     --bs-gutter-y: 0.5rem;
   }
   .g-xxl-3,
-.gx-xxl-3 {
+  .gx-xxl-3 {
     --bs-gutter-x: 1rem;
   }
   .g-xxl-3,
-.gy-xxl-3 {
+  .gy-xxl-3 {
     --bs-gutter-y: 1rem;
   }
   .g-xxl-4,
-.gx-xxl-4 {
+  .gx-xxl-4 {
     --bs-gutter-x: 1.5rem;
   }
   .g-xxl-4,
-.gy-xxl-4 {
+  .gy-xxl-4 {
     --bs-gutter-y: 1.5rem;
   }
   .g-xxl-5,
-.gx-xxl-5 {
+  .gx-xxl-5 {
     --bs-gutter-x: 3rem;
   }
   .g-xxl-5,
-.gy-xxl-5 {
+  .gy-xxl-5 {
     --bs-gutter-y: 3rem;
   }
 }
@@ -1202,6 +1141,10 @@
   display: grid !important;
 }
 
+.d-inline-grid {
+  display: inline-grid !important;
+}
+
 .d-table {
   display: table !important;
 }
@@ -1801,6 +1744,9 @@
   .d-sm-grid {
     display: grid !important;
   }
+  .d-sm-inline-grid {
+    display: inline-grid !important;
+  }
   .d-sm-table {
     display: table !important;
   }
@@ -2261,6 +2207,9 @@
   .d-md-grid {
     display: grid !important;
   }
+  .d-md-inline-grid {
+    display: inline-grid !important;
+  }
   .d-md-table {
     display: table !important;
   }
@@ -2721,6 +2670,9 @@
   .d-lg-grid {
     display: grid !important;
   }
+  .d-lg-inline-grid {
+    display: inline-grid !important;
+  }
   .d-lg-table {
     display: table !important;
   }
@@ -3181,6 +3133,9 @@
   .d-xl-grid {
     display: grid !important;
   }
+  .d-xl-inline-grid {
+    display: inline-grid !important;
+  }
   .d-xl-table {
     display: table !important;
   }
@@ -3641,6 +3596,9 @@
   .d-xxl-grid {
     display: grid !important;
   }
+  .d-xxl-inline-grid {
+    display: inline-grid !important;
+  }
   .d-xxl-table {
     display: table !important;
   }
@@ -4101,6 +4059,9 @@
   .d-print-grid {
     display: grid !important;
   }
+  .d-print-inline-grid {
+    display: inline-grid !important;
+  }
   .d-print-table {
     display: table !important;
   }

文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-grid.rtl.min.css.map


+ 125 - 16
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.css

@@ -1,10 +1,10 @@
 /*!
- * Bootstrap Reboot v5.2.0 (https://getbootstrap.com/)
- * Copyright 2011-2022 The Bootstrap Authors
- * Copyright 2011-2022 Twitter, Inc.
+ * Bootstrap Reboot v5.3.2 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  */
-:root {
+:root,
+[data-bs-theme=light] {
   --bs-blue: #0d6efd;
   --bs-indigo: #6610f2;
   --bs-purple: #6f42c1;
@@ -44,10 +44,32 @@
   --bs-danger-rgb: 220, 53, 69;
   --bs-light-rgb: 248, 249, 250;
   --bs-dark-rgb: 33, 37, 41;
+  --bs-primary-text-emphasis: #052c65;
+  --bs-secondary-text-emphasis: #2b2f32;
+  --bs-success-text-emphasis: #0a3622;
+  --bs-info-text-emphasis: #055160;
+  --bs-warning-text-emphasis: #664d03;
+  --bs-danger-text-emphasis: #58151c;
+  --bs-light-text-emphasis: #495057;
+  --bs-dark-text-emphasis: #495057;
+  --bs-primary-bg-subtle: #cfe2ff;
+  --bs-secondary-bg-subtle: #e2e3e5;
+  --bs-success-bg-subtle: #d1e7dd;
+  --bs-info-bg-subtle: #cff4fc;
+  --bs-warning-bg-subtle: #fff3cd;
+  --bs-danger-bg-subtle: #f8d7da;
+  --bs-light-bg-subtle: #fcfcfd;
+  --bs-dark-bg-subtle: #ced4da;
+  --bs-primary-border-subtle: #9ec5fe;
+  --bs-secondary-border-subtle: #c4c8cb;
+  --bs-success-border-subtle: #a3cfbb;
+  --bs-info-border-subtle: #9eeaf9;
+  --bs-warning-border-subtle: #ffe69c;
+  --bs-danger-border-subtle: #f1aeb5;
+  --bs-light-border-subtle: #e9ecef;
+  --bs-dark-border-subtle: #adb5bd;
   --bs-white-rgb: 255, 255, 255;
   --bs-black-rgb: 0, 0, 0;
-  --bs-body-color-rgb: 33, 37, 41;
-  --bs-body-bg-rgb: 255, 255, 255;
   --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
   --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
   --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
@@ -56,7 +78,28 @@
   --bs-body-font-weight: 400;
   --bs-body-line-height: 1.5;
   --bs-body-color: #212529;
+  --bs-body-color-rgb: 33, 37, 41;
   --bs-body-bg: #fff;
+  --bs-body-bg-rgb: 255, 255, 255;
+  --bs-emphasis-color: #000;
+  --bs-emphasis-color-rgb: 0, 0, 0;
+  --bs-secondary-color: rgba(33, 37, 41, 0.75);
+  --bs-secondary-color-rgb: 33, 37, 41;
+  --bs-secondary-bg: #e9ecef;
+  --bs-secondary-bg-rgb: 233, 236, 239;
+  --bs-tertiary-color: rgba(33, 37, 41, 0.5);
+  --bs-tertiary-color-rgb: 33, 37, 41;
+  --bs-tertiary-bg: #f8f9fa;
+  --bs-tertiary-bg-rgb: 248, 249, 250;
+  --bs-heading-color: inherit;
+  --bs-link-color: #0d6efd;
+  --bs-link-color-rgb: 13, 110, 253;
+  --bs-link-decoration: underline;
+  --bs-link-hover-color: #0a58ca;
+  --bs-link-hover-color-rgb: 10, 88, 202;
+  --bs-code-color: #d63384;
+  --bs-highlight-color: #212529;
+  --bs-highlight-bg: #fff3cd;
   --bs-border-width: 1px;
   --bs-border-style: solid;
   --bs-border-color: #dee2e6;
@@ -65,12 +108,76 @@
   --bs-border-radius-sm: 0.25rem;
   --bs-border-radius-lg: 0.5rem;
   --bs-border-radius-xl: 1rem;
-  --bs-border-radius-2xl: 2rem;
+  --bs-border-radius-xxl: 2rem;
+  --bs-border-radius-2xl: var(--bs-border-radius-xxl);
   --bs-border-radius-pill: 50rem;
-  --bs-link-color: #0d6efd;
-  --bs-link-hover-color: #0a58ca;
-  --bs-code-color: #d63384;
-  --bs-highlight-bg: #fff3cd;
+  --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+  --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+  --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
+  --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
+  --bs-focus-ring-width: 0.25rem;
+  --bs-focus-ring-opacity: 0.25;
+  --bs-focus-ring-color: rgba(13, 110, 253, 0.25);
+  --bs-form-valid-color: #198754;
+  --bs-form-valid-border-color: #198754;
+  --bs-form-invalid-color: #dc3545;
+  --bs-form-invalid-border-color: #dc3545;
+}
+
+[data-bs-theme=dark] {
+  color-scheme: dark;
+  --bs-body-color: #dee2e6;
+  --bs-body-color-rgb: 222, 226, 230;
+  --bs-body-bg: #212529;
+  --bs-body-bg-rgb: 33, 37, 41;
+  --bs-emphasis-color: #fff;
+  --bs-emphasis-color-rgb: 255, 255, 255;
+  --bs-secondary-color: rgba(222, 226, 230, 0.75);
+  --bs-secondary-color-rgb: 222, 226, 230;
+  --bs-secondary-bg: #343a40;
+  --bs-secondary-bg-rgb: 52, 58, 64;
+  --bs-tertiary-color: rgba(222, 226, 230, 0.5);
+  --bs-tertiary-color-rgb: 222, 226, 230;
+  --bs-tertiary-bg: #2b3035;
+  --bs-tertiary-bg-rgb: 43, 48, 53;
+  --bs-primary-text-emphasis: #6ea8fe;
+  --bs-secondary-text-emphasis: #a7acb1;
+  --bs-success-text-emphasis: #75b798;
+  --bs-info-text-emphasis: #6edff6;
+  --bs-warning-text-emphasis: #ffda6a;
+  --bs-danger-text-emphasis: #ea868f;
+  --bs-light-text-emphasis: #f8f9fa;
+  --bs-dark-text-emphasis: #dee2e6;
+  --bs-primary-bg-subtle: #031633;
+  --bs-secondary-bg-subtle: #161719;
+  --bs-success-bg-subtle: #051b11;
+  --bs-info-bg-subtle: #032830;
+  --bs-warning-bg-subtle: #332701;
+  --bs-danger-bg-subtle: #2c0b0e;
+  --bs-light-bg-subtle: #343a40;
+  --bs-dark-bg-subtle: #1a1d20;
+  --bs-primary-border-subtle: #084298;
+  --bs-secondary-border-subtle: #41464b;
+  --bs-success-border-subtle: #0f5132;
+  --bs-info-border-subtle: #087990;
+  --bs-warning-border-subtle: #997404;
+  --bs-danger-border-subtle: #842029;
+  --bs-light-border-subtle: #495057;
+  --bs-dark-border-subtle: #343a40;
+  --bs-heading-color: inherit;
+  --bs-link-color: #6ea8fe;
+  --bs-link-hover-color: #8bb9fe;
+  --bs-link-color-rgb: 110, 168, 254;
+  --bs-link-hover-color-rgb: 139, 185, 254;
+  --bs-code-color: #e685b5;
+  --bs-highlight-color: #dee2e6;
+  --bs-highlight-bg: #664d03;
+  --bs-border-color: #495057;
+  --bs-border-color-translucent: rgba(255, 255, 255, 0.15);
+  --bs-form-valid-color: #75b798;
+  --bs-form-valid-border-color: #75b798;
+  --bs-form-invalid-color: #ea868f;
+  --bs-form-invalid-border-color: #ea868f;
 }
 
 *,
@@ -102,7 +209,7 @@ hr {
   margin: 1rem 0;
   color: inherit;
   border: 0;
-  border-top: 1px solid;
+  border-top: var(--bs-border-width) solid;
   opacity: 0.25;
 }
 
@@ -111,6 +218,7 @@ h6, h5, h4, h3, h2, h1 {
   margin-bottom: 0.5rem;
   font-weight: 500;
   line-height: 1.2;
+  color: var(--bs-heading-color);
 }
 
 h1 {
@@ -219,6 +327,7 @@ small {
 
 mark {
   padding: 0.1875em;
+  color: var(--bs-highlight-color);
   background-color: var(--bs-highlight-bg);
 }
 
@@ -239,11 +348,11 @@ sup {
 }
 
 a {
-  color: var(--bs-link-color);
+  color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
   text-decoration: underline;
 }
 a:hover {
-  color: var(--bs-link-hover-color);
+  --bs-link-color-rgb: var(--bs-link-hover-color-rgb);
 }
 
 a:not([href]):not([class]), a:not([href]):not([class]):hover {
@@ -310,7 +419,7 @@ table {
 caption {
   padding-top: 0.5rem;
   padding-bottom: 0.5rem;
-  color: #6c757d;
+  color: var(--bs-secondary-color);
   text-align: left;
 }
 
@@ -434,8 +543,8 @@ legend + * {
 }
 
 [type=search] {
-  outline-offset: -2px;
   -webkit-appearance: textfield;
+  outline-offset: -2px;
 }
 
 /* rtl:raw:

文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.min.css.map


+ 125 - 16
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.css

@@ -1,10 +1,10 @@
 /*!
- * Bootstrap Reboot v5.2.0 (https://getbootstrap.com/)
- * Copyright 2011-2022 The Bootstrap Authors
- * Copyright 2011-2022 Twitter, Inc.
+ * Bootstrap Reboot v5.3.2 (https://getbootstrap.com/)
+ * Copyright 2011-2023 The Bootstrap Authors
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  */
-:root {
+:root,
+[data-bs-theme=light] {
   --bs-blue: #0d6efd;
   --bs-indigo: #6610f2;
   --bs-purple: #6f42c1;
@@ -44,10 +44,32 @@
   --bs-danger-rgb: 220, 53, 69;
   --bs-light-rgb: 248, 249, 250;
   --bs-dark-rgb: 33, 37, 41;
+  --bs-primary-text-emphasis: #052c65;
+  --bs-secondary-text-emphasis: #2b2f32;
+  --bs-success-text-emphasis: #0a3622;
+  --bs-info-text-emphasis: #055160;
+  --bs-warning-text-emphasis: #664d03;
+  --bs-danger-text-emphasis: #58151c;
+  --bs-light-text-emphasis: #495057;
+  --bs-dark-text-emphasis: #495057;
+  --bs-primary-bg-subtle: #cfe2ff;
+  --bs-secondary-bg-subtle: #e2e3e5;
+  --bs-success-bg-subtle: #d1e7dd;
+  --bs-info-bg-subtle: #cff4fc;
+  --bs-warning-bg-subtle: #fff3cd;
+  --bs-danger-bg-subtle: #f8d7da;
+  --bs-light-bg-subtle: #fcfcfd;
+  --bs-dark-bg-subtle: #ced4da;
+  --bs-primary-border-subtle: #9ec5fe;
+  --bs-secondary-border-subtle: #c4c8cb;
+  --bs-success-border-subtle: #a3cfbb;
+  --bs-info-border-subtle: #9eeaf9;
+  --bs-warning-border-subtle: #ffe69c;
+  --bs-danger-border-subtle: #f1aeb5;
+  --bs-light-border-subtle: #e9ecef;
+  --bs-dark-border-subtle: #adb5bd;
   --bs-white-rgb: 255, 255, 255;
   --bs-black-rgb: 0, 0, 0;
-  --bs-body-color-rgb: 33, 37, 41;
-  --bs-body-bg-rgb: 255, 255, 255;
   --bs-font-sans-serif: system-ui, -apple-system, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", "Liberation Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
   --bs-font-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
   --bs-gradient: linear-gradient(180deg, rgba(255, 255, 255, 0.15), rgba(255, 255, 255, 0));
@@ -56,7 +78,28 @@
   --bs-body-font-weight: 400;
   --bs-body-line-height: 1.5;
   --bs-body-color: #212529;
+  --bs-body-color-rgb: 33, 37, 41;
   --bs-body-bg: #fff;
+  --bs-body-bg-rgb: 255, 255, 255;
+  --bs-emphasis-color: #000;
+  --bs-emphasis-color-rgb: 0, 0, 0;
+  --bs-secondary-color: rgba(33, 37, 41, 0.75);
+  --bs-secondary-color-rgb: 33, 37, 41;
+  --bs-secondary-bg: #e9ecef;
+  --bs-secondary-bg-rgb: 233, 236, 239;
+  --bs-tertiary-color: rgba(33, 37, 41, 0.5);
+  --bs-tertiary-color-rgb: 33, 37, 41;
+  --bs-tertiary-bg: #f8f9fa;
+  --bs-tertiary-bg-rgb: 248, 249, 250;
+  --bs-heading-color: inherit;
+  --bs-link-color: #0d6efd;
+  --bs-link-color-rgb: 13, 110, 253;
+  --bs-link-decoration: underline;
+  --bs-link-hover-color: #0a58ca;
+  --bs-link-hover-color-rgb: 10, 88, 202;
+  --bs-code-color: #d63384;
+  --bs-highlight-color: #212529;
+  --bs-highlight-bg: #fff3cd;
   --bs-border-width: 1px;
   --bs-border-style: solid;
   --bs-border-color: #dee2e6;
@@ -65,12 +108,76 @@
   --bs-border-radius-sm: 0.25rem;
   --bs-border-radius-lg: 0.5rem;
   --bs-border-radius-xl: 1rem;
-  --bs-border-radius-2xl: 2rem;
+  --bs-border-radius-xxl: 2rem;
+  --bs-border-radius-2xl: var(--bs-border-radius-xxl);
   --bs-border-radius-pill: 50rem;
-  --bs-link-color: #0d6efd;
-  --bs-link-hover-color: #0a58ca;
-  --bs-code-color: #d63384;
-  --bs-highlight-bg: #fff3cd;
+  --bs-box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15);
+  --bs-box-shadow-sm: 0 0.125rem 0.25rem rgba(0, 0, 0, 0.075);
+  --bs-box-shadow-lg: 0 1rem 3rem rgba(0, 0, 0, 0.175);
+  --bs-box-shadow-inset: inset 0 1px 2px rgba(0, 0, 0, 0.075);
+  --bs-focus-ring-width: 0.25rem;
+  --bs-focus-ring-opacity: 0.25;
+  --bs-focus-ring-color: rgba(13, 110, 253, 0.25);
+  --bs-form-valid-color: #198754;
+  --bs-form-valid-border-color: #198754;
+  --bs-form-invalid-color: #dc3545;
+  --bs-form-invalid-border-color: #dc3545;
+}
+
+[data-bs-theme=dark] {
+  color-scheme: dark;
+  --bs-body-color: #dee2e6;
+  --bs-body-color-rgb: 222, 226, 230;
+  --bs-body-bg: #212529;
+  --bs-body-bg-rgb: 33, 37, 41;
+  --bs-emphasis-color: #fff;
+  --bs-emphasis-color-rgb: 255, 255, 255;
+  --bs-secondary-color: rgba(222, 226, 230, 0.75);
+  --bs-secondary-color-rgb: 222, 226, 230;
+  --bs-secondary-bg: #343a40;
+  --bs-secondary-bg-rgb: 52, 58, 64;
+  --bs-tertiary-color: rgba(222, 226, 230, 0.5);
+  --bs-tertiary-color-rgb: 222, 226, 230;
+  --bs-tertiary-bg: #2b3035;
+  --bs-tertiary-bg-rgb: 43, 48, 53;
+  --bs-primary-text-emphasis: #6ea8fe;
+  --bs-secondary-text-emphasis: #a7acb1;
+  --bs-success-text-emphasis: #75b798;
+  --bs-info-text-emphasis: #6edff6;
+  --bs-warning-text-emphasis: #ffda6a;
+  --bs-danger-text-emphasis: #ea868f;
+  --bs-light-text-emphasis: #f8f9fa;
+  --bs-dark-text-emphasis: #dee2e6;
+  --bs-primary-bg-subtle: #031633;
+  --bs-secondary-bg-subtle: #161719;
+  --bs-success-bg-subtle: #051b11;
+  --bs-info-bg-subtle: #032830;
+  --bs-warning-bg-subtle: #332701;
+  --bs-danger-bg-subtle: #2c0b0e;
+  --bs-light-bg-subtle: #343a40;
+  --bs-dark-bg-subtle: #1a1d20;
+  --bs-primary-border-subtle: #084298;
+  --bs-secondary-border-subtle: #41464b;
+  --bs-success-border-subtle: #0f5132;
+  --bs-info-border-subtle: #087990;
+  --bs-warning-border-subtle: #997404;
+  --bs-danger-border-subtle: #842029;
+  --bs-light-border-subtle: #495057;
+  --bs-dark-border-subtle: #343a40;
+  --bs-heading-color: inherit;
+  --bs-link-color: #6ea8fe;
+  --bs-link-hover-color: #8bb9fe;
+  --bs-link-color-rgb: 110, 168, 254;
+  --bs-link-hover-color-rgb: 139, 185, 254;
+  --bs-code-color: #e685b5;
+  --bs-highlight-color: #dee2e6;
+  --bs-highlight-bg: #664d03;
+  --bs-border-color: #495057;
+  --bs-border-color-translucent: rgba(255, 255, 255, 0.15);
+  --bs-form-valid-color: #75b798;
+  --bs-form-valid-border-color: #75b798;
+  --bs-form-invalid-color: #ea868f;
+  --bs-form-invalid-border-color: #ea868f;
 }
 
 *,
@@ -102,7 +209,7 @@ hr {
   margin: 1rem 0;
   color: inherit;
   border: 0;
-  border-top: 1px solid;
+  border-top: var(--bs-border-width) solid;
   opacity: 0.25;
 }
 
@@ -111,6 +218,7 @@ h6, h5, h4, h3, h2, h1 {
   margin-bottom: 0.5rem;
   font-weight: 500;
   line-height: 1.2;
+  color: var(--bs-heading-color);
 }
 
 h1 {
@@ -219,6 +327,7 @@ small {
 
 mark {
   padding: 0.1875em;
+  color: var(--bs-highlight-color);
   background-color: var(--bs-highlight-bg);
 }
 
@@ -239,11 +348,11 @@ sup {
 }
 
 a {
-  color: var(--bs-link-color);
+  color: rgba(var(--bs-link-color-rgb), var(--bs-link-opacity, 1));
   text-decoration: underline;
 }
 a:hover {
-  color: var(--bs-link-hover-color);
+  --bs-link-color-rgb: var(--bs-link-hover-color-rgb);
 }
 
 a:not([href]):not([class]), a:not([href]):not([class]):hover {
@@ -310,7 +419,7 @@ table {
 caption {
   padding-top: 0.5rem;
   padding-bottom: 0.5rem;
-  color: #6c757d;
+  color: var(--bs-secondary-color);
   text-align: right;
 }
 
@@ -434,8 +543,8 @@ legend + * {
 }
 
 [type=search] {
-  outline-offset: -2px;
   -webkit-appearance: textfield;
+  outline-offset: -2px;
 }
 
 [type="tel"],

文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-reboot.rtl.min.css.map


文件差異過大導致無法顯示
+ 741 - 44
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.min.css.map


文件差異過大導致無法顯示
+ 741 - 44
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap-utilities.rtl.min.css.map


文件差異過大導致無法顯示
+ 277 - 149
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.min.css.map


文件差異過大導致無法顯示
+ 277 - 149
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.css.map


文件差異過大導致無法顯示
+ 2 - 3
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.min.css


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/css/bootstrap.rtl.min.css.map


文件差異過大導致無法顯示
+ 208 - 269
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.js.map


文件差異過大導致無法顯示
+ 2 - 2
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.min.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.bundle.min.js.map


文件差異過大導致無法顯示
+ 208 - 269
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.js.map


文件差異過大導致無法顯示
+ 2 - 2
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.min.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.esm.min.js.map


文件差異過大導致無法顯示
+ 210 - 272
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.js.map


文件差異過大導致無法顯示
+ 2 - 2
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.min.js


文件差異過大導致無法顯示
+ 0 - 0
coderedcms/static/coderedcms/vendor/bootstrap/dist/js/bootstrap.min.js.map


+ 30 - 116
coderedcms/static/coderedcms/vendor/bootstrap/js/src/alert.js

@@ -1,173 +1,87 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): alert.js
+ * Bootstrap alert.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import { enableDismissTrigger } from './util/component-functions.js'
+import { defineJQueryPlugin } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'alert'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.alert'
 const EVENT_KEY = `.${DATA_KEY}`
-const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-
-const SELECTOR_DISMISS = '[data-dismiss="alert"]'
 
 const EVENT_CLOSE = `close${EVENT_KEY}`
 const EVENT_CLOSED = `closed${EVENT_KEY}`
-const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
-
-const CLASS_NAME_ALERT = 'alert'
 const CLASS_NAME_FADE = 'fade'
 const CLASS_NAME_SHOW = 'show'
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Alert {
-  constructor(element) {
-    this._element = element
-  }
-
+class Alert extends BaseComponent {
   // Getters
-
-  static get VERSION() {
-    return VERSION
+  static get NAME() {
+    return NAME
   }
 
   // Public
+  close() {
+    const closeEvent = EventHandler.trigger(this._element, EVENT_CLOSE)
 
-  close(element) {
-    let rootElement = this._element
-    if (element) {
-      rootElement = this._getRootElement(element)
-    }
-
-    const customEvent = this._triggerCloseEvent(rootElement)
-
-    if (customEvent.isDefaultPrevented()) {
+    if (closeEvent.defaultPrevented) {
       return
     }
 
-    this._removeElement(rootElement)
-  }
+    this._element.classList.remove(CLASS_NAME_SHOW)
 
-  dispose() {
-    $.removeData(this._element, DATA_KEY)
-    this._element = null
+    const isAnimated = this._element.classList.contains(CLASS_NAME_FADE)
+    this._queueCallback(() => this._destroyElement(), this._element, isAnimated)
   }
 
   // Private
-
-  _getRootElement(element) {
-    const selector = Util.getSelectorFromElement(element)
-    let parent = false
-
-    if (selector) {
-      parent = document.querySelector(selector)
-    }
-
-    if (!parent) {
-      parent = $(element).closest(`.${CLASS_NAME_ALERT}`)[0]
-    }
-
-    return parent
-  }
-
-  _triggerCloseEvent(element) {
-    const closeEvent = $.Event(EVENT_CLOSE)
-
-    $(element).trigger(closeEvent)
-    return closeEvent
-  }
-
-  _removeElement(element) {
-    $(element).removeClass(CLASS_NAME_SHOW)
-
-    if (!$(element).hasClass(CLASS_NAME_FADE)) {
-      this._destroyElement(element)
-      return
-    }
-
-    const transitionDuration = Util.getTransitionDurationFromElement(element)
-
-    $(element)
-      .one(Util.TRANSITION_END, event => this._destroyElement(element, event))
-      .emulateTransitionEnd(transitionDuration)
-  }
-
-  _destroyElement(element) {
-    $(element)
-      .detach()
-      .trigger(EVENT_CLOSED)
-      .remove()
+  _destroyElement() {
+    this._element.remove()
+    EventHandler.trigger(this._element, EVENT_CLOSED)
+    this.dispose()
   }
 
   // Static
-
-  static _jQueryInterface(config) {
+  static jQueryInterface(config) {
     return this.each(function () {
-      const $element = $(this)
-      let data = $element.data(DATA_KEY)
-
-      if (!data) {
-        data = new Alert(this)
-        $element.data(DATA_KEY, data)
-      }
+      const data = Alert.getOrCreateInstance(this)
 
-      if (config === 'close') {
-        data[config](this)
+      if (typeof config !== 'string') {
+        return
       }
-    })
-  }
 
-  static _handleDismiss(alertInstance) {
-    return function (event) {
-      if (event) {
-        event.preventDefault()
+      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+        throw new TypeError(`No method named "${config}"`)
       }
 
-      alertInstance.close(this)
-    }
+      data[config](this)
+    })
   }
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document).on(
-  EVENT_CLICK_DATA_API,
-  SELECTOR_DISMISS,
-  Alert._handleDismiss(new Alert())
-)
+enableDismissTrigger(Alert, 'close')
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Alert._jQueryInterface
-$.fn[NAME].Constructor = Alert
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Alert._jQueryInterface
-}
+defineJQueryPlugin(Alert)
 
 export default Alert

+ 85 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/base-component.js

@@ -0,0 +1,85 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap base-component.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import Data from './dom/data.js'
+import EventHandler from './dom/event-handler.js'
+import Config from './util/config.js'
+import { executeAfterTransition, getElement } from './util/index.js'
+
+/**
+ * Constants
+ */
+
+const VERSION = '5.3.2'
+
+/**
+ * Class definition
+ */
+
+class BaseComponent extends Config {
+  constructor(element, config) {
+    super()
+
+    element = getElement(element)
+    if (!element) {
+      return
+    }
+
+    this._element = element
+    this._config = this._getConfig(config)
+
+    Data.set(this._element, this.constructor.DATA_KEY, this)
+  }
+
+  // Public
+  dispose() {
+    Data.remove(this._element, this.constructor.DATA_KEY)
+    EventHandler.off(this._element, this.constructor.EVENT_KEY)
+
+    for (const propertyName of Object.getOwnPropertyNames(this)) {
+      this[propertyName] = null
+    }
+  }
+
+  _queueCallback(callback, element, isAnimated = true) {
+    executeAfterTransition(callback, element, isAnimated)
+  }
+
+  _getConfig(config) {
+    config = this._mergeConfigObj(config, this._element)
+    config = this._configAfterMerge(config)
+    this._typeCheckConfig(config)
+    return config
+  }
+
+  // Static
+  static getInstance(element) {
+    return Data.get(getElement(element), this.DATA_KEY)
+  }
+
+  static getOrCreateInstance(element, config = {}) {
+    return this.getInstance(element) || new this(element, typeof config === 'object' ? config : null)
+  }
+
+  static get VERSION() {
+    return VERSION
+  }
+
+  static get DATA_KEY() {
+    return `bs.${this.NAME}`
+  }
+
+  static get EVENT_KEY() {
+    return `.${this.DATA_KEY}`
+  }
+
+  static eventName(name) {
+    return `${name}${this.EVENT_KEY}`
+  }
+}
+
+export default BaseComponent

+ 20 - 157
coderedcms/static/coderedcms/vendor/bootstrap/js/src/button.js

@@ -1,128 +1,47 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): button.js
+ * Bootstrap button.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import { defineJQueryPlugin } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'button'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.button'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
 
 const CLASS_NAME_ACTIVE = 'active'
-const CLASS_NAME_BUTTON = 'btn'
-const CLASS_NAME_FOCUS = 'focus'
-
-const SELECTOR_DATA_TOGGLE_CARROT = '[data-toggle^="button"]'
-const SELECTOR_DATA_TOGGLES = '[data-toggle="buttons"]'
-const SELECTOR_DATA_TOGGLE = '[data-toggle="button"]'
-const SELECTOR_DATA_TOGGLES_BUTTONS = '[data-toggle="buttons"] .btn'
-const SELECTOR_INPUT = 'input:not([type="hidden"])'
-const SELECTOR_ACTIVE = '.active'
-const SELECTOR_BUTTON = '.btn'
-
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="button"]'
 const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
-const EVENT_FOCUS_BLUR_DATA_API = `focus${EVENT_KEY}${DATA_API_KEY} ` +
-                          `blur${EVENT_KEY}${DATA_API_KEY}`
-const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Button {
-  constructor(element) {
-    this._element = element
-    this.shouldAvoidTriggerChange = false
-  }
-
+class Button extends BaseComponent {
   // Getters
-
-  static get VERSION() {
-    return VERSION
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   toggle() {
-    let triggerChangeEvent = true
-    let addAriaPressed = true
-    const rootElement = $(this._element).closest(SELECTOR_DATA_TOGGLES)[0]
-
-    if (rootElement) {
-      const input = this._element.querySelector(SELECTOR_INPUT)
-
-      if (input) {
-        if (input.type === 'radio') {
-          if (input.checked && this._element.classList.contains(CLASS_NAME_ACTIVE)) {
-            triggerChangeEvent = false
-          } else {
-            const activeElement = rootElement.querySelector(SELECTOR_ACTIVE)
-
-            if (activeElement) {
-              $(activeElement).removeClass(CLASS_NAME_ACTIVE)
-            }
-          }
-        }
-
-        if (triggerChangeEvent) {
-          // if it's not a radio button or checkbox don't add a pointless/invalid checked property to the input
-          if (input.type === 'checkbox' || input.type === 'radio') {
-            input.checked = !this._element.classList.contains(CLASS_NAME_ACTIVE)
-          }
-
-          if (!this.shouldAvoidTriggerChange) {
-            $(input).trigger('change')
-          }
-        }
-
-        input.focus()
-        addAriaPressed = false
-      }
-    }
-
-    if (!(this._element.hasAttribute('disabled') || this._element.classList.contains('disabled'))) {
-      if (addAriaPressed) {
-        this._element.setAttribute('aria-pressed', !this._element.classList.contains(CLASS_NAME_ACTIVE))
-      }
-
-      if (triggerChangeEvent) {
-        $(this._element).toggleClass(CLASS_NAME_ACTIVE)
-      }
-    }
-  }
-
-  dispose() {
-    $.removeData(this._element, DATA_KEY)
-    this._element = null
+    // Toggle class and sync the `aria-pressed` attribute with the return value of the `.toggle()` method
+    this._element.setAttribute('aria-pressed', this._element.classList.toggle(CLASS_NAME_ACTIVE))
   }
 
   // Static
-
-  static _jQueryInterface(config, avoidTriggerChange) {
+  static jQueryInterface(config) {
     return this.each(function () {
-      const $element = $(this)
-      let data = $element.data(DATA_KEY)
-
-      if (!data) {
-        data = new Button(this)
-        $element.data(DATA_KEY, data)
-      }
-
-      data.shouldAvoidTriggerChange = avoidTriggerChange
+      const data = Button.getOrCreateInstance(this)
 
       if (config === 'toggle') {
         data[config]()
@@ -132,78 +51,22 @@ class Button {
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document)
-  .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => {
-    let button = event.target
-    const initialButton = button
-
-    if (!$(button).hasClass(CLASS_NAME_BUTTON)) {
-      button = $(button).closest(SELECTOR_BUTTON)[0]
-    }
-
-    if (!button || button.hasAttribute('disabled') || button.classList.contains('disabled')) {
-      event.preventDefault() // work around Firefox bug #1540995
-    } else {
-      const inputBtn = button.querySelector(SELECTOR_INPUT)
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, event => {
+  event.preventDefault()
 
-      if (inputBtn && (inputBtn.hasAttribute('disabled') || inputBtn.classList.contains('disabled'))) {
-        event.preventDefault() // work around Firefox bug #1540995
-        return
-      }
-
-      if (initialButton.tagName === 'INPUT' || button.tagName !== 'LABEL') {
-        Button._jQueryInterface.call($(button), 'toggle', initialButton.tagName === 'INPUT')
-      }
-    }
-  })
-  .on(EVENT_FOCUS_BLUR_DATA_API, SELECTOR_DATA_TOGGLE_CARROT, event => {
-    const button = $(event.target).closest(SELECTOR_BUTTON)[0]
-    $(button).toggleClass(CLASS_NAME_FOCUS, /^focus(in)?$/.test(event.type))
-  })
-
-$(window).on(EVENT_LOAD_DATA_API, () => {
-  // ensure correct active class is set to match the controls' actual values/states
-
-  // find all checkboxes/readio buttons inside data-toggle groups
-  let buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLES_BUTTONS))
-  for (let i = 0, len = buttons.length; i < len; i++) {
-    const button = buttons[i]
-    const input = button.querySelector(SELECTOR_INPUT)
-    if (input.checked || input.hasAttribute('checked')) {
-      button.classList.add(CLASS_NAME_ACTIVE)
-    } else {
-      button.classList.remove(CLASS_NAME_ACTIVE)
-    }
-  }
+  const button = event.target.closest(SELECTOR_DATA_TOGGLE)
+  const data = Button.getOrCreateInstance(button)
 
-  // find all button toggles
-  buttons = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))
-  for (let i = 0, len = buttons.length; i < len; i++) {
-    const button = buttons[i]
-    if (button.getAttribute('aria-pressed') === 'true') {
-      button.classList.add(CLASS_NAME_ACTIVE)
-    } else {
-      button.classList.remove(CLASS_NAME_ACTIVE)
-    }
-  }
+  data.toggle()
 })
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Button._jQueryInterface
-$.fn[NAME].Constructor = Button
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Button._jQueryInterface
-}
+defineJQueryPlugin(Button)
 
 export default Button

+ 252 - 391
coderedcms/static/coderedcms/vendor/bootstrap/js/src/carousel.js

@@ -1,50 +1,39 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): carousel.js
+ * Bootstrap carousel.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import Manipulator from './dom/manipulator.js'
+import SelectorEngine from './dom/selector-engine.js'
+import {
+  defineJQueryPlugin,
+  getNextActiveElement,
+  isRTL,
+  isVisible,
+  reflow,
+  triggerTransitionEnd
+} from './util/index.js'
+import Swipe from './util/swipe.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'carousel'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.carousel'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-const ARROW_LEFT_KEYCODE = 37 // KeyboardEvent.which value for left arrow key
-const ARROW_RIGHT_KEYCODE = 39 // KeyboardEvent.which value for right arrow key
-const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
-const SWIPE_THRESHOLD = 40
 
-const Default = {
-  interval: 5000,
-  keyboard: true,
-  slide: false,
-  pause: 'hover',
-  wrap: true,
-  touch: true
-}
-
-const DefaultType = {
-  interval: '(number|boolean)',
-  keyboard: 'boolean',
-  slide: '(boolean|string)',
-  pause: '(string|boolean)',
-  wrap: 'boolean',
-  touch: 'boolean'
-}
+const ARROW_LEFT_KEY = 'ArrowLeft'
+const ARROW_RIGHT_KEY = 'ArrowRight'
+const TOUCHEVENT_COMPAT_WAIT = 500 // Time for mouse compat events to fire after touch
 
-const DIRECTION_NEXT = 'next'
-const DIRECTION_PREV = 'prev'
+const ORDER_NEXT = 'next'
+const ORDER_PREV = 'prev'
 const DIRECTION_LEFT = 'left'
 const DIRECTION_RIGHT = 'right'
 
@@ -53,11 +42,6 @@ const EVENT_SLID = `slid${EVENT_KEY}`
 const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
 const EVENT_MOUSEENTER = `mouseenter${EVENT_KEY}`
 const EVENT_MOUSELEAVE = `mouseleave${EVENT_KEY}`
-const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
-const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`
-const EVENT_TOUCHEND = `touchend${EVENT_KEY}`
-const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
-const EVENT_POINTERUP = `pointerup${EVENT_KEY}`
 const EVENT_DRAG_START = `dragstart${EVENT_KEY}`
 const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
 const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
@@ -65,268 +49,206 @@ const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
 const CLASS_NAME_CAROUSEL = 'carousel'
 const CLASS_NAME_ACTIVE = 'active'
 const CLASS_NAME_SLIDE = 'slide'
-const CLASS_NAME_RIGHT = 'carousel-item-right'
-const CLASS_NAME_LEFT = 'carousel-item-left'
+const CLASS_NAME_END = 'carousel-item-end'
+const CLASS_NAME_START = 'carousel-item-start'
 const CLASS_NAME_NEXT = 'carousel-item-next'
 const CLASS_NAME_PREV = 'carousel-item-prev'
-const CLASS_NAME_POINTER_EVENT = 'pointer-event'
 
 const SELECTOR_ACTIVE = '.active'
-const SELECTOR_ACTIVE_ITEM = '.active.carousel-item'
 const SELECTOR_ITEM = '.carousel-item'
+const SELECTOR_ACTIVE_ITEM = SELECTOR_ACTIVE + SELECTOR_ITEM
 const SELECTOR_ITEM_IMG = '.carousel-item img'
-const SELECTOR_NEXT_PREV = '.carousel-item-next, .carousel-item-prev'
 const SELECTOR_INDICATORS = '.carousel-indicators'
-const SELECTOR_DATA_SLIDE = '[data-slide], [data-slide-to]'
-const SELECTOR_DATA_RIDE = '[data-ride="carousel"]'
+const SELECTOR_DATA_SLIDE = '[data-bs-slide], [data-bs-slide-to]'
+const SELECTOR_DATA_RIDE = '[data-bs-ride="carousel"]'
+
+const KEY_TO_DIRECTION = {
+  [ARROW_LEFT_KEY]: DIRECTION_RIGHT,
+  [ARROW_RIGHT_KEY]: DIRECTION_LEFT
+}
 
-const PointerType = {
-  TOUCH: 'touch',
-  PEN: 'pen'
+const Default = {
+  interval: 5000,
+  keyboard: true,
+  pause: 'hover',
+  ride: false,
+  touch: true,
+  wrap: true
+}
+
+const DefaultType = {
+  interval: '(number|boolean)', // TODO:v6 remove boolean support
+  keyboard: 'boolean',
+  pause: '(string|boolean)',
+  ride: '(boolean|string)',
+  touch: 'boolean',
+  wrap: 'boolean'
 }
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
-class Carousel {
+
+class Carousel extends BaseComponent {
   constructor(element, config) {
-    this._items = null
+    super(element, config)
+
     this._interval = null
     this._activeElement = null
-    this._isPaused = false
     this._isSliding = false
     this.touchTimeout = null
-    this.touchStartX = 0
-    this.touchDeltaX = 0
-
-    this._config = this._getConfig(config)
-    this._element = element
-    this._indicatorsElement = this._element.querySelector(SELECTOR_INDICATORS)
-    this._touchSupported = 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
-    this._pointerEvent = Boolean(window.PointerEvent || window.MSPointerEvent)
+    this._swipeHelper = null
 
+    this._indicatorsElement = SelectorEngine.findOne(SELECTOR_INDICATORS, this._element)
     this._addEventListeners()
+
+    if (this._config.ride === CLASS_NAME_CAROUSEL) {
+      this.cycle()
+    }
   }
 
   // Getters
+  static get Default() {
+    return Default
+  }
 
-  static get VERSION() {
-    return VERSION
+  static get DefaultType() {
+    return DefaultType
   }
 
-  static get Default() {
-    return Default
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   next() {
-    if (!this._isSliding) {
-      this._slide(DIRECTION_NEXT)
-    }
+    this._slide(ORDER_NEXT)
   }
 
   nextWhenVisible() {
-    const $element = $(this._element)
+    // FIXME TODO use `document.visibilityState`
     // Don't call next when the page isn't visible
     // or the carousel or its parent isn't visible
-    if (!document.hidden &&
-      ($element.is(':visible') && $element.css('visibility') !== 'hidden')) {
+    if (!document.hidden && isVisible(this._element)) {
       this.next()
     }
   }
 
   prev() {
-    if (!this._isSliding) {
-      this._slide(DIRECTION_PREV)
-    }
+    this._slide(ORDER_PREV)
   }
 
-  pause(event) {
-    if (!event) {
-      this._isPaused = true
+  pause() {
+    if (this._isSliding) {
+      triggerTransitionEnd(this._element)
     }
 
-    if (this._element.querySelector(SELECTOR_NEXT_PREV)) {
-      Util.triggerTransitionEnd(this._element)
-      this.cycle(true)
-    }
+    this._clearInterval()
+  }
 
-    clearInterval(this._interval)
-    this._interval = null
+  cycle() {
+    this._clearInterval()
+    this._updateInterval()
+
+    this._interval = setInterval(() => this.nextWhenVisible(), this._config.interval)
   }
 
-  cycle(event) {
-    if (!event) {
-      this._isPaused = false
+  _maybeEnableCycle() {
+    if (!this._config.ride) {
+      return
     }
 
-    if (this._interval) {
-      clearInterval(this._interval)
-      this._interval = null
+    if (this._isSliding) {
+      EventHandler.one(this._element, EVENT_SLID, () => this.cycle())
+      return
     }
 
-    if (this._config.interval && !this._isPaused) {
-      this._updateInterval()
-
-      this._interval = setInterval(
-        (document.visibilityState ? this.nextWhenVisible : this.next).bind(this),
-        this._config.interval
-      )
-    }
+    this.cycle()
   }
 
   to(index) {
-    this._activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM)
-
-    const activeIndex = this._getItemIndex(this._activeElement)
-
-    if (index > this._items.length - 1 || index < 0) {
+    const items = this._getItems()
+    if (index > items.length - 1 || index < 0) {
       return
     }
 
     if (this._isSliding) {
-      $(this._element).one(EVENT_SLID, () => this.to(index))
+      EventHandler.one(this._element, EVENT_SLID, () => this.to(index))
       return
     }
 
+    const activeIndex = this._getItemIndex(this._getActive())
     if (activeIndex === index) {
-      this.pause()
-      this.cycle()
       return
     }
 
-    const direction = index > activeIndex ?
-      DIRECTION_NEXT :
-      DIRECTION_PREV
+    const order = index > activeIndex ? ORDER_NEXT : ORDER_PREV
 
-    this._slide(direction, this._items[index])
+    this._slide(order, items[index])
   }
 
   dispose() {
-    $(this._element).off(EVENT_KEY)
-    $.removeData(this._element, DATA_KEY)
+    if (this._swipeHelper) {
+      this._swipeHelper.dispose()
+    }
 
-    this._items = null
-    this._config = null
-    this._element = null
-    this._interval = null
-    this._isPaused = null
-    this._isSliding = null
-    this._activeElement = null
-    this._indicatorsElement = null
+    super.dispose()
   }
 
   // Private
-
-  _getConfig(config) {
-    config = {
-      ...Default,
-      ...config
-    }
-    Util.typeCheckConfig(NAME, config, DefaultType)
+  _configAfterMerge(config) {
+    config.defaultInterval = config.interval
     return config
   }
 
-  _handleSwipe() {
-    const absDeltax = Math.abs(this.touchDeltaX)
-
-    if (absDeltax <= SWIPE_THRESHOLD) {
-      return
-    }
-
-    const direction = absDeltax / this.touchDeltaX
-
-    this.touchDeltaX = 0
-
-    // swipe left
-    if (direction > 0) {
-      this.prev()
-    }
-
-    // swipe right
-    if (direction < 0) {
-      this.next()
-    }
-  }
-
   _addEventListeners() {
     if (this._config.keyboard) {
-      $(this._element).on(EVENT_KEYDOWN, event => this._keydown(event))
+      EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))
     }
 
     if (this._config.pause === 'hover') {
-      $(this._element)
-        .on(EVENT_MOUSEENTER, event => this.pause(event))
-        .on(EVENT_MOUSELEAVE, event => this.cycle(event))
+      EventHandler.on(this._element, EVENT_MOUSEENTER, () => this.pause())
+      EventHandler.on(this._element, EVENT_MOUSELEAVE, () => this._maybeEnableCycle())
     }
 
-    if (this._config.touch) {
+    if (this._config.touch && Swipe.isSupported()) {
       this._addTouchEventListeners()
     }
   }
 
   _addTouchEventListeners() {
-    if (!this._touchSupported) {
-      return
+    for (const img of SelectorEngine.find(SELECTOR_ITEM_IMG, this._element)) {
+      EventHandler.on(img, EVENT_DRAG_START, event => event.preventDefault())
     }
 
-    const start = event => {
-      if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
-        this.touchStartX = event.originalEvent.clientX
-      } else if (!this._pointerEvent) {
-        this.touchStartX = event.originalEvent.touches[0].clientX
+    const endCallBack = () => {
+      if (this._config.pause !== 'hover') {
+        return
       }
-    }
 
-    const move = event => {
-      // ensure swiping with one touch and not pinching
-      if (event.originalEvent.touches && event.originalEvent.touches.length > 1) {
-        this.touchDeltaX = 0
-      } else {
-        this.touchDeltaX = event.originalEvent.touches[0].clientX - this.touchStartX
-      }
-    }
+      // If it's a touch-enabled device, mouseenter/leave are fired as
+      // part of the mouse compatibility events on first tap - the carousel
+      // would stop cycling until user tapped out of it;
+      // here, we listen for touchend, explicitly pause the carousel
+      // (as if it's the second time we tap on it, mouseenter compat event
+      // is NOT fired) and after a timeout (to allow for mouse compatibility
+      // events to fire) we explicitly restart cycling
 
-    const end = event => {
-      if (this._pointerEvent && PointerType[event.originalEvent.pointerType.toUpperCase()]) {
-        this.touchDeltaX = event.originalEvent.clientX - this.touchStartX
+      this.pause()
+      if (this.touchTimeout) {
+        clearTimeout(this.touchTimeout)
       }
 
-      this._handleSwipe()
-      if (this._config.pause === 'hover') {
-        // If it's a touch-enabled device, mouseenter/leave are fired as
-        // part of the mouse compatibility events on first tap - the carousel
-        // would stop cycling until user tapped out of it;
-        // here, we listen for touchend, explicitly pause the carousel
-        // (as if it's the second time we tap on it, mouseenter compat event
-        // is NOT fired) and after a timeout (to allow for mouse compatibility
-        // events to fire) we explicitly restart cycling
-
-        this.pause()
-        if (this.touchTimeout) {
-          clearTimeout(this.touchTimeout)
-        }
-
-        this.touchTimeout = setTimeout(event => this.cycle(event), TOUCHEVENT_COMPAT_WAIT + this._config.interval)
-      }
+      this.touchTimeout = setTimeout(() => this._maybeEnableCycle(), TOUCHEVENT_COMPAT_WAIT + this._config.interval)
     }
 
-    $(this._element.querySelectorAll(SELECTOR_ITEM_IMG))
-      .on(EVENT_DRAG_START, e => e.preventDefault())
-
-    if (this._pointerEvent) {
-      $(this._element).on(EVENT_POINTERDOWN, event => start(event))
-      $(this._element).on(EVENT_POINTERUP, event => end(event))
-
-      this._element.classList.add(CLASS_NAME_POINTER_EVENT)
-    } else {
-      $(this._element).on(EVENT_TOUCHSTART, event => start(event))
-      $(this._element).on(EVENT_TOUCHMOVE, event => move(event))
-      $(this._element).on(EVENT_TOUCHEND, event => end(event))
+    const swipeConfig = {
+      leftCallback: () => this._slide(this._directionToOrder(DIRECTION_LEFT)),
+      rightCallback: () => this._slide(this._directionToOrder(DIRECTION_RIGHT)),
+      endCallback: endCallBack
     }
+
+    this._swipeHelper = new Swipe(this._element, swipeConfig)
   }
 
   _keydown(event) {
@@ -334,280 +256,219 @@ class Carousel {
       return
     }
 
-    switch (event.which) {
-      case ARROW_LEFT_KEYCODE:
-        event.preventDefault()
-        this.prev()
-        break
-      case ARROW_RIGHT_KEYCODE:
-        event.preventDefault()
-        this.next()
-        break
-      default:
+    const direction = KEY_TO_DIRECTION[event.key]
+    if (direction) {
+      event.preventDefault()
+      this._slide(this._directionToOrder(direction))
     }
   }
 
   _getItemIndex(element) {
-    this._items = element && element.parentNode ?
-      [].slice.call(element.parentNode.querySelectorAll(SELECTOR_ITEM)) :
-      []
-    return this._items.indexOf(element)
+    return this._getItems().indexOf(element)
   }
 
-  _getItemByDirection(direction, activeElement) {
-    const isNextDirection = direction === DIRECTION_NEXT
-    const isPrevDirection = direction === DIRECTION_PREV
-    const activeIndex = this._getItemIndex(activeElement)
-    const lastItemIndex = this._items.length - 1
-    const isGoingToWrap = isPrevDirection && activeIndex === 0 ||
-                            isNextDirection && activeIndex === lastItemIndex
-
-    if (isGoingToWrap && !this._config.wrap) {
-      return activeElement
+  _setActiveIndicatorElement(index) {
+    if (!this._indicatorsElement) {
+      return
     }
 
-    const delta = direction === DIRECTION_PREV ? -1 : 1
-    const itemIndex = (activeIndex + delta) % this._items.length
+    const activeIndicator = SelectorEngine.findOne(SELECTOR_ACTIVE, this._indicatorsElement)
 
-    return itemIndex === -1 ?
-      this._items[this._items.length - 1] : this._items[itemIndex]
-  }
-
-  _triggerSlideEvent(relatedTarget, eventDirectionName) {
-    const targetIndex = this._getItemIndex(relatedTarget)
-    const fromIndex = this._getItemIndex(this._element.querySelector(SELECTOR_ACTIVE_ITEM))
-    const slideEvent = $.Event(EVENT_SLIDE, {
-      relatedTarget,
-      direction: eventDirectionName,
-      from: fromIndex,
-      to: targetIndex
-    })
+    activeIndicator.classList.remove(CLASS_NAME_ACTIVE)
+    activeIndicator.removeAttribute('aria-current')
 
-    $(this._element).trigger(slideEvent)
+    const newActiveIndicator = SelectorEngine.findOne(`[data-bs-slide-to="${index}"]`, this._indicatorsElement)
 
-    return slideEvent
-  }
-
-  _setActiveIndicatorElement(element) {
-    if (this._indicatorsElement) {
-      const indicators = [].slice.call(this._indicatorsElement.querySelectorAll(SELECTOR_ACTIVE))
-      $(indicators).removeClass(CLASS_NAME_ACTIVE)
-
-      const nextIndicator = this._indicatorsElement.children[
-        this._getItemIndex(element)
-      ]
-
-      if (nextIndicator) {
-        $(nextIndicator).addClass(CLASS_NAME_ACTIVE)
-      }
+    if (newActiveIndicator) {
+      newActiveIndicator.classList.add(CLASS_NAME_ACTIVE)
+      newActiveIndicator.setAttribute('aria-current', 'true')
     }
   }
 
   _updateInterval() {
-    const element = this._activeElement || this._element.querySelector(SELECTOR_ACTIVE_ITEM)
+    const element = this._activeElement || this._getActive()
 
     if (!element) {
       return
     }
 
-    const elementInterval = parseInt(element.getAttribute('data-interval'), 10)
+    const elementInterval = Number.parseInt(element.getAttribute('data-bs-interval'), 10)
 
-    if (elementInterval) {
-      this._config.defaultInterval = this._config.defaultInterval || this._config.interval
-      this._config.interval = elementInterval
-    } else {
-      this._config.interval = this._config.defaultInterval || this._config.interval
-    }
+    this._config.interval = elementInterval || this._config.defaultInterval
   }
 
-  _slide(direction, element) {
-    const activeElement = this._element.querySelector(SELECTOR_ACTIVE_ITEM)
-    const activeElementIndex = this._getItemIndex(activeElement)
-    const nextElement = element || activeElement &&
-      this._getItemByDirection(direction, activeElement)
-    const nextElementIndex = this._getItemIndex(nextElement)
-    const isCycling = Boolean(this._interval)
-
-    let directionalClassName
-    let orderClassName
-    let eventDirectionName
-
-    if (direction === DIRECTION_NEXT) {
-      directionalClassName = CLASS_NAME_LEFT
-      orderClassName = CLASS_NAME_NEXT
-      eventDirectionName = DIRECTION_LEFT
-    } else {
-      directionalClassName = CLASS_NAME_RIGHT
-      orderClassName = CLASS_NAME_PREV
-      eventDirectionName = DIRECTION_RIGHT
+  _slide(order, element = null) {
+    if (this._isSliding) {
+      return
     }
 
-    if (nextElement && $(nextElement).hasClass(CLASS_NAME_ACTIVE)) {
-      this._isSliding = false
+    const activeElement = this._getActive()
+    const isNext = order === ORDER_NEXT
+    const nextElement = element || getNextActiveElement(this._getItems(), activeElement, isNext, this._config.wrap)
+
+    if (nextElement === activeElement) {
       return
     }
 
-    const slideEvent = this._triggerSlideEvent(nextElement, eventDirectionName)
-    if (slideEvent.isDefaultPrevented()) {
+    const nextElementIndex = this._getItemIndex(nextElement)
+
+    const triggerEvent = eventName => {
+      return EventHandler.trigger(this._element, eventName, {
+        relatedTarget: nextElement,
+        direction: this._orderToDirection(order),
+        from: this._getItemIndex(activeElement),
+        to: nextElementIndex
+      })
+    }
+
+    const slideEvent = triggerEvent(EVENT_SLIDE)
+
+    if (slideEvent.defaultPrevented) {
       return
     }
 
     if (!activeElement || !nextElement) {
       // Some weirdness is happening, so we bail
+      // TODO: change tests that use empty divs to avoid this check
       return
     }
 
-    this._isSliding = true
+    const isCycling = Boolean(this._interval)
+    this.pause()
 
-    if (isCycling) {
-      this.pause()
-    }
+    this._isSliding = true
 
-    this._setActiveIndicatorElement(nextElement)
+    this._setActiveIndicatorElement(nextElementIndex)
     this._activeElement = nextElement
 
-    const slidEvent = $.Event(EVENT_SLID, {
-      relatedTarget: nextElement,
-      direction: eventDirectionName,
-      from: activeElementIndex,
-      to: nextElementIndex
-    })
-
-    if ($(this._element).hasClass(CLASS_NAME_SLIDE)) {
-      $(nextElement).addClass(orderClassName)
-
-      Util.reflow(nextElement)
-
-      $(activeElement).addClass(directionalClassName)
-      $(nextElement).addClass(directionalClassName)
+    const directionalClassName = isNext ? CLASS_NAME_START : CLASS_NAME_END
+    const orderClassName = isNext ? CLASS_NAME_NEXT : CLASS_NAME_PREV
 
-      const transitionDuration = Util.getTransitionDurationFromElement(activeElement)
+    nextElement.classList.add(orderClassName)
 
-      $(activeElement)
-        .one(Util.TRANSITION_END, () => {
-          $(nextElement)
-            .removeClass(`${directionalClassName} ${orderClassName}`)
-            .addClass(CLASS_NAME_ACTIVE)
+    reflow(nextElement)
 
-          $(activeElement).removeClass(`${CLASS_NAME_ACTIVE} ${orderClassName} ${directionalClassName}`)
+    activeElement.classList.add(directionalClassName)
+    nextElement.classList.add(directionalClassName)
 
-          this._isSliding = false
+    const completeCallBack = () => {
+      nextElement.classList.remove(directionalClassName, orderClassName)
+      nextElement.classList.add(CLASS_NAME_ACTIVE)
 
-          setTimeout(() => $(this._element).trigger(slidEvent), 0)
-        })
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      $(activeElement).removeClass(CLASS_NAME_ACTIVE)
-      $(nextElement).addClass(CLASS_NAME_ACTIVE)
+      activeElement.classList.remove(CLASS_NAME_ACTIVE, orderClassName, directionalClassName)
 
       this._isSliding = false
-      $(this._element).trigger(slidEvent)
+
+      triggerEvent(EVENT_SLID)
     }
 
+    this._queueCallback(completeCallBack, activeElement, this._isAnimated())
+
     if (isCycling) {
       this.cycle()
     }
   }
 
-  // Static
+  _isAnimated() {
+    return this._element.classList.contains(CLASS_NAME_SLIDE)
+  }
 
-  static _jQueryInterface(config) {
-    return this.each(function () {
-      let data = $(this).data(DATA_KEY)
-      let _config = {
-        ...Default,
-        ...$(this).data()
-      }
+  _getActive() {
+    return SelectorEngine.findOne(SELECTOR_ACTIVE_ITEM, this._element)
+  }
 
-      if (typeof config === 'object') {
-        _config = {
-          ..._config,
-          ...config
-        }
-      }
+  _getItems() {
+    return SelectorEngine.find(SELECTOR_ITEM, this._element)
+  }
 
-      const action = typeof config === 'string' ? config : _config.slide
+  _clearInterval() {
+    if (this._interval) {
+      clearInterval(this._interval)
+      this._interval = null
+    }
+  }
 
-      if (!data) {
-        data = new Carousel(this, _config)
-        $(this).data(DATA_KEY, data)
-      }
+  _directionToOrder(direction) {
+    if (isRTL()) {
+      return direction === DIRECTION_LEFT ? ORDER_PREV : ORDER_NEXT
+    }
+
+    return direction === DIRECTION_LEFT ? ORDER_NEXT : ORDER_PREV
+  }
+
+  _orderToDirection(order) {
+    if (isRTL()) {
+      return order === ORDER_PREV ? DIRECTION_LEFT : DIRECTION_RIGHT
+    }
+
+    return order === ORDER_PREV ? DIRECTION_RIGHT : DIRECTION_LEFT
+  }
+
+  // Static
+  static jQueryInterface(config) {
+    return this.each(function () {
+      const data = Carousel.getOrCreateInstance(this, config)
 
       if (typeof config === 'number') {
         data.to(config)
-      } else if (typeof action === 'string') {
-        if (typeof data[action] === 'undefined') {
-          throw new TypeError(`No method named "${action}"`)
+        return
+      }
+
+      if (typeof config === 'string') {
+        if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+          throw new TypeError(`No method named "${config}"`)
         }
 
-        data[action]()
-      } else if (_config.interval && _config.ride) {
-        data.pause()
-        data.cycle()
+        data[config]()
       }
     })
   }
+}
 
-  static _dataApiClickHandler(event) {
-    const selector = Util.getSelectorFromElement(this)
-
-    if (!selector) {
-      return
-    }
-
-    const target = $(selector)[0]
+/**
+ * Data API implementation
+ */
 
-    if (!target || !$(target).hasClass(CLASS_NAME_CAROUSEL)) {
-      return
-    }
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, function (event) {
+  const target = SelectorEngine.getElementFromSelector(this)
 
-    const config = {
-      ...$(target).data(),
-      ...$(this).data()
-    }
-    const slideIndex = this.getAttribute('data-slide-to')
+  if (!target || !target.classList.contains(CLASS_NAME_CAROUSEL)) {
+    return
+  }
 
-    if (slideIndex) {
-      config.interval = false
-    }
+  event.preventDefault()
 
-    Carousel._jQueryInterface.call($(target), config)
+  const carousel = Carousel.getOrCreateInstance(target)
+  const slideIndex = this.getAttribute('data-bs-slide-to')
 
-    if (slideIndex) {
-      $(target).data(DATA_KEY).to(slideIndex)
-    }
+  if (slideIndex) {
+    carousel.to(slideIndex)
+    carousel._maybeEnableCycle()
+    return
+  }
 
-    event.preventDefault()
+  if (Manipulator.getDataAttribute(this, 'slide') === 'next') {
+    carousel.next()
+    carousel._maybeEnableCycle()
+    return
   }
-}
 
-/**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
- */
+  carousel.prev()
+  carousel._maybeEnableCycle()
+})
 
-$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_SLIDE, Carousel._dataApiClickHandler)
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+  const carousels = SelectorEngine.find(SELECTOR_DATA_RIDE)
 
-$(window).on(EVENT_LOAD_DATA_API, () => {
-  const carousels = [].slice.call(document.querySelectorAll(SELECTOR_DATA_RIDE))
-  for (let i = 0, len = carousels.length; i < len; i++) {
-    const $carousel = $(carousels[i])
-    Carousel._jQueryInterface.call($carousel, $carousel.data())
+  for (const carousel of carousels) {
+    Carousel.getOrCreateInstance(carousel)
   }
 })
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Carousel._jQueryInterface
-$.fn[NAME].Constructor = Carousel
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Carousel._jQueryInterface
-}
+defineJQueryPlugin(Carousel)
 
 export default Carousel

+ 128 - 223
coderedcms/static/coderedcms/vendor/bootstrap/js/src/collapse.js

@@ -1,35 +1,27 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): collapse.js
+ * Bootstrap collapse.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import SelectorEngine from './dom/selector-engine.js'
+import {
+  defineJQueryPlugin,
+  getElement,
+  reflow
+} from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'collapse'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.collapse'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-
-const Default = {
-  toggle: true,
-  parent: ''
-}
-
-const DefaultType = {
-  toggle: 'boolean',
-  parent: '(string|element)'
-}
 
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
@@ -41,46 +33,52 @@ const CLASS_NAME_SHOW = 'show'
 const CLASS_NAME_COLLAPSE = 'collapse'
 const CLASS_NAME_COLLAPSING = 'collapsing'
 const CLASS_NAME_COLLAPSED = 'collapsed'
+const CLASS_NAME_DEEPER_CHILDREN = `:scope .${CLASS_NAME_COLLAPSE} .${CLASS_NAME_COLLAPSE}`
+const CLASS_NAME_HORIZONTAL = 'collapse-horizontal'
+
+const WIDTH = 'width'
+const HEIGHT = 'height'
+
+const SELECTOR_ACTIVES = '.collapse.show, .collapse.collapsing'
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="collapse"]'
 
-const DIMENSION_WIDTH = 'width'
-const DIMENSION_HEIGHT = 'height'
+const Default = {
+  parent: null,
+  toggle: true
+}
 
-const SELECTOR_ACTIVES = '.show, .collapsing'
-const SELECTOR_DATA_TOGGLE = '[data-toggle="collapse"]'
+const DefaultType = {
+  parent: '(null|element)',
+  toggle: 'boolean'
+}
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Collapse {
+class Collapse extends BaseComponent {
   constructor(element, config) {
+    super(element, config)
+
     this._isTransitioning = false
-    this._element = element
-    this._config = this._getConfig(config)
-    this._triggerArray = [].slice.call(document.querySelectorAll(
-      `[data-toggle="collapse"][href="#${element.id}"],` +
-      `[data-toggle="collapse"][data-target="#${element.id}"]`
-    ))
-
-    const toggleList = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))
-    for (let i = 0, len = toggleList.length; i < len; i++) {
-      const elem = toggleList[i]
-      const selector = Util.getSelectorFromElement(elem)
-      const filterElement = [].slice.call(document.querySelectorAll(selector))
-        .filter(foundElem => foundElem === element)
-
-      if (selector !== null && filterElement.length > 0) {
-        this._selector = selector
+    this._triggerArray = []
+
+    const toggleList = SelectorEngine.find(SELECTOR_DATA_TOGGLE)
+
+    for (const elem of toggleList) {
+      const selector = SelectorEngine.getSelectorFromElement(elem)
+      const filterElement = SelectorEngine.find(selector)
+        .filter(foundElement => foundElement === this._element)
+
+      if (selector !== null && filterElement.length) {
         this._triggerArray.push(elem)
       }
     }
 
-    this._parent = this._config.parent ? this._getParent() : null
+    this._initializeChildren()
 
     if (!this._config.parent) {
-      this._addAriaAndCollapsedClass(this._element, this._triggerArray)
+      this._addAriaAndCollapsedClass(this._triggerArray, this._isShown())
     }
 
     if (this._config.toggle) {
@@ -89,19 +87,21 @@ class Collapse {
   }
 
   // Getters
+  static get Default() {
+    return Default
+  }
 
-  static get VERSION() {
-    return VERSION
+  static get DefaultType() {
+    return DefaultType
   }
 
-  static get Default() {
-    return Default
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   toggle() {
-    if ($(this._element).hasClass(CLASS_NAME_SHOW)) {
+    if (this._isShown()) {
       this.hide()
     } else {
       this.show()
@@ -109,97 +109,67 @@ class Collapse {
   }
 
   show() {
-    if (this._isTransitioning ||
-      $(this._element).hasClass(CLASS_NAME_SHOW)) {
+    if (this._isTransitioning || this._isShown()) {
       return
     }
 
-    let actives
-    let activesData
-
-    if (this._parent) {
-      actives = [].slice.call(this._parent.querySelectorAll(SELECTOR_ACTIVES))
-        .filter(elem => {
-          if (typeof this._config.parent === 'string') {
-            return elem.getAttribute('data-parent') === this._config.parent
-          }
-
-          return elem.classList.contains(CLASS_NAME_COLLAPSE)
-        })
+    let activeChildren = []
 
-      if (actives.length === 0) {
-        actives = null
-      }
+    // find active children
+    if (this._config.parent) {
+      activeChildren = this._getFirstLevelChildren(SELECTOR_ACTIVES)
+        .filter(element => element !== this._element)
+        .map(element => Collapse.getOrCreateInstance(element, { toggle: false }))
     }
 
-    if (actives) {
-      activesData = $(actives).not(this._selector).data(DATA_KEY)
-      if (activesData && activesData._isTransitioning) {
-        return
-      }
+    if (activeChildren.length && activeChildren[0]._isTransitioning) {
+      return
     }
 
-    const startEvent = $.Event(EVENT_SHOW)
-    $(this._element).trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) {
+    const startEvent = EventHandler.trigger(this._element, EVENT_SHOW)
+    if (startEvent.defaultPrevented) {
       return
     }
 
-    if (actives) {
-      Collapse._jQueryInterface.call($(actives).not(this._selector), 'hide')
-      if (!activesData) {
-        $(actives).data(DATA_KEY, null)
-      }
+    for (const activeInstance of activeChildren) {
+      activeInstance.hide()
     }
 
     const dimension = this._getDimension()
 
-    $(this._element)
-      .removeClass(CLASS_NAME_COLLAPSE)
-      .addClass(CLASS_NAME_COLLAPSING)
+    this._element.classList.remove(CLASS_NAME_COLLAPSE)
+    this._element.classList.add(CLASS_NAME_COLLAPSING)
 
     this._element.style[dimension] = 0
 
-    if (this._triggerArray.length) {
-      $(this._triggerArray)
-        .removeClass(CLASS_NAME_COLLAPSED)
-        .attr('aria-expanded', true)
-    }
-
-    this.setTransitioning(true)
+    this._addAriaAndCollapsedClass(this._triggerArray, true)
+    this._isTransitioning = true
 
     const complete = () => {
-      $(this._element)
-        .removeClass(CLASS_NAME_COLLAPSING)
-        .addClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`)
+      this._isTransitioning = false
 
-      this._element.style[dimension] = ''
+      this._element.classList.remove(CLASS_NAME_COLLAPSING)
+      this._element.classList.add(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)
 
-      this.setTransitioning(false)
+      this._element.style[dimension] = ''
 
-      $(this._element).trigger(EVENT_SHOWN)
+      EventHandler.trigger(this._element, EVENT_SHOWN)
     }
 
     const capitalizedDimension = dimension[0].toUpperCase() + dimension.slice(1)
     const scrollSize = `scroll${capitalizedDimension}`
-    const transitionDuration = Util.getTransitionDurationFromElement(this._element)
-
-    $(this._element)
-      .one(Util.TRANSITION_END, complete)
-      .emulateTransitionEnd(transitionDuration)
 
+    this._queueCallback(complete, this._element, true)
     this._element.style[dimension] = `${this._element[scrollSize]}px`
   }
 
   hide() {
-    if (this._isTransitioning ||
-      !$(this._element).hasClass(CLASS_NAME_SHOW)) {
+    if (this._isTransitioning || !this._isShown()) {
       return
     }
 
-    const startEvent = $.Event(EVENT_HIDE)
-    $(this._element).trigger(startEvent)
-    if (startEvent.isDefaultPrevented()) {
+    const startEvent = EventHandler.trigger(this._element, EVENT_HIDE)
+    if (startEvent.defaultPrevented) {
       return
     }
 
@@ -207,139 +177,90 @@ class Collapse {
 
     this._element.style[dimension] = `${this._element.getBoundingClientRect()[dimension]}px`
 
-    Util.reflow(this._element)
+    reflow(this._element)
 
-    $(this._element)
-      .addClass(CLASS_NAME_COLLAPSING)
-      .removeClass(`${CLASS_NAME_COLLAPSE} ${CLASS_NAME_SHOW}`)
+    this._element.classList.add(CLASS_NAME_COLLAPSING)
+    this._element.classList.remove(CLASS_NAME_COLLAPSE, CLASS_NAME_SHOW)
 
-    const triggerArrayLength = this._triggerArray.length
-    if (triggerArrayLength > 0) {
-      for (let i = 0; i < triggerArrayLength; i++) {
-        const trigger = this._triggerArray[i]
-        const selector = Util.getSelectorFromElement(trigger)
+    for (const trigger of this._triggerArray) {
+      const element = SelectorEngine.getElementFromSelector(trigger)
 
-        if (selector !== null) {
-          const $elem = $([].slice.call(document.querySelectorAll(selector)))
-          if (!$elem.hasClass(CLASS_NAME_SHOW)) {
-            $(trigger).addClass(CLASS_NAME_COLLAPSED)
-              .attr('aria-expanded', false)
-          }
-        }
+      if (element && !this._isShown(element)) {
+        this._addAriaAndCollapsedClass([trigger], false)
       }
     }
 
-    this.setTransitioning(true)
+    this._isTransitioning = true
 
     const complete = () => {
-      this.setTransitioning(false)
-      $(this._element)
-        .removeClass(CLASS_NAME_COLLAPSING)
-        .addClass(CLASS_NAME_COLLAPSE)
-        .trigger(EVENT_HIDDEN)
+      this._isTransitioning = false
+      this._element.classList.remove(CLASS_NAME_COLLAPSING)
+      this._element.classList.add(CLASS_NAME_COLLAPSE)
+      EventHandler.trigger(this._element, EVENT_HIDDEN)
     }
 
     this._element.style[dimension] = ''
-    const transitionDuration = Util.getTransitionDurationFromElement(this._element)
-
-    $(this._element)
-      .one(Util.TRANSITION_END, complete)
-      .emulateTransitionEnd(transitionDuration)
-  }
 
-  setTransitioning(isTransitioning) {
-    this._isTransitioning = isTransitioning
+    this._queueCallback(complete, this._element, true)
   }
 
-  dispose() {
-    $.removeData(this._element, DATA_KEY)
-
-    this._config = null
-    this._parent = null
-    this._element = null
-    this._triggerArray = null
-    this._isTransitioning = null
+  _isShown(element = this._element) {
+    return element.classList.contains(CLASS_NAME_SHOW)
   }
 
   // Private
-
-  _getConfig(config) {
-    config = {
-      ...Default,
-      ...config
-    }
+  _configAfterMerge(config) {
     config.toggle = Boolean(config.toggle) // Coerce string values
-    Util.typeCheckConfig(NAME, config, DefaultType)
+    config.parent = getElement(config.parent)
     return config
   }
 
   _getDimension() {
-    const hasWidth = $(this._element).hasClass(DIMENSION_WIDTH)
-    return hasWidth ? DIMENSION_WIDTH : DIMENSION_HEIGHT
+    return this._element.classList.contains(CLASS_NAME_HORIZONTAL) ? WIDTH : HEIGHT
   }
 
-  _getParent() {
-    let parent
+  _initializeChildren() {
+    if (!this._config.parent) {
+      return
+    }
+
+    const children = this._getFirstLevelChildren(SELECTOR_DATA_TOGGLE)
 
-    if (Util.isElement(this._config.parent)) {
-      parent = this._config.parent
+    for (const element of children) {
+      const selected = SelectorEngine.getElementFromSelector(element)
 
-      // It's a jQuery object
-      if (typeof this._config.parent.jquery !== 'undefined') {
-        parent = this._config.parent[0]
+      if (selected) {
+        this._addAriaAndCollapsedClass([element], this._isShown(selected))
       }
-    } else {
-      parent = document.querySelector(this._config.parent)
     }
+  }
 
-    const selector = `[data-toggle="collapse"][data-parent="${this._config.parent}"]`
-    const children = [].slice.call(parent.querySelectorAll(selector))
-
-    $(children).each((i, element) => {
-      this._addAriaAndCollapsedClass(
-        Collapse._getTargetFromElement(element),
-        [element]
-      )
-    })
-
-    return parent
+  _getFirstLevelChildren(selector) {
+    const children = SelectorEngine.find(CLASS_NAME_DEEPER_CHILDREN, this._config.parent)
+    // remove children if greater depth
+    return SelectorEngine.find(selector, this._config.parent).filter(element => !children.includes(element))
   }
 
-  _addAriaAndCollapsedClass(element, triggerArray) {
-    const isOpen = $(element).hasClass(CLASS_NAME_SHOW)
+  _addAriaAndCollapsedClass(triggerArray, isOpen) {
+    if (!triggerArray.length) {
+      return
+    }
 
-    if (triggerArray.length) {
-      $(triggerArray)
-        .toggleClass(CLASS_NAME_COLLAPSED, !isOpen)
-        .attr('aria-expanded', isOpen)
+    for (const element of triggerArray) {
+      element.classList.toggle(CLASS_NAME_COLLAPSED, !isOpen)
+      element.setAttribute('aria-expanded', isOpen)
     }
   }
 
   // Static
+  static jQueryInterface(config) {
+    const _config = {}
+    if (typeof config === 'string' && /show|hide/.test(config)) {
+      _config.toggle = false
+    }
 
-  static _getTargetFromElement(element) {
-    const selector = Util.getSelectorFromElement(element)
-    return selector ? document.querySelector(selector) : null
-  }
-
-  static _jQueryInterface(config) {
     return this.each(function () {
-      const $element = $(this)
-      let data = $element.data(DATA_KEY)
-      const _config = {
-        ...Default,
-        ...$element.data(),
-        ...(typeof config === 'object' && config ? config : {})
-      }
-
-      if (!data && _config.toggle && typeof config === 'string' && /show|hide/.test(config)) {
-        _config.toggle = false
-      }
-
-      if (!data) {
-        data = new Collapse(this, _config)
-        $element.data(DATA_KEY, data)
-      }
+      const data = Collapse.getOrCreateInstance(this, _config)
 
       if (typeof config === 'string') {
         if (typeof data[config] === 'undefined') {
@@ -353,40 +274,24 @@ class Collapse {
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
   // preventDefault only for <a> elements (which change the URL) not inside the collapsible element
-  if (event.currentTarget.tagName === 'A') {
+  if (event.target.tagName === 'A' || (event.delegateTarget && event.delegateTarget.tagName === 'A')) {
     event.preventDefault()
   }
 
-  const $trigger = $(this)
-  const selector = Util.getSelectorFromElement(this)
-  const selectors = [].slice.call(document.querySelectorAll(selector))
-
-  $(selectors).each(function () {
-    const $target = $(this)
-    const data = $target.data(DATA_KEY)
-    const config = data ? 'toggle' : $trigger.data()
-    Collapse._jQueryInterface.call($target, config)
-  })
+  for (const element of SelectorEngine.getMultipleElementsFromSelector(this)) {
+    Collapse.getOrCreateInstance(element, { toggle: false }).toggle()
+  }
 })
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Collapse._jQueryInterface
-$.fn[NAME].Constructor = Collapse
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Collapse._jQueryInterface
-}
+defineJQueryPlugin(Collapse)
 
 export default Collapse

+ 55 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/data.js

@@ -0,0 +1,55 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/data.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+/**
+ * Constants
+ */
+
+const elementMap = new Map()
+
+export default {
+  set(element, key, instance) {
+    if (!elementMap.has(element)) {
+      elementMap.set(element, new Map())
+    }
+
+    const instanceMap = elementMap.get(element)
+
+    // make it clear we only want one instance per element
+    // can be removed later when multiple key/instances are fine to be used
+    if (!instanceMap.has(key) && instanceMap.size !== 0) {
+      // eslint-disable-next-line no-console
+      console.error(`Bootstrap doesn't allow more than one instance per element. Bound instance: ${Array.from(instanceMap.keys())[0]}.`)
+      return
+    }
+
+    instanceMap.set(key, instance)
+  },
+
+  get(element, key) {
+    if (elementMap.has(element)) {
+      return elementMap.get(element).get(key) || null
+    }
+
+    return null
+  },
+
+  remove(element, key) {
+    if (!elementMap.has(element)) {
+      return
+    }
+
+    const instanceMap = elementMap.get(element)
+
+    instanceMap.delete(key)
+
+    // free up element references if there are no instances left for an element
+    if (instanceMap.size === 0) {
+      elementMap.delete(element)
+    }
+  }
+}

+ 317 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/event-handler.js

@@ -0,0 +1,317 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/event-handler.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import { getjQuery } from '../util/index.js'
+
+/**
+ * Constants
+ */
+
+const namespaceRegex = /[^.]*(?=\..*)\.|.*/
+const stripNameRegex = /\..*/
+const stripUidRegex = /::\d+$/
+const eventRegistry = {} // Events storage
+let uidEvent = 1
+const customEvents = {
+  mouseenter: 'mouseover',
+  mouseleave: 'mouseout'
+}
+
+const nativeEvents = new Set([
+  'click',
+  'dblclick',
+  'mouseup',
+  'mousedown',
+  'contextmenu',
+  'mousewheel',
+  'DOMMouseScroll',
+  'mouseover',
+  'mouseout',
+  'mousemove',
+  'selectstart',
+  'selectend',
+  'keydown',
+  'keypress',
+  'keyup',
+  'orientationchange',
+  'touchstart',
+  'touchmove',
+  'touchend',
+  'touchcancel',
+  'pointerdown',
+  'pointermove',
+  'pointerup',
+  'pointerleave',
+  'pointercancel',
+  'gesturestart',
+  'gesturechange',
+  'gestureend',
+  'focus',
+  'blur',
+  'change',
+  'reset',
+  'select',
+  'submit',
+  'focusin',
+  'focusout',
+  'load',
+  'unload',
+  'beforeunload',
+  'resize',
+  'move',
+  'DOMContentLoaded',
+  'readystatechange',
+  'error',
+  'abort',
+  'scroll'
+])
+
+/**
+ * Private methods
+ */
+
+function makeEventUid(element, uid) {
+  return (uid && `${uid}::${uidEvent++}`) || element.uidEvent || uidEvent++
+}
+
+function getElementEvents(element) {
+  const uid = makeEventUid(element)
+
+  element.uidEvent = uid
+  eventRegistry[uid] = eventRegistry[uid] || {}
+
+  return eventRegistry[uid]
+}
+
+function bootstrapHandler(element, fn) {
+  return function handler(event) {
+    hydrateObj(event, { delegateTarget: element })
+
+    if (handler.oneOff) {
+      EventHandler.off(element, event.type, fn)
+    }
+
+    return fn.apply(element, [event])
+  }
+}
+
+function bootstrapDelegationHandler(element, selector, fn) {
+  return function handler(event) {
+    const domElements = element.querySelectorAll(selector)
+
+    for (let { target } = event; target && target !== this; target = target.parentNode) {
+      for (const domElement of domElements) {
+        if (domElement !== target) {
+          continue
+        }
+
+        hydrateObj(event, { delegateTarget: target })
+
+        if (handler.oneOff) {
+          EventHandler.off(element, event.type, selector, fn)
+        }
+
+        return fn.apply(target, [event])
+      }
+    }
+  }
+}
+
+function findHandler(events, callable, delegationSelector = null) {
+  return Object.values(events)
+    .find(event => event.callable === callable && event.delegationSelector === delegationSelector)
+}
+
+function normalizeParameters(originalTypeEvent, handler, delegationFunction) {
+  const isDelegated = typeof handler === 'string'
+  // TODO: tooltip passes `false` instead of selector, so we need to check
+  const callable = isDelegated ? delegationFunction : (handler || delegationFunction)
+  let typeEvent = getTypeEvent(originalTypeEvent)
+
+  if (!nativeEvents.has(typeEvent)) {
+    typeEvent = originalTypeEvent
+  }
+
+  return [isDelegated, callable, typeEvent]
+}
+
+function addHandler(element, originalTypeEvent, handler, delegationFunction, oneOff) {
+  if (typeof originalTypeEvent !== 'string' || !element) {
+    return
+  }
+
+  let [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
+
+  // in case of mouseenter or mouseleave wrap the handler within a function that checks for its DOM position
+  // this prevents the handler from being dispatched the same way as mouseover or mouseout does
+  if (originalTypeEvent in customEvents) {
+    const wrapFunction = fn => {
+      return function (event) {
+        if (!event.relatedTarget || (event.relatedTarget !== event.delegateTarget && !event.delegateTarget.contains(event.relatedTarget))) {
+          return fn.call(this, event)
+        }
+      }
+    }
+
+    callable = wrapFunction(callable)
+  }
+
+  const events = getElementEvents(element)
+  const handlers = events[typeEvent] || (events[typeEvent] = {})
+  const previousFunction = findHandler(handlers, callable, isDelegated ? handler : null)
+
+  if (previousFunction) {
+    previousFunction.oneOff = previousFunction.oneOff && oneOff
+
+    return
+  }
+
+  const uid = makeEventUid(callable, originalTypeEvent.replace(namespaceRegex, ''))
+  const fn = isDelegated ?
+    bootstrapDelegationHandler(element, handler, callable) :
+    bootstrapHandler(element, callable)
+
+  fn.delegationSelector = isDelegated ? handler : null
+  fn.callable = callable
+  fn.oneOff = oneOff
+  fn.uidEvent = uid
+  handlers[uid] = fn
+
+  element.addEventListener(typeEvent, fn, isDelegated)
+}
+
+function removeHandler(element, events, typeEvent, handler, delegationSelector) {
+  const fn = findHandler(events[typeEvent], handler, delegationSelector)
+
+  if (!fn) {
+    return
+  }
+
+  element.removeEventListener(typeEvent, fn, Boolean(delegationSelector))
+  delete events[typeEvent][fn.uidEvent]
+}
+
+function removeNamespacedHandlers(element, events, typeEvent, namespace) {
+  const storeElementEvent = events[typeEvent] || {}
+
+  for (const [handlerKey, event] of Object.entries(storeElementEvent)) {
+    if (handlerKey.includes(namespace)) {
+      removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
+    }
+  }
+}
+
+function getTypeEvent(event) {
+  // allow to get the native events from namespaced events ('click.bs.button' --> 'click')
+  event = event.replace(stripNameRegex, '')
+  return customEvents[event] || event
+}
+
+const EventHandler = {
+  on(element, event, handler, delegationFunction) {
+    addHandler(element, event, handler, delegationFunction, false)
+  },
+
+  one(element, event, handler, delegationFunction) {
+    addHandler(element, event, handler, delegationFunction, true)
+  },
+
+  off(element, originalTypeEvent, handler, delegationFunction) {
+    if (typeof originalTypeEvent !== 'string' || !element) {
+      return
+    }
+
+    const [isDelegated, callable, typeEvent] = normalizeParameters(originalTypeEvent, handler, delegationFunction)
+    const inNamespace = typeEvent !== originalTypeEvent
+    const events = getElementEvents(element)
+    const storeElementEvent = events[typeEvent] || {}
+    const isNamespace = originalTypeEvent.startsWith('.')
+
+    if (typeof callable !== 'undefined') {
+      // Simplest case: handler is passed, remove that listener ONLY.
+      if (!Object.keys(storeElementEvent).length) {
+        return
+      }
+
+      removeHandler(element, events, typeEvent, callable, isDelegated ? handler : null)
+      return
+    }
+
+    if (isNamespace) {
+      for (const elementEvent of Object.keys(events)) {
+        removeNamespacedHandlers(element, events, elementEvent, originalTypeEvent.slice(1))
+      }
+    }
+
+    for (const [keyHandlers, event] of Object.entries(storeElementEvent)) {
+      const handlerKey = keyHandlers.replace(stripUidRegex, '')
+
+      if (!inNamespace || originalTypeEvent.includes(handlerKey)) {
+        removeHandler(element, events, typeEvent, event.callable, event.delegationSelector)
+      }
+    }
+  },
+
+  trigger(element, event, args) {
+    if (typeof event !== 'string' || !element) {
+      return null
+    }
+
+    const $ = getjQuery()
+    const typeEvent = getTypeEvent(event)
+    const inNamespace = event !== typeEvent
+
+    let jQueryEvent = null
+    let bubbles = true
+    let nativeDispatch = true
+    let defaultPrevented = false
+
+    if (inNamespace && $) {
+      jQueryEvent = $.Event(event, args)
+
+      $(element).trigger(jQueryEvent)
+      bubbles = !jQueryEvent.isPropagationStopped()
+      nativeDispatch = !jQueryEvent.isImmediatePropagationStopped()
+      defaultPrevented = jQueryEvent.isDefaultPrevented()
+    }
+
+    const evt = hydrateObj(new Event(event, { bubbles, cancelable: true }), args)
+
+    if (defaultPrevented) {
+      evt.preventDefault()
+    }
+
+    if (nativeDispatch) {
+      element.dispatchEvent(evt)
+    }
+
+    if (evt.defaultPrevented && jQueryEvent) {
+      jQueryEvent.preventDefault()
+    }
+
+    return evt
+  }
+}
+
+function hydrateObj(obj, meta = {}) {
+  for (const [key, value] of Object.entries(meta)) {
+    try {
+      obj[key] = value
+    } catch {
+      Object.defineProperty(obj, key, {
+        configurable: true,
+        get() {
+          return value
+        }
+      })
+    }
+  }
+
+  return obj
+}
+
+export default EventHandler

+ 71 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/manipulator.js

@@ -0,0 +1,71 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/manipulator.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+function normalizeData(value) {
+  if (value === 'true') {
+    return true
+  }
+
+  if (value === 'false') {
+    return false
+  }
+
+  if (value === Number(value).toString()) {
+    return Number(value)
+  }
+
+  if (value === '' || value === 'null') {
+    return null
+  }
+
+  if (typeof value !== 'string') {
+    return value
+  }
+
+  try {
+    return JSON.parse(decodeURIComponent(value))
+  } catch {
+    return value
+  }
+}
+
+function normalizeDataKey(key) {
+  return key.replace(/[A-Z]/g, chr => `-${chr.toLowerCase()}`)
+}
+
+const Manipulator = {
+  setDataAttribute(element, key, value) {
+    element.setAttribute(`data-bs-${normalizeDataKey(key)}`, value)
+  },
+
+  removeDataAttribute(element, key) {
+    element.removeAttribute(`data-bs-${normalizeDataKey(key)}`)
+  },
+
+  getDataAttributes(element) {
+    if (!element) {
+      return {}
+    }
+
+    const attributes = {}
+    const bsKeys = Object.keys(element.dataset).filter(key => key.startsWith('bs') && !key.startsWith('bsConfig'))
+
+    for (const key of bsKeys) {
+      let pureKey = key.replace(/^bs/, '')
+      pureKey = pureKey.charAt(0).toLowerCase() + pureKey.slice(1, pureKey.length)
+      attributes[pureKey] = normalizeData(element.dataset[key])
+    }
+
+    return attributes
+  },
+
+  getDataAttribute(element, key) {
+    return normalizeData(element.getAttribute(`data-bs-${normalizeDataKey(key)}`))
+  }
+}
+
+export default Manipulator

+ 126 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/dom/selector-engine.js

@@ -0,0 +1,126 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap dom/selector-engine.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import { isDisabled, isVisible, parseSelector } from '../util/index.js'
+
+const getSelector = element => {
+  let selector = element.getAttribute('data-bs-target')
+
+  if (!selector || selector === '#') {
+    let hrefAttribute = element.getAttribute('href')
+
+    // The only valid content that could double as a selector are IDs or classes,
+    // so everything starting with `#` or `.`. If a "real" URL is used as the selector,
+    // `document.querySelector` will rightfully complain it is invalid.
+    // See https://github.com/twbs/bootstrap/issues/32273
+    if (!hrefAttribute || (!hrefAttribute.includes('#') && !hrefAttribute.startsWith('.'))) {
+      return null
+    }
+
+    // Just in case some CMS puts out a full URL with the anchor appended
+    if (hrefAttribute.includes('#') && !hrefAttribute.startsWith('#')) {
+      hrefAttribute = `#${hrefAttribute.split('#')[1]}`
+    }
+
+    selector = hrefAttribute && hrefAttribute !== '#' ? parseSelector(hrefAttribute.trim()) : null
+  }
+
+  return selector
+}
+
+const SelectorEngine = {
+  find(selector, element = document.documentElement) {
+    return [].concat(...Element.prototype.querySelectorAll.call(element, selector))
+  },
+
+  findOne(selector, element = document.documentElement) {
+    return Element.prototype.querySelector.call(element, selector)
+  },
+
+  children(element, selector) {
+    return [].concat(...element.children).filter(child => child.matches(selector))
+  },
+
+  parents(element, selector) {
+    const parents = []
+    let ancestor = element.parentNode.closest(selector)
+
+    while (ancestor) {
+      parents.push(ancestor)
+      ancestor = ancestor.parentNode.closest(selector)
+    }
+
+    return parents
+  },
+
+  prev(element, selector) {
+    let previous = element.previousElementSibling
+
+    while (previous) {
+      if (previous.matches(selector)) {
+        return [previous]
+      }
+
+      previous = previous.previousElementSibling
+    }
+
+    return []
+  },
+  // TODO: this is now unused; remove later along with prev()
+  next(element, selector) {
+    let next = element.nextElementSibling
+
+    while (next) {
+      if (next.matches(selector)) {
+        return [next]
+      }
+
+      next = next.nextElementSibling
+    }
+
+    return []
+  },
+
+  focusableChildren(element) {
+    const focusables = [
+      'a',
+      'button',
+      'input',
+      'textarea',
+      'select',
+      'details',
+      '[tabindex]',
+      '[contenteditable="true"]'
+    ].map(selector => `${selector}:not([tabindex^="-"])`).join(',')
+
+    return this.find(focusables, element).filter(el => !isDisabled(el) && isVisible(el))
+  },
+
+  getSelectorFromElement(element) {
+    const selector = getSelector(element)
+
+    if (selector) {
+      return SelectorEngine.findOne(selector) ? selector : null
+    }
+
+    return null
+  },
+
+  getElementFromSelector(element) {
+    const selector = getSelector(element)
+
+    return selector ? SelectorEngine.findOne(selector) : null
+  },
+
+  getMultipleElementsFromSelector(element) {
+    const selector = getSelector(element)
+
+    return selector ? SelectorEngine.find(selector) : []
+  }
+}
+
+export default SelectorEngine

+ 250 - 333
coderedcms/static/coderedcms/vendor/bootstrap/js/src/dropdown.js

@@ -1,105 +1,109 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): dropdown.js
+ * Bootstrap dropdown.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Popper from 'popper.js'
-import Util from './util'
+import * as Popper from '@popperjs/core'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import Manipulator from './dom/manipulator.js'
+import SelectorEngine from './dom/selector-engine.js'
+import {
+  defineJQueryPlugin,
+  execute,
+  getElement,
+  getNextActiveElement,
+  isDisabled,
+  isElement,
+  isRTL,
+  isVisible,
+  noop
+} from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'dropdown'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.dropdown'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
-const SPACE_KEYCODE = 32 // KeyboardEvent.which value for space key
-const TAB_KEYCODE = 9 // KeyboardEvent.which value for tab key
-const ARROW_UP_KEYCODE = 38 // KeyboardEvent.which value for up arrow key
-const ARROW_DOWN_KEYCODE = 40 // KeyboardEvent.which value for down arrow key
-const RIGHT_MOUSE_BUTTON_WHICH = 3 // MouseEvent.which value for the right button (assuming a right-handed mouse)
-const REGEXP_KEYDOWN = new RegExp(`${ARROW_UP_KEYCODE}|${ARROW_DOWN_KEYCODE}|${ESCAPE_KEYCODE}`)
+
+const ESCAPE_KEY = 'Escape'
+const TAB_KEY = 'Tab'
+const ARROW_UP_KEY = 'ArrowUp'
+const ARROW_DOWN_KEY = 'ArrowDown'
+const RIGHT_MOUSE_BUTTON = 2 // MouseEvent.button value for the secondary button, usually the right button
 
 const EVENT_HIDE = `hide${EVENT_KEY}`
 const EVENT_HIDDEN = `hidden${EVENT_KEY}`
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
-const EVENT_CLICK = `click${EVENT_KEY}`
 const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
 const EVENT_KEYDOWN_DATA_API = `keydown${EVENT_KEY}${DATA_API_KEY}`
 const EVENT_KEYUP_DATA_API = `keyup${EVENT_KEY}${DATA_API_KEY}`
 
-const CLASS_NAME_DISABLED = 'disabled'
 const CLASS_NAME_SHOW = 'show'
 const CLASS_NAME_DROPUP = 'dropup'
-const CLASS_NAME_DROPRIGHT = 'dropright'
-const CLASS_NAME_DROPLEFT = 'dropleft'
-const CLASS_NAME_MENURIGHT = 'dropdown-menu-right'
-const CLASS_NAME_POSITION_STATIC = 'position-static'
+const CLASS_NAME_DROPEND = 'dropend'
+const CLASS_NAME_DROPSTART = 'dropstart'
+const CLASS_NAME_DROPUP_CENTER = 'dropup-center'
+const CLASS_NAME_DROPDOWN_CENTER = 'dropdown-center'
 
-const SELECTOR_DATA_TOGGLE = '[data-toggle="dropdown"]'
-const SELECTOR_FORM_CHILD = '.dropdown form'
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="dropdown"]:not(.disabled):not(:disabled)'
+const SELECTOR_DATA_TOGGLE_SHOWN = `${SELECTOR_DATA_TOGGLE}.${CLASS_NAME_SHOW}`
 const SELECTOR_MENU = '.dropdown-menu'
+const SELECTOR_NAVBAR = '.navbar'
 const SELECTOR_NAVBAR_NAV = '.navbar-nav'
 const SELECTOR_VISIBLE_ITEMS = '.dropdown-menu .dropdown-item:not(.disabled):not(:disabled)'
 
-const PLACEMENT_TOP = 'top-start'
-const PLACEMENT_TOPEND = 'top-end'
-const PLACEMENT_BOTTOM = 'bottom-start'
-const PLACEMENT_BOTTOMEND = 'bottom-end'
-const PLACEMENT_RIGHT = 'right-start'
-const PLACEMENT_LEFT = 'left-start'
+const PLACEMENT_TOP = isRTL() ? 'top-end' : 'top-start'
+const PLACEMENT_TOPEND = isRTL() ? 'top-start' : 'top-end'
+const PLACEMENT_BOTTOM = isRTL() ? 'bottom-end' : 'bottom-start'
+const PLACEMENT_BOTTOMEND = isRTL() ? 'bottom-start' : 'bottom-end'
+const PLACEMENT_RIGHT = isRTL() ? 'left-start' : 'right-start'
+const PLACEMENT_LEFT = isRTL() ? 'right-start' : 'left-start'
+const PLACEMENT_TOPCENTER = 'top'
+const PLACEMENT_BOTTOMCENTER = 'bottom'
 
 const Default = {
-  offset: 0,
-  flip: true,
-  boundary: 'scrollParent',
-  reference: 'toggle',
+  autoClose: true,
+  boundary: 'clippingParents',
   display: 'dynamic',
-  popperConfig: null
+  offset: [0, 2],
+  popperConfig: null,
+  reference: 'toggle'
 }
 
 const DefaultType = {
-  offset: '(number|string|function)',
-  flip: 'boolean',
+  autoClose: '(boolean|string)',
   boundary: '(string|element)',
-  reference: '(string|element)',
   display: 'string',
-  popperConfig: '(null|object)'
+  offset: '(array|string|function)',
+  popperConfig: '(null|object|function)',
+  reference: '(string|element|object)'
 }
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Dropdown {
+class Dropdown extends BaseComponent {
   constructor(element, config) {
-    this._element = element
+    super(element, config)
+
     this._popper = null
-    this._config = this._getConfig(config)
-    this._menu = this._getMenuElement()
+    this._parent = this._element.parentNode // dropdown wrapper
+    // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+    this._menu = SelectorEngine.next(this._element, SELECTOR_MENU)[0] ||
+      SelectorEngine.prev(this._element, SELECTOR_MENU)[0] ||
+      SelectorEngine.findOne(SELECTOR_MENU, this._parent)
     this._inNavbar = this._detectNavbar()
-
-    this._addEventListeners()
   }
 
   // Getters
-
-  static get VERSION() {
-    return VERSION
-  }
-
   static get Default() {
     return Default
   }
@@ -108,431 +112,344 @@ class Dropdown {
     return DefaultType
   }
 
-  // Public
+  static get NAME() {
+    return NAME
+  }
 
+  // Public
   toggle() {
-    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED)) {
-      return
-    }
-
-    const isActive = $(this._menu).hasClass(CLASS_NAME_SHOW)
-
-    Dropdown._clearMenus()
-
-    if (isActive) {
-      return
-    }
-
-    this.show(true)
+    return this._isShown() ? this.hide() : this.show()
   }
 
-  show(usePopper = false) {
-    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || $(this._menu).hasClass(CLASS_NAME_SHOW)) {
+  show() {
+    if (isDisabled(this._element) || this._isShown()) {
       return
     }
 
     const relatedTarget = {
       relatedTarget: this._element
     }
-    const showEvent = $.Event(EVENT_SHOW, relatedTarget)
-    const parent = Dropdown._getParentFromElement(this._element)
 
-    $(parent).trigger(showEvent)
+    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, relatedTarget)
 
-    if (showEvent.isDefaultPrevented()) {
+    if (showEvent.defaultPrevented) {
       return
     }
 
-    // Totally disable Popper for Dropdowns in Navbar
-    if (!this._inNavbar && usePopper) {
-      /**
-       * Check for Popper dependency
-       * Popper - https://popper.js.org
-       */
-      if (typeof Popper === 'undefined') {
-        throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
-      }
-
-      let referenceElement = this._element
-
-      if (this._config.reference === 'parent') {
-        referenceElement = parent
-      } else if (Util.isElement(this._config.reference)) {
-        referenceElement = this._config.reference
-
-        // Check if it's jQuery element
-        if (typeof this._config.reference.jquery !== 'undefined') {
-          referenceElement = this._config.reference[0]
-        }
-      }
-
-      // If boundary is not `scrollParent`, then set position to `static`
-      // to allow the menu to "escape" the scroll parent's boundaries
-      // https://github.com/twbs/bootstrap/issues/24251
-      if (this._config.boundary !== 'scrollParent') {
-        $(parent).addClass(CLASS_NAME_POSITION_STATIC)
-      }
-
-      this._popper = new Popper(referenceElement, this._menu, this._getPopperConfig())
-    }
+    this._createPopper()
 
     // If this is a touch-enabled device we add extra
     // empty mouseover listeners to the body's immediate children;
     // only needed because of broken event delegation on iOS
     // https://www.quirksmode.org/blog/archives/2014/02/mouse_event_bub.html
-    if ('ontouchstart' in document.documentElement &&
-        $(parent).closest(SELECTOR_NAVBAR_NAV).length === 0) {
-      $(document.body).children().on('mouseover', null, $.noop)
+    if ('ontouchstart' in document.documentElement && !this._parent.closest(SELECTOR_NAVBAR_NAV)) {
+      for (const element of [].concat(...document.body.children)) {
+        EventHandler.on(element, 'mouseover', noop)
+      }
     }
 
     this._element.focus()
     this._element.setAttribute('aria-expanded', true)
 
-    $(this._menu).toggleClass(CLASS_NAME_SHOW)
-    $(parent)
-      .toggleClass(CLASS_NAME_SHOW)
-      .trigger($.Event(EVENT_SHOWN, relatedTarget))
+    this._menu.classList.add(CLASS_NAME_SHOW)
+    this._element.classList.add(CLASS_NAME_SHOW)
+    EventHandler.trigger(this._element, EVENT_SHOWN, relatedTarget)
   }
 
   hide() {
-    if (this._element.disabled || $(this._element).hasClass(CLASS_NAME_DISABLED) || !$(this._menu).hasClass(CLASS_NAME_SHOW)) {
+    if (isDisabled(this._element) || !this._isShown()) {
       return
     }
 
     const relatedTarget = {
       relatedTarget: this._element
     }
-    const hideEvent = $.Event(EVENT_HIDE, relatedTarget)
-    const parent = Dropdown._getParentFromElement(this._element)
-
-    $(parent).trigger(hideEvent)
-
-    if (hideEvent.isDefaultPrevented()) {
-      return
-    }
-
-    if (this._popper) {
-      this._popper.destroy()
-    }
 
-    $(this._menu).toggleClass(CLASS_NAME_SHOW)
-    $(parent)
-      .toggleClass(CLASS_NAME_SHOW)
-      .trigger($.Event(EVENT_HIDDEN, relatedTarget))
+    this._completeHide(relatedTarget)
   }
 
   dispose() {
-    $.removeData(this._element, DATA_KEY)
-    $(this._element).off(EVENT_KEY)
-    this._element = null
-    this._menu = null
-    if (this._popper !== null) {
+    if (this._popper) {
       this._popper.destroy()
-      this._popper = null
     }
+
+    super.dispose()
   }
 
   update() {
     this._inNavbar = this._detectNavbar()
-    if (this._popper !== null) {
-      this._popper.scheduleUpdate()
+    if (this._popper) {
+      this._popper.update()
     }
   }
 
   // Private
+  _completeHide(relatedTarget) {
+    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE, relatedTarget)
+    if (hideEvent.defaultPrevented) {
+      return
+    }
 
-  _addEventListeners() {
-    $(this._element).on(EVENT_CLICK, event => {
-      event.preventDefault()
-      event.stopPropagation()
-      this.toggle()
-    })
+    // If this is a touch-enabled device we remove the extra
+    // empty mouseover listeners we added for iOS support
+    if ('ontouchstart' in document.documentElement) {
+      for (const element of [].concat(...document.body.children)) {
+        EventHandler.off(element, 'mouseover', noop)
+      }
+    }
+
+    if (this._popper) {
+      this._popper.destroy()
+    }
+
+    this._menu.classList.remove(CLASS_NAME_SHOW)
+    this._element.classList.remove(CLASS_NAME_SHOW)
+    this._element.setAttribute('aria-expanded', 'false')
+    Manipulator.removeDataAttribute(this._menu, 'popper')
+    EventHandler.trigger(this._element, EVENT_HIDDEN, relatedTarget)
   }
 
   _getConfig(config) {
-    config = {
-      ...this.constructor.Default,
-      ...$(this._element).data(),
-      ...config
-    }
+    config = super._getConfig(config)
 
-    Util.typeCheckConfig(
-      NAME,
-      config,
-      this.constructor.DefaultType
-    )
+    if (typeof config.reference === 'object' && !isElement(config.reference) &&
+      typeof config.reference.getBoundingClientRect !== 'function'
+    ) {
+      // Popper virtual elements require a getBoundingClientRect method
+      throw new TypeError(`${NAME.toUpperCase()}: Option "reference" provided type "object" without a required "getBoundingClientRect" method.`)
+    }
 
     return config
   }
 
-  _getMenuElement() {
-    if (!this._menu) {
-      const parent = Dropdown._getParentFromElement(this._element)
+  _createPopper() {
+    if (typeof Popper === 'undefined') {
+      throw new TypeError('Bootstrap\'s dropdowns require Popper (https://popper.js.org)')
+    }
+
+    let referenceElement = this._element
 
-      if (parent) {
-        this._menu = parent.querySelector(SELECTOR_MENU)
-      }
+    if (this._config.reference === 'parent') {
+      referenceElement = this._parent
+    } else if (isElement(this._config.reference)) {
+      referenceElement = getElement(this._config.reference)
+    } else if (typeof this._config.reference === 'object') {
+      referenceElement = this._config.reference
     }
 
-    return this._menu
+    const popperConfig = this._getPopperConfig()
+    this._popper = Popper.createPopper(referenceElement, this._menu, popperConfig)
+  }
+
+  _isShown() {
+    return this._menu.classList.contains(CLASS_NAME_SHOW)
   }
 
   _getPlacement() {
-    const $parentDropdown = $(this._element.parentNode)
-    let placement = PLACEMENT_BOTTOM
-
-    // Handle dropup
-    if ($parentDropdown.hasClass(CLASS_NAME_DROPUP)) {
-      placement = $(this._menu).hasClass(CLASS_NAME_MENURIGHT) ?
-        PLACEMENT_TOPEND :
-        PLACEMENT_TOP
-    } else if ($parentDropdown.hasClass(CLASS_NAME_DROPRIGHT)) {
-      placement = PLACEMENT_RIGHT
-    } else if ($parentDropdown.hasClass(CLASS_NAME_DROPLEFT)) {
-      placement = PLACEMENT_LEFT
-    } else if ($(this._menu).hasClass(CLASS_NAME_MENURIGHT)) {
-      placement = PLACEMENT_BOTTOMEND
+    const parentDropdown = this._parent
+
+    if (parentDropdown.classList.contains(CLASS_NAME_DROPEND)) {
+      return PLACEMENT_RIGHT
     }
 
-    return placement
+    if (parentDropdown.classList.contains(CLASS_NAME_DROPSTART)) {
+      return PLACEMENT_LEFT
+    }
+
+    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP_CENTER)) {
+      return PLACEMENT_TOPCENTER
+    }
+
+    if (parentDropdown.classList.contains(CLASS_NAME_DROPDOWN_CENTER)) {
+      return PLACEMENT_BOTTOMCENTER
+    }
+
+    // We need to trim the value because custom properties can also include spaces
+    const isEnd = getComputedStyle(this._menu).getPropertyValue('--bs-position').trim() === 'end'
+
+    if (parentDropdown.classList.contains(CLASS_NAME_DROPUP)) {
+      return isEnd ? PLACEMENT_TOPEND : PLACEMENT_TOP
+    }
+
+    return isEnd ? PLACEMENT_BOTTOMEND : PLACEMENT_BOTTOM
   }
 
   _detectNavbar() {
-    return $(this._element).closest('.navbar').length > 0
+    return this._element.closest(SELECTOR_NAVBAR) !== null
   }
 
   _getOffset() {
-    const offset = {}
+    const { offset } = this._config
 
-    if (typeof this._config.offset === 'function') {
-      offset.fn = data => {
-        data.offsets = {
-          ...data.offsets,
-          ...(this._config.offset(data.offsets, this._element) || {})
-        }
+    if (typeof offset === 'string') {
+      return offset.split(',').map(value => Number.parseInt(value, 10))
+    }
 
-        return data
-      }
-    } else {
-      offset.offset = this._config.offset
+    if (typeof offset === 'function') {
+      return popperData => offset(popperData, this._element)
     }
 
     return offset
   }
 
   _getPopperConfig() {
-    const popperConfig = {
+    const defaultBsPopperConfig = {
       placement: this._getPlacement(),
-      modifiers: {
-        offset: this._getOffset(),
-        flip: {
-          enabled: this._config.flip
-        },
-        preventOverflow: {
-          boundariesElement: this._config.boundary
+      modifiers: [{
+        name: 'preventOverflow',
+        options: {
+          boundary: this._config.boundary
         }
-      }
+      },
+      {
+        name: 'offset',
+        options: {
+          offset: this._getOffset()
+        }
+      }]
     }
 
-    // Disable Popper if we have a static display
-    if (this._config.display === 'static') {
-      popperConfig.modifiers.applyStyle = {
+    // Disable Popper if we have a static display or Dropdown is in Navbar
+    if (this._inNavbar || this._config.display === 'static') {
+      Manipulator.setDataAttribute(this._menu, 'popper', 'static') // TODO: v6 remove
+      defaultBsPopperConfig.modifiers = [{
+        name: 'applyStyles',
         enabled: false
-      }
+      }]
     }
 
     return {
-      ...popperConfig,
-      ...this._config.popperConfig
+      ...defaultBsPopperConfig,
+      ...execute(this._config.popperConfig, [defaultBsPopperConfig])
     }
   }
 
-  // Static
+  _selectMenuItem({ key, target }) {
+    const items = SelectorEngine.find(SELECTOR_VISIBLE_ITEMS, this._menu).filter(element => isVisible(element))
+
+    if (!items.length) {
+      return
+    }
 
-  static _jQueryInterface(config) {
+    // if target isn't included in items (e.g. when expanding the dropdown)
+    // allow cycling to get the last item in case key equals ARROW_UP_KEY
+    getNextActiveElement(items, target, key === ARROW_DOWN_KEY, !items.includes(target)).focus()
+  }
+
+  // Static
+  static jQueryInterface(config) {
     return this.each(function () {
-      let data = $(this).data(DATA_KEY)
-      const _config = typeof config === 'object' ? config : null
+      const data = Dropdown.getOrCreateInstance(this, config)
 
-      if (!data) {
-        data = new Dropdown(this, _config)
-        $(this).data(DATA_KEY, data)
+      if (typeof config !== 'string') {
+        return
       }
 
-      if (typeof config === 'string') {
-        if (typeof data[config] === 'undefined') {
-          throw new TypeError(`No method named "${config}"`)
-        }
-
-        data[config]()
+      if (typeof data[config] === 'undefined') {
+        throw new TypeError(`No method named "${config}"`)
       }
+
+      data[config]()
     })
   }
 
-  static _clearMenus(event) {
-    if (event && (event.which === RIGHT_MOUSE_BUTTON_WHICH ||
-      event.type === 'keyup' && event.which !== TAB_KEYCODE)) {
+  static clearMenus(event) {
+    if (event.button === RIGHT_MOUSE_BUTTON || (event.type === 'keyup' && event.key !== TAB_KEY)) {
       return
     }
 
-    const toggles = [].slice.call(document.querySelectorAll(SELECTOR_DATA_TOGGLE))
+    const openToggles = SelectorEngine.find(SELECTOR_DATA_TOGGLE_SHOWN)
 
-    for (let i = 0, len = toggles.length; i < len; i++) {
-      const parent = Dropdown._getParentFromElement(toggles[i])
-      const context = $(toggles[i]).data(DATA_KEY)
-      const relatedTarget = {
-        relatedTarget: toggles[i]
-      }
-
-      if (event && event.type === 'click') {
-        relatedTarget.clickEvent = event
-      }
-
-      if (!context) {
+    for (const toggle of openToggles) {
+      const context = Dropdown.getInstance(toggle)
+      if (!context || context._config.autoClose === false) {
         continue
       }
 
-      const dropdownMenu = context._menu
-      if (!$(parent).hasClass(CLASS_NAME_SHOW)) {
+      const composedPath = event.composedPath()
+      const isMenuTarget = composedPath.includes(context._menu)
+      if (
+        composedPath.includes(context._element) ||
+        (context._config.autoClose === 'inside' && !isMenuTarget) ||
+        (context._config.autoClose === 'outside' && isMenuTarget)
+      ) {
         continue
       }
 
-      if (event && (event.type === 'click' &&
-          /input|textarea/i.test(event.target.tagName) || event.type === 'keyup' && event.which === TAB_KEYCODE) &&
-          $.contains(parent, event.target)) {
+      // Tab navigation through the dropdown menu or events from contained inputs shouldn't close the menu
+      if (context._menu.contains(event.target) && ((event.type === 'keyup' && event.key === TAB_KEY) || /input|select|option|textarea|form/i.test(event.target.tagName))) {
         continue
       }
 
-      const hideEvent = $.Event(EVENT_HIDE, relatedTarget)
-      $(parent).trigger(hideEvent)
-      if (hideEvent.isDefaultPrevented()) {
-        continue
-      }
+      const relatedTarget = { relatedTarget: context._element }
 
-      // If this is a touch-enabled device we remove the extra
-      // empty mouseover listeners we added for iOS support
-      if ('ontouchstart' in document.documentElement) {
-        $(document.body).children().off('mouseover', null, $.noop)
-      }
-
-      toggles[i].setAttribute('aria-expanded', 'false')
-
-      if (context._popper) {
-        context._popper.destroy()
+      if (event.type === 'click') {
+        relatedTarget.clickEvent = event
       }
 
-      $(dropdownMenu).removeClass(CLASS_NAME_SHOW)
-      $(parent)
-        .removeClass(CLASS_NAME_SHOW)
-        .trigger($.Event(EVENT_HIDDEN, relatedTarget))
+      context._completeHide(relatedTarget)
     }
   }
 
-  static _getParentFromElement(element) {
-    let parent
-    const selector = Util.getSelectorFromElement(element)
+  static dataApiKeydownHandler(event) {
+    // If not an UP | DOWN | ESCAPE key => not a dropdown command
+    // If input/textarea && if key is other than ESCAPE => not a dropdown command
 
-    if (selector) {
-      parent = document.querySelector(selector)
-    }
-
-    return parent || element.parentNode
-  }
+    const isInput = /input|textarea/i.test(event.target.tagName)
+    const isEscapeEvent = event.key === ESCAPE_KEY
+    const isUpOrDownEvent = [ARROW_UP_KEY, ARROW_DOWN_KEY].includes(event.key)
 
-  // eslint-disable-next-line complexity
-  static _dataApiKeydownHandler(event) {
-    // If not input/textarea:
-    //  - And not a key in REGEXP_KEYDOWN => not a dropdown command
-    // If input/textarea:
-    //  - If space key => not a dropdown command
-    //  - If key is other than escape
-    //    - If key is not up or down => not a dropdown command
-    //    - If trigger inside the menu => not a dropdown command
-    if (/input|textarea/i.test(event.target.tagName) ?
-      event.which === SPACE_KEYCODE || event.which !== ESCAPE_KEYCODE &&
-      (event.which !== ARROW_DOWN_KEYCODE && event.which !== ARROW_UP_KEYCODE ||
-        $(event.target).closest(SELECTOR_MENU).length) : !REGEXP_KEYDOWN.test(event.which)) {
+    if (!isUpOrDownEvent && !isEscapeEvent) {
       return
     }
 
-    if (this.disabled || $(this).hasClass(CLASS_NAME_DISABLED)) {
-      return
-    }
-
-    const parent = Dropdown._getParentFromElement(this)
-    const isActive = $(parent).hasClass(CLASS_NAME_SHOW)
-
-    if (!isActive && event.which === ESCAPE_KEYCODE) {
+    if (isInput && !isEscapeEvent) {
       return
     }
 
     event.preventDefault()
-    event.stopPropagation()
 
-    if (!isActive || (event.which === ESCAPE_KEYCODE || event.which === SPACE_KEYCODE)) {
-      if (event.which === ESCAPE_KEYCODE) {
-        $(parent.querySelector(SELECTOR_DATA_TOGGLE)).trigger('focus')
-      }
-
-      $(this).trigger('click')
-      return
-    }
+    // TODO: v6 revert #37011 & change markup https://getbootstrap.com/docs/5.3/forms/input-group/
+    const getToggleButton = this.matches(SELECTOR_DATA_TOGGLE) ?
+      this :
+      (SelectorEngine.prev(this, SELECTOR_DATA_TOGGLE)[0] ||
+        SelectorEngine.next(this, SELECTOR_DATA_TOGGLE)[0] ||
+        SelectorEngine.findOne(SELECTOR_DATA_TOGGLE, event.delegateTarget.parentNode))
 
-    const items = [].slice.call(parent.querySelectorAll(SELECTOR_VISIBLE_ITEMS))
-      .filter(item => $(item).is(':visible'))
+    const instance = Dropdown.getOrCreateInstance(getToggleButton)
 
-    if (items.length === 0) {
+    if (isUpOrDownEvent) {
+      event.stopPropagation()
+      instance.show()
+      instance._selectMenuItem(event)
       return
     }
 
-    let index = items.indexOf(event.target)
-
-    if (event.which === ARROW_UP_KEYCODE && index > 0) { // Up
-      index--
-    }
-
-    if (event.which === ARROW_DOWN_KEYCODE && index < items.length - 1) { // Down
-      index++
-    }
-
-    if (index < 0) {
-      index = 0
+    if (instance._isShown()) { // else is escape and we check if it is shown
+      event.stopPropagation()
+      instance.hide()
+      getToggleButton.focus()
     }
-
-    items[index].focus()
   }
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document)
-  .on(EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown._dataApiKeydownHandler)
-  .on(EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown._dataApiKeydownHandler)
-  .on(`${EVENT_CLICK_DATA_API} ${EVENT_KEYUP_DATA_API}`, Dropdown._clearMenus)
-  .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
-    event.preventDefault()
-    event.stopPropagation()
-    Dropdown._jQueryInterface.call($(this), 'toggle')
-  })
-  .on(EVENT_CLICK_DATA_API, SELECTOR_FORM_CHILD, e => {
-    e.stopPropagation()
-  })
+EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_DATA_TOGGLE, Dropdown.dataApiKeydownHandler)
+EventHandler.on(document, EVENT_KEYDOWN_DATA_API, SELECTOR_MENU, Dropdown.dataApiKeydownHandler)
+EventHandler.on(document, EVENT_CLICK_DATA_API, Dropdown.clearMenus)
+EventHandler.on(document, EVENT_KEYUP_DATA_API, Dropdown.clearMenus)
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+  event.preventDefault()
+  Dropdown.getOrCreateInstance(this).toggle()
+})
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Dropdown._jQueryInterface
-$.fn[NAME].Constructor = Dropdown
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Dropdown._jQueryInterface
-}
+defineJQueryPlugin(Dropdown)
 
 export default Dropdown

+ 0 - 34
coderedcms/static/coderedcms/vendor/bootstrap/js/src/index.js

@@ -1,34 +0,0 @@
-import Alert from './alert'
-import Button from './button'
-import Carousel from './carousel'
-import Collapse from './collapse'
-import Dropdown from './dropdown'
-import Modal from './modal'
-import Popover from './popover'
-import Scrollspy from './scrollspy'
-import Tab from './tab'
-import Toast from './toast'
-import Tooltip from './tooltip'
-import Util from './util'
-
-/**
- * --------------------------------------------------------------------------
- * Bootstrap (v4.5.1): index.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-export {
-  Util,
-  Alert,
-  Button,
-  Carousel,
-  Collapse,
-  Dropdown,
-  Modal,
-  Popover,
-  Scrollspy,
-  Tab,
-  Toast,
-  Tooltip
-}

+ 185 - 438
coderedcms/static/coderedcms/vendor/bootstrap/js/src/modal.js

@@ -1,100 +1,94 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): modal.js
+ * Bootstrap modal.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import SelectorEngine from './dom/selector-engine.js'
+import Backdrop from './util/backdrop.js'
+import { enableDismissTrigger } from './util/component-functions.js'
+import FocusTrap from './util/focustrap.js'
+import { defineJQueryPlugin, isRTL, isVisible, reflow } from './util/index.js'
+import ScrollBarHelper from './util/scrollbar.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'modal'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.modal'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-const ESCAPE_KEYCODE = 27 // KeyboardEvent.which value for Escape (Esc) key
-
-const Default = {
-  backdrop: true,
-  keyboard: true,
-  focus: true,
-  show: true
-}
-
-const DefaultType = {
-  backdrop: '(boolean|string)',
-  keyboard: 'boolean',
-  focus: 'boolean',
-  show: 'boolean'
-}
+const ESCAPE_KEY = 'Escape'
 
 const EVENT_HIDE = `hide${EVENT_KEY}`
 const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
 const EVENT_HIDDEN = `hidden${EVENT_KEY}`
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
-const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
 const EVENT_RESIZE = `resize${EVENT_KEY}`
 const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
-const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
-const EVENT_MOUSEUP_DISMISS = `mouseup.dismiss${EVENT_KEY}`
 const EVENT_MOUSEDOWN_DISMISS = `mousedown.dismiss${EVENT_KEY}`
+const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
 const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
 
-const CLASS_NAME_SCROLLABLE = 'modal-dialog-scrollable'
-const CLASS_NAME_SCROLLBAR_MEASURER = 'modal-scrollbar-measure'
-const CLASS_NAME_BACKDROP = 'modal-backdrop'
 const CLASS_NAME_OPEN = 'modal-open'
 const CLASS_NAME_FADE = 'fade'
 const CLASS_NAME_SHOW = 'show'
 const CLASS_NAME_STATIC = 'modal-static'
 
+const OPEN_SELECTOR = '.modal.show'
 const SELECTOR_DIALOG = '.modal-dialog'
 const SELECTOR_MODAL_BODY = '.modal-body'
-const SELECTOR_DATA_TOGGLE = '[data-toggle="modal"]'
-const SELECTOR_DATA_DISMISS = '[data-dismiss="modal"]'
-const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
-const SELECTOR_STICKY_CONTENT = '.sticky-top'
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="modal"]'
+
+const Default = {
+  backdrop: true,
+  focus: true,
+  keyboard: true
+}
+
+const DefaultType = {
+  backdrop: '(boolean|string)',
+  focus: 'boolean',
+  keyboard: 'boolean'
+}
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Modal {
+class Modal extends BaseComponent {
   constructor(element, config) {
-    this._config = this._getConfig(config)
-    this._element = element
-    this._dialog = element.querySelector(SELECTOR_DIALOG)
-    this._backdrop = null
+    super(element, config)
+
+    this._dialog = SelectorEngine.findOne(SELECTOR_DIALOG, this._element)
+    this._backdrop = this._initializeBackDrop()
+    this._focustrap = this._initializeFocusTrap()
     this._isShown = false
-    this._isBodyOverflowing = false
-    this._ignoreBackdropClick = false
     this._isTransitioning = false
-    this._scrollbarWidth = 0
+    this._scrollBar = new ScrollBarHelper()
+
+    this._addEventListeners()
   }
 
   // Getters
+  static get Default() {
+    return Default
+  }
 
-  static get VERSION() {
-    return VERSION
+  static get DefaultType() {
+    return DefaultType
   }
 
-  static get Default() {
-    return Default
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   toggle(relatedTarget) {
     return this._isShown ? this.hide() : this.show(relatedTarget)
   }
@@ -104,114 +98,54 @@ class Modal {
       return
     }
 
-    if ($(this._element).hasClass(CLASS_NAME_FADE)) {
-      this._isTransitioning = true
-    }
-
-    const showEvent = $.Event(EVENT_SHOW, {
+    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, {
       relatedTarget
     })
 
-    $(this._element).trigger(showEvent)
-
-    if (this._isShown || showEvent.isDefaultPrevented()) {
+    if (showEvent.defaultPrevented) {
       return
     }
 
     this._isShown = true
+    this._isTransitioning = true
 
-    this._checkScrollbar()
-    this._setScrollbar()
-
-    this._adjustDialog()
-
-    this._setEscapeEvent()
-    this._setResizeEvent()
+    this._scrollBar.hide()
 
-    $(this._element).on(
-      EVENT_CLICK_DISMISS,
-      SELECTOR_DATA_DISMISS,
-      event => this.hide(event)
-    )
+    document.body.classList.add(CLASS_NAME_OPEN)
 
-    $(this._dialog).on(EVENT_MOUSEDOWN_DISMISS, () => {
-      $(this._element).one(EVENT_MOUSEUP_DISMISS, event => {
-        if ($(event.target).is(this._element)) {
-          this._ignoreBackdropClick = true
-        }
-      })
-    })
+    this._adjustDialog()
 
-    this._showBackdrop(() => this._showElement(relatedTarget))
+    this._backdrop.show(() => this._showElement(relatedTarget))
   }
 
-  hide(event) {
-    if (event) {
-      event.preventDefault()
-    }
-
+  hide() {
     if (!this._isShown || this._isTransitioning) {
       return
     }
 
-    const hideEvent = $.Event(EVENT_HIDE)
+    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
 
-    $(this._element).trigger(hideEvent)
-
-    if (!this._isShown || hideEvent.isDefaultPrevented()) {
+    if (hideEvent.defaultPrevented) {
       return
     }
 
     this._isShown = false
-    const transition = $(this._element).hasClass(CLASS_NAME_FADE)
-
-    if (transition) {
-      this._isTransitioning = true
-    }
-
-    this._setEscapeEvent()
-    this._setResizeEvent()
-
-    $(document).off(EVENT_FOCUSIN)
+    this._isTransitioning = true
+    this._focustrap.deactivate()
 
-    $(this._element).removeClass(CLASS_NAME_SHOW)
+    this._element.classList.remove(CLASS_NAME_SHOW)
 
-    $(this._element).off(EVENT_CLICK_DISMISS)
-    $(this._dialog).off(EVENT_MOUSEDOWN_DISMISS)
-
-    if (transition) {
-      const transitionDuration = Util.getTransitionDurationFromElement(this._element)
-
-      $(this._element)
-        .one(Util.TRANSITION_END, event => this._hideModal(event))
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      this._hideModal()
-    }
+    this._queueCallback(() => this._hideModal(), this._element, this._isAnimated())
   }
 
   dispose() {
-    [window, this._element, this._dialog]
-      .forEach(htmlElement => $(htmlElement).off(EVENT_KEY))
-
-    /**
-     * `document` has 2 events `EVENT_FOCUSIN` and `EVENT_CLICK_DATA_API`
-     * Do not move `document` in `htmlElements` array
-     * It will remove `EVENT_CLICK_DATA_API` event that should remain
-     */
-    $(document).off(EVENT_FOCUSIN)
-
-    $.removeData(this._element, DATA_KEY)
-
-    this._config = null
-    this._element = null
-    this._dialog = null
-    this._backdrop = null
-    this._isShown = null
-    this._isBodyOverflowing = null
-    this._ignoreBackdropClick = null
-    this._isTransitioning = null
-    this._scrollbarWidth = null
+    EventHandler.off(window, EVENT_KEY)
+    EventHandler.off(this._dialog, EVENT_KEY)
+
+    this._backdrop.dispose()
+    this._focustrap.deactivate()
+
+    super.dispose()
   }
 
   handleUpdate() {
@@ -219,248 +153,157 @@ class Modal {
   }
 
   // Private
-
-  _getConfig(config) {
-    config = {
-      ...Default,
-      ...config
-    }
-    Util.typeCheckConfig(NAME, config, DefaultType)
-    return config
+  _initializeBackDrop() {
+    return new Backdrop({
+      isVisible: Boolean(this._config.backdrop), // 'static' option will be translated to true, and booleans will keep their value,
+      isAnimated: this._isAnimated()
+    })
   }
 
-  _triggerBackdropTransition() {
-    const hideEventPrevented = $.Event(EVENT_HIDE_PREVENTED)
-
-    $(this._element).trigger(hideEventPrevented)
-    if (hideEventPrevented.isDefaultPrevented()) {
-      return
-    }
-
-    const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
-
-    if (!isModalOverflowing) {
-      this._element.style.overflowY = 'hidden'
-    }
-
-    this._element.classList.add(CLASS_NAME_STATIC)
-
-    const modalTransitionDuration = Util.getTransitionDurationFromElement(this._dialog)
-    $(this._element).off(Util.TRANSITION_END)
-
-    $(this._element).one(Util.TRANSITION_END, () => {
-      this._element.classList.remove(CLASS_NAME_STATIC)
-      if (!isModalOverflowing) {
-        $(this._element).one(Util.TRANSITION_END, () => {
-          this._element.style.overflowY = ''
-        })
-          .emulateTransitionEnd(this._element, modalTransitionDuration)
-      }
+  _initializeFocusTrap() {
+    return new FocusTrap({
+      trapElement: this._element
     })
-      .emulateTransitionEnd(modalTransitionDuration)
-    this._element.focus()
   }
 
   _showElement(relatedTarget) {
-    const transition = $(this._element).hasClass(CLASS_NAME_FADE)
-    const modalBody = this._dialog ? this._dialog.querySelector(SELECTOR_MODAL_BODY) : null
-
-    if (!this._element.parentNode ||
-        this._element.parentNode.nodeType !== Node.ELEMENT_NODE) {
-      // Don't move modal's DOM position
-      document.body.appendChild(this._element)
+    // try to append dynamic modal
+    if (!document.body.contains(this._element)) {
+      document.body.append(this._element)
     }
 
     this._element.style.display = 'block'
     this._element.removeAttribute('aria-hidden')
     this._element.setAttribute('aria-modal', true)
     this._element.setAttribute('role', 'dialog')
+    this._element.scrollTop = 0
 
-    if ($(this._dialog).hasClass(CLASS_NAME_SCROLLABLE) && modalBody) {
+    const modalBody = SelectorEngine.findOne(SELECTOR_MODAL_BODY, this._dialog)
+    if (modalBody) {
       modalBody.scrollTop = 0
-    } else {
-      this._element.scrollTop = 0
     }
 
-    if (transition) {
-      Util.reflow(this._element)
-    }
-
-    $(this._element).addClass(CLASS_NAME_SHOW)
-
-    if (this._config.focus) {
-      this._enforceFocus()
-    }
+    reflow(this._element)
 
-    const shownEvent = $.Event(EVENT_SHOWN, {
-      relatedTarget
-    })
+    this._element.classList.add(CLASS_NAME_SHOW)
 
     const transitionComplete = () => {
       if (this._config.focus) {
-        this._element.focus()
+        this._focustrap.activate()
       }
 
       this._isTransitioning = false
-      $(this._element).trigger(shownEvent)
-    }
-
-    if (transition) {
-      const transitionDuration = Util.getTransitionDurationFromElement(this._dialog)
-
-      $(this._dialog)
-        .one(Util.TRANSITION_END, transitionComplete)
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      transitionComplete()
-    }
-  }
-
-  _enforceFocus() {
-    $(document)
-      .off(EVENT_FOCUSIN) // Guard against infinite focus loop
-      .on(EVENT_FOCUSIN, event => {
-        if (document !== event.target &&
-            this._element !== event.target &&
-            $(this._element).has(event.target).length === 0) {
-          this._element.focus()
-        }
+      EventHandler.trigger(this._element, EVENT_SHOWN, {
+        relatedTarget
       })
-  }
-
-  _setEscapeEvent() {
-    if (this._isShown) {
-      $(this._element).on(EVENT_KEYDOWN_DISMISS, event => {
-        if (this._config.keyboard && event.which === ESCAPE_KEYCODE) {
-          event.preventDefault()
-          this.hide()
-        } else if (!this._config.keyboard && event.which === ESCAPE_KEYCODE) {
-          this._triggerBackdropTransition()
-        }
-      })
-    } else if (!this._isShown) {
-      $(this._element).off(EVENT_KEYDOWN_DISMISS)
     }
-  }
 
-  _setResizeEvent() {
-    if (this._isShown) {
-      $(window).on(EVENT_RESIZE, event => this.handleUpdate(event))
-    } else {
-      $(window).off(EVENT_RESIZE)
-    }
-  }
-
-  _hideModal() {
-    this._element.style.display = 'none'
-    this._element.setAttribute('aria-hidden', true)
-    this._element.removeAttribute('aria-modal')
-    this._element.removeAttribute('role')
-    this._isTransitioning = false
-    this._showBackdrop(() => {
-      $(document.body).removeClass(CLASS_NAME_OPEN)
-      this._resetAdjustments()
-      this._resetScrollbar()
-      $(this._element).trigger(EVENT_HIDDEN)
-    })
+    this._queueCallback(transitionComplete, this._dialog, this._isAnimated())
   }
 
-  _removeBackdrop() {
-    if (this._backdrop) {
-      $(this._backdrop).remove()
-      this._backdrop = null
-    }
-  }
+  _addEventListeners() {
+    EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
+      if (event.key !== ESCAPE_KEY) {
+        return
+      }
 
-  _showBackdrop(callback) {
-    const animate = $(this._element).hasClass(CLASS_NAME_FADE) ?
-      CLASS_NAME_FADE : ''
+      if (this._config.keyboard) {
+        this.hide()
+        return
+      }
 
-    if (this._isShown && this._config.backdrop) {
-      this._backdrop = document.createElement('div')
-      this._backdrop.className = CLASS_NAME_BACKDROP
+      this._triggerBackdropTransition()
+    })
 
-      if (animate) {
-        this._backdrop.classList.add(animate)
+    EventHandler.on(window, EVENT_RESIZE, () => {
+      if (this._isShown && !this._isTransitioning) {
+        this._adjustDialog()
       }
+    })
 
-      $(this._backdrop).appendTo(document.body)
-
-      $(this._element).on(EVENT_CLICK_DISMISS, event => {
-        if (this._ignoreBackdropClick) {
-          this._ignoreBackdropClick = false
+    EventHandler.on(this._element, EVENT_MOUSEDOWN_DISMISS, event => {
+      // a bad trick to segregate clicks that may start inside dialog but end outside, and avoid listen to scrollbar clicks
+      EventHandler.one(this._element, EVENT_CLICK_DISMISS, event2 => {
+        if (this._element !== event.target || this._element !== event2.target) {
           return
         }
 
-        if (event.target !== event.currentTarget) {
+        if (this._config.backdrop === 'static') {
+          this._triggerBackdropTransition()
           return
         }
 
-        if (this._config.backdrop === 'static') {
-          this._triggerBackdropTransition()
-        } else {
+        if (this._config.backdrop) {
           this.hide()
         }
       })
+    })
+  }
 
-      if (animate) {
-        Util.reflow(this._backdrop)
-      }
-
-      $(this._backdrop).addClass(CLASS_NAME_SHOW)
+  _hideModal() {
+    this._element.style.display = 'none'
+    this._element.setAttribute('aria-hidden', true)
+    this._element.removeAttribute('aria-modal')
+    this._element.removeAttribute('role')
+    this._isTransitioning = false
 
-      if (!callback) {
-        return
-      }
+    this._backdrop.hide(() => {
+      document.body.classList.remove(CLASS_NAME_OPEN)
+      this._resetAdjustments()
+      this._scrollBar.reset()
+      EventHandler.trigger(this._element, EVENT_HIDDEN)
+    })
+  }
 
-      if (!animate) {
-        callback()
-        return
-      }
+  _isAnimated() {
+    return this._element.classList.contains(CLASS_NAME_FADE)
+  }
 
-      const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
+  _triggerBackdropTransition() {
+    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
+    if (hideEvent.defaultPrevented) {
+      return
+    }
 
-      $(this._backdrop)
-        .one(Util.TRANSITION_END, callback)
-        .emulateTransitionEnd(backdropTransitionDuration)
-    } else if (!this._isShown && this._backdrop) {
-      $(this._backdrop).removeClass(CLASS_NAME_SHOW)
+    const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
+    const initialOverflowY = this._element.style.overflowY
+    // return if the following background transition hasn't yet completed
+    if (initialOverflowY === 'hidden' || this._element.classList.contains(CLASS_NAME_STATIC)) {
+      return
+    }
 
-      const callbackRemove = () => {
-        this._removeBackdrop()
-        if (callback) {
-          callback()
-        }
-      }
+    if (!isModalOverflowing) {
+      this._element.style.overflowY = 'hidden'
+    }
 
-      if ($(this._element).hasClass(CLASS_NAME_FADE)) {
-        const backdropTransitionDuration = Util.getTransitionDurationFromElement(this._backdrop)
+    this._element.classList.add(CLASS_NAME_STATIC)
+    this._queueCallback(() => {
+      this._element.classList.remove(CLASS_NAME_STATIC)
+      this._queueCallback(() => {
+        this._element.style.overflowY = initialOverflowY
+      }, this._dialog)
+    }, this._dialog)
 
-        $(this._backdrop)
-          .one(Util.TRANSITION_END, callbackRemove)
-          .emulateTransitionEnd(backdropTransitionDuration)
-      } else {
-        callbackRemove()
-      }
-    } else if (callback) {
-      callback()
-    }
+    this._element.focus()
   }
 
-  // ----------------------------------------------------------------------
-  // the following methods are used to handle overflowing modals
-  // todo (fat): these should probably be refactored out of modal.js
-  // ----------------------------------------------------------------------
+  /**
+   * The following methods are used to handle overflowing modals
+   */
 
   _adjustDialog() {
     const isModalOverflowing = this._element.scrollHeight > document.documentElement.clientHeight
+    const scrollbarWidth = this._scrollBar.getWidth()
+    const isBodyOverflowing = scrollbarWidth > 0
 
-    if (!this._isBodyOverflowing && isModalOverflowing) {
-      this._element.style.paddingLeft = `${this._scrollbarWidth}px`
+    if (isBodyOverflowing && !isModalOverflowing) {
+      const property = isRTL() ? 'paddingLeft' : 'paddingRight'
+      this._element.style[property] = `${scrollbarWidth}px`
     }
 
-    if (this._isBodyOverflowing && !isModalOverflowing) {
-      this._element.style.paddingRight = `${this._scrollbarWidth}px`
+    if (!isBodyOverflowing && isModalOverflowing) {
+      const property = isRTL() ? 'paddingRight' : 'paddingLeft'
+      this._element.style[property] = `${scrollbarWidth}px`
     }
   }
 
@@ -469,161 +312,65 @@ class Modal {
     this._element.style.paddingRight = ''
   }
 
-  _checkScrollbar() {
-    const rect = document.body.getBoundingClientRect()
-    this._isBodyOverflowing = Math.round(rect.left + rect.right) < window.innerWidth
-    this._scrollbarWidth = this._getScrollbarWidth()
-  }
-
-  _setScrollbar() {
-    if (this._isBodyOverflowing) {
-      // Note: DOMNode.style.paddingRight returns the actual value or '' if not set
-      //   while $(DOMNode).css('padding-right') returns the calculated value or 0 if not set
-      const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT))
-      const stickyContent = [].slice.call(document.querySelectorAll(SELECTOR_STICKY_CONTENT))
-
-      // Adjust fixed content padding
-      $(fixedContent).each((index, element) => {
-        const actualPadding = element.style.paddingRight
-        const calculatedPadding = $(element).css('padding-right')
-        $(element)
-          .data('padding-right', actualPadding)
-          .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)
-      })
-
-      // Adjust sticky content margin
-      $(stickyContent).each((index, element) => {
-        const actualMargin = element.style.marginRight
-        const calculatedMargin = $(element).css('margin-right')
-        $(element)
-          .data('margin-right', actualMargin)
-          .css('margin-right', `${parseFloat(calculatedMargin) - this._scrollbarWidth}px`)
-      })
-
-      // Adjust body padding
-      const actualPadding = document.body.style.paddingRight
-      const calculatedPadding = $(document.body).css('padding-right')
-      $(document.body)
-        .data('padding-right', actualPadding)
-        .css('padding-right', `${parseFloat(calculatedPadding) + this._scrollbarWidth}px`)
-    }
-
-    $(document.body).addClass(CLASS_NAME_OPEN)
-  }
-
-  _resetScrollbar() {
-    // Restore fixed content padding
-    const fixedContent = [].slice.call(document.querySelectorAll(SELECTOR_FIXED_CONTENT))
-    $(fixedContent).each((index, element) => {
-      const padding = $(element).data('padding-right')
-      $(element).removeData('padding-right')
-      element.style.paddingRight = padding ? padding : ''
-    })
-
-    // Restore sticky content
-    const elements = [].slice.call(document.querySelectorAll(`${SELECTOR_STICKY_CONTENT}`))
-    $(elements).each((index, element) => {
-      const margin = $(element).data('margin-right')
-      if (typeof margin !== 'undefined') {
-        $(element).css('margin-right', margin).removeData('margin-right')
-      }
-    })
-
-    // Restore body padding
-    const padding = $(document.body).data('padding-right')
-    $(document.body).removeData('padding-right')
-    document.body.style.paddingRight = padding ? padding : ''
-  }
-
-  _getScrollbarWidth() { // thx d.walsh
-    const scrollDiv = document.createElement('div')
-    scrollDiv.className = CLASS_NAME_SCROLLBAR_MEASURER
-    document.body.appendChild(scrollDiv)
-    const scrollbarWidth = scrollDiv.getBoundingClientRect().width - scrollDiv.clientWidth
-    document.body.removeChild(scrollDiv)
-    return scrollbarWidth
-  }
-
   // Static
-
-  static _jQueryInterface(config, relatedTarget) {
+  static jQueryInterface(config, relatedTarget) {
     return this.each(function () {
-      let data = $(this).data(DATA_KEY)
-      const _config = {
-        ...Default,
-        ...$(this).data(),
-        ...(typeof config === 'object' && config ? config : {})
-      }
+      const data = Modal.getOrCreateInstance(this, config)
 
-      if (!data) {
-        data = new Modal(this, _config)
-        $(this).data(DATA_KEY, data)
+      if (typeof config !== 'string') {
+        return
       }
 
-      if (typeof config === 'string') {
-        if (typeof data[config] === 'undefined') {
-          throw new TypeError(`No method named "${config}"`)
-        }
-
-        data[config](relatedTarget)
-      } else if (_config.show) {
-        data.show(relatedTarget)
+      if (typeof data[config] === 'undefined') {
+        throw new TypeError(`No method named "${config}"`)
       }
+
+      data[config](relatedTarget)
     })
   }
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document).on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
-  let target
-  const selector = Util.getSelectorFromElement(this)
-
-  if (selector) {
-    target = document.querySelector(selector)
-  }
-
-  const config = $(target).data(DATA_KEY) ?
-    'toggle' : {
-      ...$(target).data(),
-      ...$(this).data()
-    }
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+  const target = SelectorEngine.getElementFromSelector(this)
 
-  if (this.tagName === 'A' || this.tagName === 'AREA') {
+  if (['A', 'AREA'].includes(this.tagName)) {
     event.preventDefault()
   }
 
-  const $target = $(target).one(EVENT_SHOW, showEvent => {
-    if (showEvent.isDefaultPrevented()) {
-      // Only register focus restorer if modal will actually get shown
+  EventHandler.one(target, EVENT_SHOW, showEvent => {
+    if (showEvent.defaultPrevented) {
+      // only register focus restorer if modal will actually get shown
       return
     }
 
-    $target.one(EVENT_HIDDEN, () => {
-      if ($(this).is(':visible')) {
+    EventHandler.one(target, EVENT_HIDDEN, () => {
+      if (isVisible(this)) {
         this.focus()
       }
     })
   })
 
-  Modal._jQueryInterface.call($(target), config, this)
+  // avoid conflict when clicking modal toggler while another one is open
+  const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)
+  if (alreadyOpen) {
+    Modal.getInstance(alreadyOpen).hide()
+  }
+
+  const data = Modal.getOrCreateInstance(target)
+
+  data.toggle(this)
 })
 
+enableDismissTrigger(Modal)
+
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Modal._jQueryInterface
-$.fn[NAME].Constructor = Modal
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Modal._jQueryInterface
-}
+defineJQueryPlugin(Modal)
 
 export default Modal

+ 282 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/offcanvas.js

@@ -0,0 +1,282 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap offcanvas.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import SelectorEngine from './dom/selector-engine.js'
+import Backdrop from './util/backdrop.js'
+import { enableDismissTrigger } from './util/component-functions.js'
+import FocusTrap from './util/focustrap.js'
+import {
+  defineJQueryPlugin,
+  isDisabled,
+  isVisible
+} from './util/index.js'
+import ScrollBarHelper from './util/scrollbar.js'
+
+/**
+ * Constants
+ */
+
+const NAME = 'offcanvas'
+const DATA_KEY = 'bs.offcanvas'
+const EVENT_KEY = `.${DATA_KEY}`
+const DATA_API_KEY = '.data-api'
+const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
+const ESCAPE_KEY = 'Escape'
+
+const CLASS_NAME_SHOW = 'show'
+const CLASS_NAME_SHOWING = 'showing'
+const CLASS_NAME_HIDING = 'hiding'
+const CLASS_NAME_BACKDROP = 'offcanvas-backdrop'
+const OPEN_SELECTOR = '.offcanvas.show'
+
+const EVENT_SHOW = `show${EVENT_KEY}`
+const EVENT_SHOWN = `shown${EVENT_KEY}`
+const EVENT_HIDE = `hide${EVENT_KEY}`
+const EVENT_HIDE_PREVENTED = `hidePrevented${EVENT_KEY}`
+const EVENT_HIDDEN = `hidden${EVENT_KEY}`
+const EVENT_RESIZE = `resize${EVENT_KEY}`
+const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
+const EVENT_KEYDOWN_DISMISS = `keydown.dismiss${EVENT_KEY}`
+
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="offcanvas"]'
+
+const Default = {
+  backdrop: true,
+  keyboard: true,
+  scroll: false
+}
+
+const DefaultType = {
+  backdrop: '(boolean|string)',
+  keyboard: 'boolean',
+  scroll: 'boolean'
+}
+
+/**
+ * Class definition
+ */
+
+class Offcanvas extends BaseComponent {
+  constructor(element, config) {
+    super(element, config)
+
+    this._isShown = false
+    this._backdrop = this._initializeBackDrop()
+    this._focustrap = this._initializeFocusTrap()
+    this._addEventListeners()
+  }
+
+  // Getters
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
+  }
+
+  // Public
+  toggle(relatedTarget) {
+    return this._isShown ? this.hide() : this.show(relatedTarget)
+  }
+
+  show(relatedTarget) {
+    if (this._isShown) {
+      return
+    }
+
+    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW, { relatedTarget })
+
+    if (showEvent.defaultPrevented) {
+      return
+    }
+
+    this._isShown = true
+    this._backdrop.show()
+
+    if (!this._config.scroll) {
+      new ScrollBarHelper().hide()
+    }
+
+    this._element.setAttribute('aria-modal', true)
+    this._element.setAttribute('role', 'dialog')
+    this._element.classList.add(CLASS_NAME_SHOWING)
+
+    const completeCallBack = () => {
+      if (!this._config.scroll || this._config.backdrop) {
+        this._focustrap.activate()
+      }
+
+      this._element.classList.add(CLASS_NAME_SHOW)
+      this._element.classList.remove(CLASS_NAME_SHOWING)
+      EventHandler.trigger(this._element, EVENT_SHOWN, { relatedTarget })
+    }
+
+    this._queueCallback(completeCallBack, this._element, true)
+  }
+
+  hide() {
+    if (!this._isShown) {
+      return
+    }
+
+    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
+
+    if (hideEvent.defaultPrevented) {
+      return
+    }
+
+    this._focustrap.deactivate()
+    this._element.blur()
+    this._isShown = false
+    this._element.classList.add(CLASS_NAME_HIDING)
+    this._backdrop.hide()
+
+    const completeCallback = () => {
+      this._element.classList.remove(CLASS_NAME_SHOW, CLASS_NAME_HIDING)
+      this._element.removeAttribute('aria-modal')
+      this._element.removeAttribute('role')
+
+      if (!this._config.scroll) {
+        new ScrollBarHelper().reset()
+      }
+
+      EventHandler.trigger(this._element, EVENT_HIDDEN)
+    }
+
+    this._queueCallback(completeCallback, this._element, true)
+  }
+
+  dispose() {
+    this._backdrop.dispose()
+    this._focustrap.deactivate()
+    super.dispose()
+  }
+
+  // Private
+  _initializeBackDrop() {
+    const clickCallback = () => {
+      if (this._config.backdrop === 'static') {
+        EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
+        return
+      }
+
+      this.hide()
+    }
+
+    // 'static' option will be translated to true, and booleans will keep their value
+    const isVisible = Boolean(this._config.backdrop)
+
+    return new Backdrop({
+      className: CLASS_NAME_BACKDROP,
+      isVisible,
+      isAnimated: true,
+      rootElement: this._element.parentNode,
+      clickCallback: isVisible ? clickCallback : null
+    })
+  }
+
+  _initializeFocusTrap() {
+    return new FocusTrap({
+      trapElement: this._element
+    })
+  }
+
+  _addEventListeners() {
+    EventHandler.on(this._element, EVENT_KEYDOWN_DISMISS, event => {
+      if (event.key !== ESCAPE_KEY) {
+        return
+      }
+
+      if (this._config.keyboard) {
+        this.hide()
+        return
+      }
+
+      EventHandler.trigger(this._element, EVENT_HIDE_PREVENTED)
+    })
+  }
+
+  // Static
+  static jQueryInterface(config) {
+    return this.each(function () {
+      const data = Offcanvas.getOrCreateInstance(this, config)
+
+      if (typeof config !== 'string') {
+        return
+      }
+
+      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+        throw new TypeError(`No method named "${config}"`)
+      }
+
+      data[config](this)
+    })
+  }
+}
+
+/**
+ * Data API implementation
+ */
+
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+  const target = SelectorEngine.getElementFromSelector(this)
+
+  if (['A', 'AREA'].includes(this.tagName)) {
+    event.preventDefault()
+  }
+
+  if (isDisabled(this)) {
+    return
+  }
+
+  EventHandler.one(target, EVENT_HIDDEN, () => {
+    // focus on trigger when it is closed
+    if (isVisible(this)) {
+      this.focus()
+    }
+  })
+
+  // avoid conflict when clicking a toggler of an offcanvas, while another is open
+  const alreadyOpen = SelectorEngine.findOne(OPEN_SELECTOR)
+  if (alreadyOpen && alreadyOpen !== target) {
+    Offcanvas.getInstance(alreadyOpen).hide()
+  }
+
+  const data = Offcanvas.getOrCreateInstance(target)
+  data.toggle(this)
+})
+
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+  for (const selector of SelectorEngine.find(OPEN_SELECTOR)) {
+    Offcanvas.getOrCreateInstance(selector).show()
+  }
+})
+
+EventHandler.on(window, EVENT_RESIZE, () => {
+  for (const element of SelectorEngine.find('[aria-modal][class*=show][class*=offcanvas-]')) {
+    if (getComputedStyle(element).position !== 'fixed') {
+      Offcanvas.getOrCreateInstance(element).hide()
+    }
+  }
+})
+
+enableDismissTrigger(Offcanvas)
+
+/**
+ * jQuery
+ */
+
+defineJQueryPlugin(Offcanvas)
+
+export default Offcanvas

+ 33 - 118
coderedcms/static/coderedcms/vendor/bootstrap/js/src/popover.js

@@ -1,182 +1,97 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): popover.js
+ * Bootstrap popover.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Tooltip from './tooltip'
+import Tooltip from './tooltip.js'
+import { defineJQueryPlugin } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'popover'
-const VERSION = '4.6.0'
-const DATA_KEY = 'bs.popover'
-const EVENT_KEY = `.${DATA_KEY}`
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-const CLASS_PREFIX = 'bs-popover'
-const BSCLS_PREFIX_REGEX = new RegExp(`(^|\\s)${CLASS_PREFIX}\\S+`, 'g')
+
+const SELECTOR_TITLE = '.popover-header'
+const SELECTOR_CONTENT = '.popover-body'
 
 const Default = {
   ...Tooltip.Default,
-  placement: 'right',
-  trigger: 'click',
   content: '',
+  offset: [0, 8],
+  placement: 'right',
   template: '<div class="popover" role="tooltip">' +
-              '<div class="arrow"></div>' +
-              '<h3 class="popover-header"></h3>' +
-              '<div class="popover-body"></div></div>'
+    '<div class="popover-arrow"></div>' +
+    '<h3 class="popover-header"></h3>' +
+    '<div class="popover-body"></div>' +
+    '</div>',
+  trigger: 'click'
 }
 
 const DefaultType = {
   ...Tooltip.DefaultType,
-  content: '(string|element|function)'
-}
-
-const CLASS_NAME_FADE = 'fade'
-const CLASS_NAME_SHOW = 'show'
-
-const SELECTOR_TITLE = '.popover-header'
-const SELECTOR_CONTENT = '.popover-body'
-
-const Event = {
-  HIDE: `hide${EVENT_KEY}`,
-  HIDDEN: `hidden${EVENT_KEY}`,
-  SHOW: `show${EVENT_KEY}`,
-  SHOWN: `shown${EVENT_KEY}`,
-  INSERTED: `inserted${EVENT_KEY}`,
-  CLICK: `click${EVENT_KEY}`,
-  FOCUSIN: `focusin${EVENT_KEY}`,
-  FOCUSOUT: `focusout${EVENT_KEY}`,
-  MOUSEENTER: `mouseenter${EVENT_KEY}`,
-  MOUSELEAVE: `mouseleave${EVENT_KEY}`
+  content: '(null|string|element|function)'
 }
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
 class Popover extends Tooltip {
   // Getters
-
-  static get VERSION() {
-    return VERSION
-  }
-
   static get Default() {
     return Default
   }
 
-  static get NAME() {
-    return NAME
-  }
-
-  static get DATA_KEY() {
-    return DATA_KEY
-  }
-
-  static get Event() {
-    return Event
-  }
-
-  static get EVENT_KEY() {
-    return EVENT_KEY
-  }
-
   static get DefaultType() {
     return DefaultType
   }
 
-  // Overrides
-
-  isWithContent() {
-    return this.getTitle() || this._getContent()
-  }
-
-  addAttachmentClass(attachment) {
-    $(this.getTipElement()).addClass(`${CLASS_PREFIX}-${attachment}`)
+  static get NAME() {
+    return NAME
   }
 
-  getTipElement() {
-    this.tip = this.tip || $(this.config.template)[0]
-    return this.tip
+  // Overrides
+  _isWithContent() {
+    return this._getTitle() || this._getContent()
   }
 
-  setContent() {
-    const $tip = $(this.getTipElement())
-
-    // We use append for html objects to maintain js events
-    this.setElementContent($tip.find(SELECTOR_TITLE), this.getTitle())
-    let content = this._getContent()
-    if (typeof content === 'function') {
-      content = content.call(this.element)
+  // Private
+  _getContentForTemplate() {
+    return {
+      [SELECTOR_TITLE]: this._getTitle(),
+      [SELECTOR_CONTENT]: this._getContent()
     }
-
-    this.setElementContent($tip.find(SELECTOR_CONTENT), content)
-
-    $tip.removeClass(`${CLASS_NAME_FADE} ${CLASS_NAME_SHOW}`)
   }
 
-  // Private
-
   _getContent() {
-    return this.element.getAttribute('data-content') ||
-      this.config.content
-  }
-
-  _cleanTipClass() {
-    const $tip = $(this.getTipElement())
-    const tabClass = $tip.attr('class').match(BSCLS_PREFIX_REGEX)
-    if (tabClass !== null && tabClass.length > 0) {
-      $tip.removeClass(tabClass.join(''))
-    }
+    return this._resolvePossibleFunction(this._config.content)
   }
 
   // Static
-
-  static _jQueryInterface(config) {
+  static jQueryInterface(config) {
     return this.each(function () {
-      let data = $(this).data(DATA_KEY)
-      const _config = typeof config === 'object' ? config : null
+      const data = Popover.getOrCreateInstance(this, config)
 
-      if (!data && /dispose|hide/.test(config)) {
+      if (typeof config !== 'string') {
         return
       }
 
-      if (!data) {
-        data = new Popover(this, _config)
-        $(this).data(DATA_KEY, data)
+      if (typeof data[config] === 'undefined') {
+        throw new TypeError(`No method named "${config}"`)
       }
 
-      if (typeof config === 'string') {
-        if (typeof data[config] === 'undefined') {
-          throw new TypeError(`No method named "${config}"`)
-        }
-
-        data[config]()
-      }
+      data[config]()
     })
   }
 }
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Popover._jQueryInterface
-$.fn[NAME].Constructor = Popover
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Popover._jQueryInterface
-}
+defineJQueryPlugin(Popover)
 
 export default Popover

+ 182 - 212
coderedcms/static/coderedcms/vendor/bootstrap/js/src/scrollspy.js

@@ -1,324 +1,294 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): scrollspy.js
+ * Bootstrap scrollspy.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import SelectorEngine from './dom/selector-engine.js'
+import { defineJQueryPlugin, getElement, isDisabled, isVisible } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'scrollspy'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.scrollspy'
 const EVENT_KEY = `.${DATA_KEY}`
 const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
-
-const Default = {
-  offset: 10,
-  method: 'auto',
-  target: ''
-}
-
-const DefaultType = {
-  offset: 'number',
-  method: 'string',
-  target: '(string|element)'
-}
 
 const EVENT_ACTIVATE = `activate${EVENT_KEY}`
-const EVENT_SCROLL = `scroll${EVENT_KEY}`
+const EVENT_CLICK = `click${EVENT_KEY}`
 const EVENT_LOAD_DATA_API = `load${EVENT_KEY}${DATA_API_KEY}`
 
 const CLASS_NAME_DROPDOWN_ITEM = 'dropdown-item'
 const CLASS_NAME_ACTIVE = 'active'
 
-const SELECTOR_DATA_SPY = '[data-spy="scroll"]'
+const SELECTOR_DATA_SPY = '[data-bs-spy="scroll"]'
+const SELECTOR_TARGET_LINKS = '[href]'
 const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
 const SELECTOR_NAV_LINKS = '.nav-link'
 const SELECTOR_NAV_ITEMS = '.nav-item'
 const SELECTOR_LIST_ITEMS = '.list-group-item'
+const SELECTOR_LINK_ITEMS = `${SELECTOR_NAV_LINKS}, ${SELECTOR_NAV_ITEMS} > ${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`
 const SELECTOR_DROPDOWN = '.dropdown'
-const SELECTOR_DROPDOWN_ITEMS = '.dropdown-item'
 const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
 
-const METHOD_OFFSET = 'offset'
-const METHOD_POSITION = 'position'
+const Default = {
+  offset: null, // TODO: v6 @deprecated, keep it for backwards compatibility reasons
+  rootMargin: '0px 0px -25%',
+  smoothScroll: false,
+  target: null,
+  threshold: [0.1, 0.5, 1]
+}
+
+const DefaultType = {
+  offset: '(number|null)', // TODO v6 @deprecated, keep it for backwards compatibility reasons
+  rootMargin: 'string',
+  smoothScroll: 'boolean',
+  target: 'element',
+  threshold: 'array'
+}
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class ScrollSpy {
+class ScrollSpy extends BaseComponent {
   constructor(element, config) {
-    this._element = element
-    this._scrollElement = element.tagName === 'BODY' ? window : element
-    this._config = this._getConfig(config)
-    this._selector = `${this._config.target} ${SELECTOR_NAV_LINKS},` +
-                          `${this._config.target} ${SELECTOR_LIST_ITEMS},` +
-                          `${this._config.target} ${SELECTOR_DROPDOWN_ITEMS}`
-    this._offsets = []
-    this._targets = []
-    this._activeTarget = null
-    this._scrollHeight = 0
-
-    $(this._scrollElement).on(EVENT_SCROLL, event => this._process(event))
+    super(element, config)
 
-    this.refresh()
-    this._process()
+    // this._element is the observablesContainer and config.target the menu links wrapper
+    this._targetLinks = new Map()
+    this._observableSections = new Map()
+    this._rootElement = getComputedStyle(this._element).overflowY === 'visible' ? null : this._element
+    this._activeTarget = null
+    this._observer = null
+    this._previousScrollData = {
+      visibleEntryTop: 0,
+      parentScrollTop: 0
+    }
+    this.refresh() // initialize
   }
 
   // Getters
+  static get Default() {
+    return Default
+  }
 
-  static get VERSION() {
-    return VERSION
+  static get DefaultType() {
+    return DefaultType
   }
 
-  static get Default() {
-    return Default
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   refresh() {
-    const autoMethod = this._scrollElement === this._scrollElement.window ?
-      METHOD_OFFSET : METHOD_POSITION
-
-    const offsetMethod = this._config.method === 'auto' ?
-      autoMethod : this._config.method
-
-    const offsetBase = offsetMethod === METHOD_POSITION ?
-      this._getScrollTop() : 0
-
-    this._offsets = []
-    this._targets = []
-
-    this._scrollHeight = this._getScrollHeight()
+    this._initializeTargetsAndObservables()
+    this._maybeEnableSmoothScroll()
 
-    const targets = [].slice.call(document.querySelectorAll(this._selector))
-
-    targets
-      .map(element => {
-        let target
-        const targetSelector = Util.getSelectorFromElement(element)
-
-        if (targetSelector) {
-          target = document.querySelector(targetSelector)
-        }
-
-        if (target) {
-          const targetBCR = target.getBoundingClientRect()
-          if (targetBCR.width || targetBCR.height) {
-            // TODO (fat): remove sketch reliance on jQuery position/offset
-            return [
-              $(target)[offsetMethod]().top + offsetBase,
-              targetSelector
-            ]
-          }
-        }
+    if (this._observer) {
+      this._observer.disconnect()
+    } else {
+      this._observer = this._getNewObserver()
+    }
 
-        return null
-      })
-      .filter(item => item)
-      .sort((a, b) => a[0] - b[0])
-      .forEach(item => {
-        this._offsets.push(item[0])
-        this._targets.push(item[1])
-      })
+    for (const section of this._observableSections.values()) {
+      this._observer.observe(section)
+    }
   }
 
   dispose() {
-    $.removeData(this._element, DATA_KEY)
-    $(this._scrollElement).off(EVENT_KEY)
-
-    this._element = null
-    this._scrollElement = null
-    this._config = null
-    this._selector = null
-    this._offsets = null
-    this._targets = null
-    this._activeTarget = null
-    this._scrollHeight = null
+    this._observer.disconnect()
+    super.dispose()
   }
 
   // Private
+  _configAfterMerge(config) {
+    // TODO: on v6 target should be given explicitly & remove the {target: 'ss-target'} case
+    config.target = getElement(config.target) || document.body
+
+    // TODO: v6 Only for backwards compatibility reasons. Use rootMargin only
+    config.rootMargin = config.offset ? `${config.offset}px 0px -30%` : config.rootMargin
 
-  _getConfig(config) {
-    config = {
-      ...Default,
-      ...(typeof config === 'object' && config ? config : {})
+    if (typeof config.threshold === 'string') {
+      config.threshold = config.threshold.split(',').map(value => Number.parseFloat(value))
     }
 
-    if (typeof config.target !== 'string' && Util.isElement(config.target)) {
-      let id = $(config.target).attr('id')
-      if (!id) {
-        id = Util.getUID(NAME)
-        $(config.target).attr('id', id)
-      }
+    return config
+  }
 
-      config.target = `#${id}`
+  _maybeEnableSmoothScroll() {
+    if (!this._config.smoothScroll) {
+      return
     }
 
-    Util.typeCheckConfig(NAME, config, DefaultType)
+    // unregister any previous listeners
+    EventHandler.off(this._config.target, EVENT_CLICK)
+
+    EventHandler.on(this._config.target, EVENT_CLICK, SELECTOR_TARGET_LINKS, event => {
+      const observableSection = this._observableSections.get(event.target.hash)
+      if (observableSection) {
+        event.preventDefault()
+        const root = this._rootElement || window
+        const height = observableSection.offsetTop - this._element.offsetTop
+        if (root.scrollTo) {
+          root.scrollTo({ top: height, behavior: 'smooth' })
+          return
+        }
 
-    return config
+        // Chrome 60 doesn't support `scrollTo`
+        root.scrollTop = height
+      }
+    })
   }
 
-  _getScrollTop() {
-    return this._scrollElement === window ?
-      this._scrollElement.pageYOffset : this._scrollElement.scrollTop
-  }
+  _getNewObserver() {
+    const options = {
+      root: this._rootElement,
+      threshold: this._config.threshold,
+      rootMargin: this._config.rootMargin
+    }
 
-  _getScrollHeight() {
-    return this._scrollElement.scrollHeight || Math.max(
-      document.body.scrollHeight,
-      document.documentElement.scrollHeight
-    )
+    return new IntersectionObserver(entries => this._observerCallback(entries), options)
   }
 
-  _getOffsetHeight() {
-    return this._scrollElement === window ?
-      window.innerHeight : this._scrollElement.getBoundingClientRect().height
-  }
+  // The logic of selection
+  _observerCallback(entries) {
+    const targetElement = entry => this._targetLinks.get(`#${entry.target.id}`)
+    const activate = entry => {
+      this._previousScrollData.visibleEntryTop = entry.target.offsetTop
+      this._process(targetElement(entry))
+    }
 
-  _process() {
-    const scrollTop = this._getScrollTop() + this._config.offset
-    const scrollHeight = this._getScrollHeight()
-    const maxScroll = this._config.offset + scrollHeight - this._getOffsetHeight()
+    const parentScrollTop = (this._rootElement || document.documentElement).scrollTop
+    const userScrollsDown = parentScrollTop >= this._previousScrollData.parentScrollTop
+    this._previousScrollData.parentScrollTop = parentScrollTop
 
-    if (this._scrollHeight !== scrollHeight) {
-      this.refresh()
-    }
+    for (const entry of entries) {
+      if (!entry.isIntersecting) {
+        this._activeTarget = null
+        this._clearActiveClass(targetElement(entry))
+
+        continue
+      }
 
-    if (scrollTop >= maxScroll) {
-      const target = this._targets[this._targets.length - 1]
+      const entryIsLowerThanPrevious = entry.target.offsetTop >= this._previousScrollData.visibleEntryTop
+      // if we are scrolling down, pick the bigger offsetTop
+      if (userScrollsDown && entryIsLowerThanPrevious) {
+        activate(entry)
+        // if parent isn't scrolled, let's keep the first visible item, breaking the iteration
+        if (!parentScrollTop) {
+          return
+        }
 
-      if (this._activeTarget !== target) {
-        this._activate(target)
+        continue
       }
 
-      return
+      // if we are scrolling up, pick the smallest offsetTop
+      if (!userScrollsDown && !entryIsLowerThanPrevious) {
+        activate(entry)
+      }
     }
+  }
 
-    if (this._activeTarget && scrollTop < this._offsets[0] && this._offsets[0] > 0) {
-      this._activeTarget = null
-      this._clear()
-      return
-    }
+  _initializeTargetsAndObservables() {
+    this._targetLinks = new Map()
+    this._observableSections = new Map()
+
+    const targetLinks = SelectorEngine.find(SELECTOR_TARGET_LINKS, this._config.target)
+
+    for (const anchor of targetLinks) {
+      // ensure that the anchor has an id and is not disabled
+      if (!anchor.hash || isDisabled(anchor)) {
+        continue
+      }
 
-    for (let i = this._offsets.length; i--;) {
-      const isActiveTarget = this._activeTarget !== this._targets[i] &&
-          scrollTop >= this._offsets[i] &&
-          (typeof this._offsets[i + 1] === 'undefined' ||
-              scrollTop < this._offsets[i + 1])
+      const observableSection = SelectorEngine.findOne(decodeURI(anchor.hash), this._element)
 
-      if (isActiveTarget) {
-        this._activate(this._targets[i])
+      // ensure that the observableSection exists & is visible
+      if (isVisible(observableSection)) {
+        this._targetLinks.set(decodeURI(anchor.hash), anchor)
+        this._observableSections.set(anchor.hash, observableSection)
       }
     }
   }
 
-  _activate(target) {
-    this._activeTarget = target
+  _process(target) {
+    if (this._activeTarget === target) {
+      return
+    }
 
-    this._clear()
+    this._clearActiveClass(this._config.target)
+    this._activeTarget = target
+    target.classList.add(CLASS_NAME_ACTIVE)
+    this._activateParents(target)
 
-    const queries = this._selector
-      .split(',')
-      .map(selector => `${selector}[data-target="${target}"],${selector}[href="${target}"]`)
+    EventHandler.trigger(this._element, EVENT_ACTIVATE, { relatedTarget: target })
+  }
 
-    const $link = $([].slice.call(document.querySelectorAll(queries.join(','))))
+  _activateParents(target) {
+    // Activate dropdown parents
+    if (target.classList.contains(CLASS_NAME_DROPDOWN_ITEM)) {
+      SelectorEngine.findOne(SELECTOR_DROPDOWN_TOGGLE, target.closest(SELECTOR_DROPDOWN))
+        .classList.add(CLASS_NAME_ACTIVE)
+      return
+    }
 
-    if ($link.hasClass(CLASS_NAME_DROPDOWN_ITEM)) {
-      $link.closest(SELECTOR_DROPDOWN)
-        .find(SELECTOR_DROPDOWN_TOGGLE)
-        .addClass(CLASS_NAME_ACTIVE)
-      $link.addClass(CLASS_NAME_ACTIVE)
-    } else {
-      // Set triggered link as active
-      $link.addClass(CLASS_NAME_ACTIVE)
+    for (const listGroup of SelectorEngine.parents(target, SELECTOR_NAV_LIST_GROUP)) {
       // Set triggered links parents as active
       // With both <ul> and <nav> markup a parent is the previous sibling of any nav ancestor
-      $link.parents(SELECTOR_NAV_LIST_GROUP)
-        .prev(`${SELECTOR_NAV_LINKS}, ${SELECTOR_LIST_ITEMS}`)
-        .addClass(CLASS_NAME_ACTIVE)
-      // Handle special case when .nav-link is inside .nav-item
-      $link.parents(SELECTOR_NAV_LIST_GROUP)
-        .prev(SELECTOR_NAV_ITEMS)
-        .children(SELECTOR_NAV_LINKS)
-        .addClass(CLASS_NAME_ACTIVE)
+      for (const item of SelectorEngine.prev(listGroup, SELECTOR_LINK_ITEMS)) {
+        item.classList.add(CLASS_NAME_ACTIVE)
+      }
     }
-
-    $(this._scrollElement).trigger(EVENT_ACTIVATE, {
-      relatedTarget: target
-    })
   }
 
-  _clear() {
-    [].slice.call(document.querySelectorAll(this._selector))
-      .filter(node => node.classList.contains(CLASS_NAME_ACTIVE))
-      .forEach(node => node.classList.remove(CLASS_NAME_ACTIVE))
+  _clearActiveClass(parent) {
+    parent.classList.remove(CLASS_NAME_ACTIVE)
+
+    const activeNodes = SelectorEngine.find(`${SELECTOR_TARGET_LINKS}.${CLASS_NAME_ACTIVE}`, parent)
+    for (const node of activeNodes) {
+      node.classList.remove(CLASS_NAME_ACTIVE)
+    }
   }
 
   // Static
-
-  static _jQueryInterface(config) {
+  static jQueryInterface(config) {
     return this.each(function () {
-      let data = $(this).data(DATA_KEY)
-      const _config = typeof config === 'object' && config
+      const data = ScrollSpy.getOrCreateInstance(this, config)
 
-      if (!data) {
-        data = new ScrollSpy(this, _config)
-        $(this).data(DATA_KEY, data)
+      if (typeof config !== 'string') {
+        return
       }
 
-      if (typeof config === 'string') {
-        if (typeof data[config] === 'undefined') {
-          throw new TypeError(`No method named "${config}"`)
-        }
-
-        data[config]()
+      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+        throw new TypeError(`No method named "${config}"`)
       }
+
+      data[config]()
     })
   }
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(window).on(EVENT_LOAD_DATA_API, () => {
-  const scrollSpys = [].slice.call(document.querySelectorAll(SELECTOR_DATA_SPY))
-  const scrollSpysLength = scrollSpys.length
-
-  for (let i = scrollSpysLength; i--;) {
-    const $spy = $(scrollSpys[i])
-    ScrollSpy._jQueryInterface.call($spy, $spy.data())
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+  for (const spy of SelectorEngine.find(SELECTOR_DATA_SPY)) {
+    ScrollSpy.getOrCreateInstance(spy)
   }
 })
 
 /**
- * ------------------------------------------------------------------------
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = ScrollSpy._jQueryInterface
-$.fn[NAME].Constructor = ScrollSpy
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return ScrollSpy._jQueryInterface
-}
+defineJQueryPlugin(ScrollSpy)
 
 export default ScrollSpy

+ 210 - 150
coderedcms/static/coderedcms/vendor/bootstrap/js/src/tab.js

@@ -1,255 +1,315 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): tab.js
+ * Bootstrap tab.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import SelectorEngine from './dom/selector-engine.js'
+import { defineJQueryPlugin, getNextActiveElement, isDisabled } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'tab'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.tab'
 const EVENT_KEY = `.${DATA_KEY}`
-const DATA_API_KEY = '.data-api'
-const JQUERY_NO_CONFLICT = $.fn[NAME]
 
 const EVENT_HIDE = `hide${EVENT_KEY}`
 const EVENT_HIDDEN = `hidden${EVENT_KEY}`
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
-const EVENT_CLICK_DATA_API = `click${EVENT_KEY}${DATA_API_KEY}`
+const EVENT_CLICK_DATA_API = `click${EVENT_KEY}`
+const EVENT_KEYDOWN = `keydown${EVENT_KEY}`
+const EVENT_LOAD_DATA_API = `load${EVENT_KEY}`
+
+const ARROW_LEFT_KEY = 'ArrowLeft'
+const ARROW_RIGHT_KEY = 'ArrowRight'
+const ARROW_UP_KEY = 'ArrowUp'
+const ARROW_DOWN_KEY = 'ArrowDown'
+const HOME_KEY = 'Home'
+const END_KEY = 'End'
 
-const CLASS_NAME_DROPDOWN_MENU = 'dropdown-menu'
 const CLASS_NAME_ACTIVE = 'active'
-const CLASS_NAME_DISABLED = 'disabled'
 const CLASS_NAME_FADE = 'fade'
 const CLASS_NAME_SHOW = 'show'
+const CLASS_DROPDOWN = 'dropdown'
 
-const SELECTOR_DROPDOWN = '.dropdown'
-const SELECTOR_NAV_LIST_GROUP = '.nav, .list-group'
-const SELECTOR_ACTIVE = '.active'
-const SELECTOR_ACTIVE_UL = '> li > .active'
-const SELECTOR_DATA_TOGGLE = '[data-toggle="tab"], [data-toggle="pill"], [data-toggle="list"]'
 const SELECTOR_DROPDOWN_TOGGLE = '.dropdown-toggle'
-const SELECTOR_DROPDOWN_ACTIVE_CHILD = '> .dropdown-menu .active'
+const SELECTOR_DROPDOWN_MENU = '.dropdown-menu'
+const NOT_SELECTOR_DROPDOWN_TOGGLE = `:not(${SELECTOR_DROPDOWN_TOGGLE})`
+
+const SELECTOR_TAB_PANEL = '.list-group, .nav, [role="tablist"]'
+const SELECTOR_OUTER = '.nav-item, .list-group-item'
+const SELECTOR_INNER = `.nav-link${NOT_SELECTOR_DROPDOWN_TOGGLE}, .list-group-item${NOT_SELECTOR_DROPDOWN_TOGGLE}, [role="tab"]${NOT_SELECTOR_DROPDOWN_TOGGLE}`
+const SELECTOR_DATA_TOGGLE = '[data-bs-toggle="tab"], [data-bs-toggle="pill"], [data-bs-toggle="list"]' // TODO: could only be `tab` in v6
+const SELECTOR_INNER_ELEM = `${SELECTOR_INNER}, ${SELECTOR_DATA_TOGGLE}`
+
+const SELECTOR_DATA_TOGGLE_ACTIVE = `.${CLASS_NAME_ACTIVE}[data-bs-toggle="tab"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="pill"], .${CLASS_NAME_ACTIVE}[data-bs-toggle="list"]`
 
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Tab {
+class Tab extends BaseComponent {
   constructor(element) {
-    this._element = element
+    super(element)
+    this._parent = this._element.closest(SELECTOR_TAB_PANEL)
+
+    if (!this._parent) {
+      return
+      // TODO: should throw exception in v6
+      // throw new TypeError(`${element.outerHTML} has not a valid parent ${SELECTOR_INNER_ELEM}`)
+    }
+
+    // Set up initial aria attributes
+    this._setInitialAttributes(this._parent, this._getChildren())
+
+    EventHandler.on(this._element, EVENT_KEYDOWN, event => this._keydown(event))
   }
 
   // Getters
-
-  static get VERSION() {
-    return VERSION
+  static get NAME() {
+    return NAME
   }
 
   // Public
+  show() { // Shows this elem and deactivate the active sibling if exists
+    const innerElem = this._element
+    if (this._elemIsActive(innerElem)) {
+      return
+    }
+
+    // Search for active tab on same parent to deactivate it
+    const active = this._getActiveElem()
+
+    const hideEvent = active ?
+      EventHandler.trigger(active, EVENT_HIDE, { relatedTarget: innerElem }) :
+      null
 
-  show() {
-    if (this._element.parentNode &&
-        this._element.parentNode.nodeType === Node.ELEMENT_NODE &&
-        $(this._element).hasClass(CLASS_NAME_ACTIVE) ||
-        $(this._element).hasClass(CLASS_NAME_DISABLED)) {
+    const showEvent = EventHandler.trigger(innerElem, EVENT_SHOW, { relatedTarget: active })
+
+    if (showEvent.defaultPrevented || (hideEvent && hideEvent.defaultPrevented)) {
       return
     }
 
-    let target
-    let previous
-    const listElement = $(this._element).closest(SELECTOR_NAV_LIST_GROUP)[0]
-    const selector = Util.getSelectorFromElement(this._element)
+    this._deactivate(active, innerElem)
+    this._activate(innerElem, active)
+  }
 
-    if (listElement) {
-      const itemSelector = listElement.nodeName === 'UL' || listElement.nodeName === 'OL' ? SELECTOR_ACTIVE_UL : SELECTOR_ACTIVE
-      previous = $.makeArray($(listElement).find(itemSelector))
-      previous = previous[previous.length - 1]
+  // Private
+  _activate(element, relatedElem) {
+    if (!element) {
+      return
     }
 
-    const hideEvent = $.Event(EVENT_HIDE, {
-      relatedTarget: this._element
-    })
+    element.classList.add(CLASS_NAME_ACTIVE)
 
-    const showEvent = $.Event(EVENT_SHOW, {
-      relatedTarget: previous
-    })
+    this._activate(SelectorEngine.getElementFromSelector(element)) // Search and activate/show the proper section
 
-    if (previous) {
-      $(previous).trigger(hideEvent)
+    const complete = () => {
+      if (element.getAttribute('role') !== 'tab') {
+        element.classList.add(CLASS_NAME_SHOW)
+        return
+      }
+
+      element.removeAttribute('tabindex')
+      element.setAttribute('aria-selected', true)
+      this._toggleDropDown(element, true)
+      EventHandler.trigger(element, EVENT_SHOWN, {
+        relatedTarget: relatedElem
+      })
     }
 
-    $(this._element).trigger(showEvent)
+    this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
+  }
 
-    if (showEvent.isDefaultPrevented() ||
-        hideEvent.isDefaultPrevented()) {
+  _deactivate(element, relatedElem) {
+    if (!element) {
       return
     }
 
-    if (selector) {
-      target = document.querySelector(selector)
-    }
+    element.classList.remove(CLASS_NAME_ACTIVE)
+    element.blur()
 
-    this._activate(
-      this._element,
-      listElement
-    )
+    this._deactivate(SelectorEngine.getElementFromSelector(element)) // Search and deactivate the shown section too
 
     const complete = () => {
-      const hiddenEvent = $.Event(EVENT_HIDDEN, {
-        relatedTarget: this._element
-      })
+      if (element.getAttribute('role') !== 'tab') {
+        element.classList.remove(CLASS_NAME_SHOW)
+        return
+      }
 
-      const shownEvent = $.Event(EVENT_SHOWN, {
-        relatedTarget: previous
-      })
+      element.setAttribute('aria-selected', false)
+      element.setAttribute('tabindex', '-1')
+      this._toggleDropDown(element, false)
+      EventHandler.trigger(element, EVENT_HIDDEN, { relatedTarget: relatedElem })
+    }
+
+    this._queueCallback(complete, element, element.classList.contains(CLASS_NAME_FADE))
+  }
 
-      $(previous).trigger(hiddenEvent)
-      $(this._element).trigger(shownEvent)
+  _keydown(event) {
+    if (!([ARROW_LEFT_KEY, ARROW_RIGHT_KEY, ARROW_UP_KEY, ARROW_DOWN_KEY, HOME_KEY, END_KEY].includes(event.key))) {
+      return
     }
 
-    if (target) {
-      this._activate(target, target.parentNode, complete)
+    event.stopPropagation()// stopPropagation/preventDefault both added to support up/down keys without scrolling the page
+    event.preventDefault()
+
+    const children = this._getChildren().filter(element => !isDisabled(element))
+    let nextActiveElement
+
+    if ([HOME_KEY, END_KEY].includes(event.key)) {
+      nextActiveElement = children[event.key === HOME_KEY ? 0 : children.length - 1]
     } else {
-      complete()
+      const isNext = [ARROW_RIGHT_KEY, ARROW_DOWN_KEY].includes(event.key)
+      nextActiveElement = getNextActiveElement(children, event.target, isNext, true)
     }
-  }
 
-  dispose() {
-    $.removeData(this._element, DATA_KEY)
-    this._element = null
+    if (nextActiveElement) {
+      nextActiveElement.focus({ preventScroll: true })
+      Tab.getOrCreateInstance(nextActiveElement).show()
+    }
   }
 
-  // Private
+  _getChildren() { // collection of inner elements
+    return SelectorEngine.find(SELECTOR_INNER_ELEM, this._parent)
+  }
 
-  _activate(element, container, callback) {
-    const activeElements = container && (container.nodeName === 'UL' || container.nodeName === 'OL') ?
-      $(container).find(SELECTOR_ACTIVE_UL) :
-      $(container).children(SELECTOR_ACTIVE)
-
-    const active = activeElements[0]
-    const isTransitioning = callback && (active && $(active).hasClass(CLASS_NAME_FADE))
-    const complete = () => this._transitionComplete(
-      element,
-      active,
-      callback
-    )
-
-    if (active && isTransitioning) {
-      const transitionDuration = Util.getTransitionDurationFromElement(active)
-
-      $(active)
-        .removeClass(CLASS_NAME_SHOW)
-        .one(Util.TRANSITION_END, complete)
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      complete()
-    }
+  _getActiveElem() {
+    return this._getChildren().find(child => this._elemIsActive(child)) || null
   }
 
-  _transitionComplete(element, active, callback) {
-    if (active) {
-      $(active).removeClass(CLASS_NAME_ACTIVE)
+  _setInitialAttributes(parent, children) {
+    this._setAttributeIfNotExists(parent, 'role', 'tablist')
 
-      const dropdownChild = $(active.parentNode).find(
-        SELECTOR_DROPDOWN_ACTIVE_CHILD
-      )[0]
+    for (const child of children) {
+      this._setInitialAttributesOnChild(child)
+    }
+  }
 
-      if (dropdownChild) {
-        $(dropdownChild).removeClass(CLASS_NAME_ACTIVE)
-      }
+  _setInitialAttributesOnChild(child) {
+    child = this._getInnerElement(child)
+    const isActive = this._elemIsActive(child)
+    const outerElem = this._getOuterElement(child)
+    child.setAttribute('aria-selected', isActive)
 
-      if (active.getAttribute('role') === 'tab') {
-        active.setAttribute('aria-selected', false)
-      }
+    if (outerElem !== child) {
+      this._setAttributeIfNotExists(outerElem, 'role', 'presentation')
     }
 
-    $(element).addClass(CLASS_NAME_ACTIVE)
-    if (element.getAttribute('role') === 'tab') {
-      element.setAttribute('aria-selected', true)
+    if (!isActive) {
+      child.setAttribute('tabindex', '-1')
     }
 
-    Util.reflow(element)
+    this._setAttributeIfNotExists(child, 'role', 'tab')
 
-    if (element.classList.contains(CLASS_NAME_FADE)) {
-      element.classList.add(CLASS_NAME_SHOW)
+    // set attributes to the related panel too
+    this._setInitialAttributesOnTargetPanel(child)
+  }
+
+  _setInitialAttributesOnTargetPanel(child) {
+    const target = SelectorEngine.getElementFromSelector(child)
+
+    if (!target) {
+      return
     }
 
-    if (element.parentNode && $(element.parentNode).hasClass(CLASS_NAME_DROPDOWN_MENU)) {
-      const dropdownElement = $(element).closest(SELECTOR_DROPDOWN)[0]
+    this._setAttributeIfNotExists(target, 'role', 'tabpanel')
 
-      if (dropdownElement) {
-        const dropdownToggleList = [].slice.call(dropdownElement.querySelectorAll(SELECTOR_DROPDOWN_TOGGLE))
+    if (child.id) {
+      this._setAttributeIfNotExists(target, 'aria-labelledby', `${child.id}`)
+    }
+  }
 
-        $(dropdownToggleList).addClass(CLASS_NAME_ACTIVE)
-      }
+  _toggleDropDown(element, open) {
+    const outerElem = this._getOuterElement(element)
+    if (!outerElem.classList.contains(CLASS_DROPDOWN)) {
+      return
+    }
 
-      element.setAttribute('aria-expanded', true)
+    const toggle = (selector, className) => {
+      const element = SelectorEngine.findOne(selector, outerElem)
+      if (element) {
+        element.classList.toggle(className, open)
+      }
     }
 
-    if (callback) {
-      callback()
+    toggle(SELECTOR_DROPDOWN_TOGGLE, CLASS_NAME_ACTIVE)
+    toggle(SELECTOR_DROPDOWN_MENU, CLASS_NAME_SHOW)
+    outerElem.setAttribute('aria-expanded', open)
+  }
+
+  _setAttributeIfNotExists(element, attribute, value) {
+    if (!element.hasAttribute(attribute)) {
+      element.setAttribute(attribute, value)
     }
   }
 
-  // Static
+  _elemIsActive(elem) {
+    return elem.classList.contains(CLASS_NAME_ACTIVE)
+  }
+
+  // Try to get the inner element (usually the .nav-link)
+  _getInnerElement(elem) {
+    return elem.matches(SELECTOR_INNER_ELEM) ? elem : SelectorEngine.findOne(SELECTOR_INNER_ELEM, elem)
+  }
+
+  // Try to get the outer element (usually the .nav-item)
+  _getOuterElement(elem) {
+    return elem.closest(SELECTOR_OUTER) || elem
+  }
 
-  static _jQueryInterface(config) {
+  // Static
+  static jQueryInterface(config) {
     return this.each(function () {
-      const $this = $(this)
-      let data = $this.data(DATA_KEY)
+      const data = Tab.getOrCreateInstance(this)
 
-      if (!data) {
-        data = new Tab(this)
-        $this.data(DATA_KEY, data)
+      if (typeof config !== 'string') {
+        return
       }
 
-      if (typeof config === 'string') {
-        if (typeof data[config] === 'undefined') {
-          throw new TypeError(`No method named "${config}"`)
-        }
-
-        data[config]()
+      if (data[config] === undefined || config.startsWith('_') || config === 'constructor') {
+        throw new TypeError(`No method named "${config}"`)
       }
+
+      data[config]()
     })
   }
 }
 
 /**
- * ------------------------------------------------------------------------
- * Data Api implementation
- * ------------------------------------------------------------------------
+ * Data API implementation
  */
 
-$(document)
-  .on(EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+EventHandler.on(document, EVENT_CLICK_DATA_API, SELECTOR_DATA_TOGGLE, function (event) {
+  if (['A', 'AREA'].includes(this.tagName)) {
     event.preventDefault()
-    Tab._jQueryInterface.call($(this), 'show')
-  })
+  }
+
+  if (isDisabled(this)) {
+    return
+  }
+
+  Tab.getOrCreateInstance(this).show()
+})
 
 /**
- * ------------------------------------------------------------------------
+ * Initialize on focus
+ */
+EventHandler.on(window, EVENT_LOAD_DATA_API, () => {
+  for (const element of SelectorEngine.find(SELECTOR_DATA_TOGGLE_ACTIVE)) {
+    Tab.getOrCreateInstance(element)
+  }
+})
+/**
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Tab._jQueryInterface
-$.fn[NAME].Constructor = Tab
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Tab._jQueryInterface
-}
+defineJQueryPlugin(Tab)
 
 export default Tab

+ 95 - 100
coderedcms/static/coderedcms/vendor/bootstrap/js/src/toast.js

@@ -1,33 +1,34 @@
 /**
  * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): toast.js
+ * Bootstrap toast.js
  * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
  * --------------------------------------------------------------------------
  */
 
-import $ from 'jquery'
-import Util from './util'
+import BaseComponent from './base-component.js'
+import EventHandler from './dom/event-handler.js'
+import { enableDismissTrigger } from './util/component-functions.js'
+import { defineJQueryPlugin, reflow } from './util/index.js'
 
 /**
- * ------------------------------------------------------------------------
  * Constants
- * ------------------------------------------------------------------------
  */
 
 const NAME = 'toast'
-const VERSION = '4.6.0'
 const DATA_KEY = 'bs.toast'
 const EVENT_KEY = `.${DATA_KEY}`
-const JQUERY_NO_CONFLICT = $.fn[NAME]
 
-const EVENT_CLICK_DISMISS = `click.dismiss${EVENT_KEY}`
+const EVENT_MOUSEOVER = `mouseover${EVENT_KEY}`
+const EVENT_MOUSEOUT = `mouseout${EVENT_KEY}`
+const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
+const EVENT_FOCUSOUT = `focusout${EVENT_KEY}`
 const EVENT_HIDE = `hide${EVENT_KEY}`
 const EVENT_HIDDEN = `hidden${EVENT_KEY}`
 const EVENT_SHOW = `show${EVENT_KEY}`
 const EVENT_SHOWN = `shown${EVENT_KEY}`
 
 const CLASS_NAME_FADE = 'fade'
-const CLASS_NAME_HIDE = 'hide'
+const CLASS_NAME_HIDE = 'hide' // @deprecated - kept here only for backwards compatibility
 const CLASS_NAME_SHOW = 'show'
 const CLASS_NAME_SHOWING = 'showing'
 
@@ -40,46 +41,41 @@ const DefaultType = {
 const Default = {
   animation: true,
   autohide: true,
-  delay: 500
+  delay: 5000
 }
 
-const SELECTOR_DATA_DISMISS = '[data-dismiss="toast"]'
-
 /**
- * ------------------------------------------------------------------------
- * Class Definition
- * ------------------------------------------------------------------------
+ * Class definition
  */
 
-class Toast {
+class Toast extends BaseComponent {
   constructor(element, config) {
-    this._element = element
-    this._config = this._getConfig(config)
+    super(element, config)
+
     this._timeout = null
+    this._hasMouseInteraction = false
+    this._hasKeyboardInteraction = false
     this._setListeners()
   }
 
   // Getters
-
-  static get VERSION() {
-    return VERSION
+  static get Default() {
+    return Default
   }
 
   static get DefaultType() {
     return DefaultType
   }
 
-  static get Default() {
-    return Default
+  static get NAME() {
+    return NAME
   }
 
   // Public
-
   show() {
-    const showEvent = $.Event(EVENT_SHOW)
+    const showEvent = EventHandler.trigger(this._element, EVENT_SHOW)
 
-    $(this._element).trigger(showEvent)
-    if (showEvent.isDefaultPrevented()) {
+    if (showEvent.defaultPrevented) {
       return
     }
 
@@ -91,98 +87,106 @@ class Toast {
 
     const complete = () => {
       this._element.classList.remove(CLASS_NAME_SHOWING)
-      this._element.classList.add(CLASS_NAME_SHOW)
-
-      $(this._element).trigger(EVENT_SHOWN)
+      EventHandler.trigger(this._element, EVENT_SHOWN)
 
-      if (this._config.autohide) {
-        this._timeout = setTimeout(() => {
-          this.hide()
-        }, this._config.delay)
-      }
+      this._maybeScheduleHide()
     }
 
-    this._element.classList.remove(CLASS_NAME_HIDE)
-    Util.reflow(this._element)
-    this._element.classList.add(CLASS_NAME_SHOWING)
-    if (this._config.animation) {
-      const transitionDuration = Util.getTransitionDurationFromElement(this._element)
+    this._element.classList.remove(CLASS_NAME_HIDE) // @deprecated
+    reflow(this._element)
+    this._element.classList.add(CLASS_NAME_SHOW, CLASS_NAME_SHOWING)
 
-      $(this._element)
-        .one(Util.TRANSITION_END, complete)
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      complete()
-    }
+    this._queueCallback(complete, this._element, this._config.animation)
   }
 
   hide() {
-    if (!this._element.classList.contains(CLASS_NAME_SHOW)) {
+    if (!this.isShown()) {
       return
     }
 
-    const hideEvent = $.Event(EVENT_HIDE)
+    const hideEvent = EventHandler.trigger(this._element, EVENT_HIDE)
 
-    $(this._element).trigger(hideEvent)
-    if (hideEvent.isDefaultPrevented()) {
+    if (hideEvent.defaultPrevented) {
       return
     }
 
-    this._close()
+    const complete = () => {
+      this._element.classList.add(CLASS_NAME_HIDE) // @deprecated
+      this._element.classList.remove(CLASS_NAME_SHOWING, CLASS_NAME_SHOW)
+      EventHandler.trigger(this._element, EVENT_HIDDEN)
+    }
+
+    this._element.classList.add(CLASS_NAME_SHOWING)
+    this._queueCallback(complete, this._element, this._config.animation)
   }
 
   dispose() {
     this._clearTimeout()
 
-    if (this._element.classList.contains(CLASS_NAME_SHOW)) {
+    if (this.isShown()) {
       this._element.classList.remove(CLASS_NAME_SHOW)
     }
 
-    $(this._element).off(EVENT_CLICK_DISMISS)
+    super.dispose()
+  }
 
-    $.removeData(this._element, DATA_KEY)
-    this._element = null
-    this._config = null
+  isShown() {
+    return this._element.classList.contains(CLASS_NAME_SHOW)
   }
 
   // Private
 
-  _getConfig(config) {
-    config = {
-      ...Default,
-      ...$(this._element).data(),
-      ...(typeof config === 'object' && config ? config : {})
+  _maybeScheduleHide() {
+    if (!this._config.autohide) {
+      return
     }
 
-    Util.typeCheckConfig(
-      NAME,
-      config,
-      this.constructor.DefaultType
-    )
+    if (this._hasMouseInteraction || this._hasKeyboardInteraction) {
+      return
+    }
 
-    return config
+    this._timeout = setTimeout(() => {
+      this.hide()
+    }, this._config.delay)
   }
 
-  _setListeners() {
-    $(this._element).on(EVENT_CLICK_DISMISS, SELECTOR_DATA_DISMISS, () => this.hide())
-  }
+  _onInteraction(event, isInteracting) {
+    switch (event.type) {
+      case 'mouseover':
+      case 'mouseout': {
+        this._hasMouseInteraction = isInteracting
+        break
+      }
 
-  _close() {
-    const complete = () => {
-      this._element.classList.add(CLASS_NAME_HIDE)
-      $(this._element).trigger(EVENT_HIDDEN)
+      case 'focusin':
+      case 'focusout': {
+        this._hasKeyboardInteraction = isInteracting
+        break
+      }
+
+      default: {
+        break
+      }
     }
 
-    this._element.classList.remove(CLASS_NAME_SHOW)
-    if (this._config.animation) {
-      const transitionDuration = Util.getTransitionDurationFromElement(this._element)
+    if (isInteracting) {
+      this._clearTimeout()
+      return
+    }
 
-      $(this._element)
-        .one(Util.TRANSITION_END, complete)
-        .emulateTransitionEnd(transitionDuration)
-    } else {
-      complete()
+    const nextElement = event.relatedTarget
+    if (this._element === nextElement || this._element.contains(nextElement)) {
+      return
     }
+
+    this._maybeScheduleHide()
+  }
+
+  _setListeners() {
+    EventHandler.on(this._element, EVENT_MOUSEOVER, event => this._onInteraction(event, true))
+    EventHandler.on(this._element, EVENT_MOUSEOUT, event => this._onInteraction(event, false))
+    EventHandler.on(this._element, EVENT_FOCUSIN, event => this._onInteraction(event, true))
+    EventHandler.on(this._element, EVENT_FOCUSOUT, event => this._onInteraction(event, false))
   }
 
   _clearTimeout() {
@@ -191,17 +195,9 @@ class Toast {
   }
 
   // Static
-
-  static _jQueryInterface(config) {
+  static jQueryInterface(config) {
     return this.each(function () {
-      const $element = $(this)
-      let data = $element.data(DATA_KEY)
-      const _config = typeof config === 'object' && config
-
-      if (!data) {
-        data = new Toast(this, _config)
-        $element.data(DATA_KEY, data)
-      }
+      const data = Toast.getOrCreateInstance(this, config)
 
       if (typeof config === 'string') {
         if (typeof data[config] === 'undefined') {
@@ -215,16 +211,15 @@ class Toast {
 }
 
 /**
- * ------------------------------------------------------------------------
+ * Data API implementation
+ */
+
+enableDismissTrigger(Toast)
+
+/**
  * jQuery
- * ------------------------------------------------------------------------
  */
 
-$.fn[NAME] = Toast._jQueryInterface
-$.fn[NAME].Constructor = Toast
-$.fn[NAME].noConflict = () => {
-  $.fn[NAME] = JQUERY_NO_CONFLICT
-  return Toast._jQueryInterface
-}
+defineJQueryPlugin(Toast)
 
 export default Toast

+ 0 - 127
coderedcms/static/coderedcms/vendor/bootstrap/js/src/tools/sanitizer.js

@@ -1,127 +0,0 @@
-/**
- * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): tools/sanitizer.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-const uriAttrs = [
-  'background',
-  'cite',
-  'href',
-  'itemtype',
-  'longdesc',
-  'poster',
-  'src',
-  'xlink:href'
-]
-
-const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
-
-export const DefaultWhitelist = {
-  // Global attributes allowed on any supplied element below.
-  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
-  a: ['target', 'href', 'title', 'rel'],
-  area: [],
-  b: [],
-  br: [],
-  col: [],
-  code: [],
-  div: [],
-  em: [],
-  hr: [],
-  h1: [],
-  h2: [],
-  h3: [],
-  h4: [],
-  h5: [],
-  h6: [],
-  i: [],
-  img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
-  li: [],
-  ol: [],
-  p: [],
-  pre: [],
-  s: [],
-  small: [],
-  span: [],
-  sub: [],
-  sup: [],
-  strong: [],
-  u: [],
-  ul: []
-}
-
-/**
- * A pattern that recognizes a commonly useful subset of URLs that are safe.
- *
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
- */
-const SAFE_URL_PATTERN = /^(?:(?:https?|mailto|ftp|tel|file):|[^#&/:?]*(?:[#/?]|$))/gi
-
-/**
- * A pattern that matches safe data URLs. Only matches image, video and audio types.
- *
- * Shoutout to Angular 7 https://github.com/angular/angular/blob/7.2.4/packages/core/src/sanitization/url_sanitizer.ts
- */
-const DATA_URL_PATTERN = /^data:(?:image\/(?:bmp|gif|jpeg|jpg|png|tiff|webp)|video\/(?:mpeg|mp4|ogg|webm)|audio\/(?:mp3|oga|ogg|opus));base64,[\d+/a-z]+=*$/i
-
-function allowedAttribute(attr, allowedAttributeList) {
-  const attrName = attr.nodeName.toLowerCase()
-
-  if (allowedAttributeList.indexOf(attrName) !== -1) {
-    if (uriAttrs.indexOf(attrName) !== -1) {
-      return Boolean(attr.nodeValue.match(SAFE_URL_PATTERN) || attr.nodeValue.match(DATA_URL_PATTERN))
-    }
-
-    return true
-  }
-
-  const regExp = allowedAttributeList.filter(attrRegex => attrRegex instanceof RegExp)
-
-  // Check if a regular expression validates the attribute.
-  for (let i = 0, len = regExp.length; i < len; i++) {
-    if (attrName.match(regExp[i])) {
-      return true
-    }
-  }
-
-  return false
-}
-
-export function sanitizeHtml(unsafeHtml, whiteList, sanitizeFn) {
-  if (unsafeHtml.length === 0) {
-    return unsafeHtml
-  }
-
-  if (sanitizeFn && typeof sanitizeFn === 'function') {
-    return sanitizeFn(unsafeHtml)
-  }
-
-  const domParser = new window.DOMParser()
-  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
-  const whitelistKeys = Object.keys(whiteList)
-  const elements = [].slice.call(createdDocument.body.querySelectorAll('*'))
-
-  for (let i = 0, len = elements.length; i < len; i++) {
-    const el = elements[i]
-    const elName = el.nodeName.toLowerCase()
-
-    if (whitelistKeys.indexOf(el.nodeName.toLowerCase()) === -1) {
-      el.parentNode.removeChild(el)
-
-      continue
-    }
-
-    const attributeList = [].slice.call(el.attributes)
-    const whitelistedAttributes = [].concat(whiteList['*'] || [], whiteList[elName] || [])
-
-    attributeList.forEach(attr => {
-      if (!allowedAttribute(attr, whitelistedAttributes)) {
-        el.removeAttribute(attr.nodeName)
-      }
-    })
-  }
-
-  return createdDocument.body.innerHTML
-}

文件差異過大導致無法顯示
+ 340 - 447
coderedcms/static/coderedcms/vendor/bootstrap/js/src/tooltip.js


+ 0 - 198
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util.js

@@ -1,198 +0,0 @@
-/**
- * --------------------------------------------------------------------------
- * Bootstrap (v4.6.0): util.js
- * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
- * --------------------------------------------------------------------------
- */
-
-import $ from 'jquery'
-
-/**
- * ------------------------------------------------------------------------
- * Private TransitionEnd Helpers
- * ------------------------------------------------------------------------
- */
-
-const TRANSITION_END = 'transitionend'
-const MAX_UID = 1000000
-const MILLISECONDS_MULTIPLIER = 1000
-
-// Shoutout AngusCroll (https://goo.gl/pxwQGp)
-function toType(obj) {
-  if (obj === null || typeof obj === 'undefined') {
-    return `${obj}`
-  }
-
-  return {}.toString.call(obj).match(/\s([a-z]+)/i)[1].toLowerCase()
-}
-
-function getSpecialTransitionEndEvent() {
-  return {
-    bindType: TRANSITION_END,
-    delegateType: TRANSITION_END,
-    handle(event) {
-      if ($(event.target).is(this)) {
-        return event.handleObj.handler.apply(this, arguments) // eslint-disable-line prefer-rest-params
-      }
-
-      return undefined
-    }
-  }
-}
-
-function transitionEndEmulator(duration) {
-  let called = false
-
-  $(this).one(Util.TRANSITION_END, () => {
-    called = true
-  })
-
-  setTimeout(() => {
-    if (!called) {
-      Util.triggerTransitionEnd(this)
-    }
-  }, duration)
-
-  return this
-}
-
-function setTransitionEndSupport() {
-  $.fn.emulateTransitionEnd = transitionEndEmulator
-  $.event.special[Util.TRANSITION_END] = getSpecialTransitionEndEvent()
-}
-
-/**
- * --------------------------------------------------------------------------
- * Public Util Api
- * --------------------------------------------------------------------------
- */
-
-const Util = {
-  TRANSITION_END: 'bsTransitionEnd',
-
-  getUID(prefix) {
-    do {
-      prefix += ~~(Math.random() * MAX_UID) // "~~" acts like a faster Math.floor() here
-    } while (document.getElementById(prefix))
-
-    return prefix
-  },
-
-  getSelectorFromElement(element) {
-    let selector = element.getAttribute('data-target')
-
-    if (!selector || selector === '#') {
-      const hrefAttr = element.getAttribute('href')
-      selector = hrefAttr && hrefAttr !== '#' ? hrefAttr.trim() : ''
-    }
-
-    try {
-      return document.querySelector(selector) ? selector : null
-    } catch (_) {
-      return null
-    }
-  },
-
-  getTransitionDurationFromElement(element) {
-    if (!element) {
-      return 0
-    }
-
-    // Get transition-duration of the element
-    let transitionDuration = $(element).css('transition-duration')
-    let transitionDelay = $(element).css('transition-delay')
-
-    const floatTransitionDuration = parseFloat(transitionDuration)
-    const floatTransitionDelay = parseFloat(transitionDelay)
-
-    // Return 0 if element or transition duration is not found
-    if (!floatTransitionDuration && !floatTransitionDelay) {
-      return 0
-    }
-
-    // If multiple durations are defined, take the first
-    transitionDuration = transitionDuration.split(',')[0]
-    transitionDelay = transitionDelay.split(',')[0]
-
-    return (parseFloat(transitionDuration) + parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
-  },
-
-  reflow(element) {
-    return element.offsetHeight
-  },
-
-  triggerTransitionEnd(element) {
-    $(element).trigger(TRANSITION_END)
-  },
-
-  supportsTransitionEnd() {
-    return Boolean(TRANSITION_END)
-  },
-
-  isElement(obj) {
-    return (obj[0] || obj).nodeType
-  },
-
-  typeCheckConfig(componentName, config, configTypes) {
-    for (const property in configTypes) {
-      if (Object.prototype.hasOwnProperty.call(configTypes, property)) {
-        const expectedTypes = configTypes[property]
-        const value = config[property]
-        const valueType = value && Util.isElement(value) ?
-          'element' : toType(value)
-
-        if (!new RegExp(expectedTypes).test(valueType)) {
-          throw new Error(
-            `${componentName.toUpperCase()}: ` +
-            `Option "${property}" provided type "${valueType}" ` +
-            `but expected type "${expectedTypes}".`)
-        }
-      }
-    }
-  },
-
-  findShadowRoot(element) {
-    if (!document.documentElement.attachShadow) {
-      return null
-    }
-
-    // Can find the shadow root otherwise it'll return the document
-    if (typeof element.getRootNode === 'function') {
-      const root = element.getRootNode()
-      return root instanceof ShadowRoot ? root : null
-    }
-
-    if (element instanceof ShadowRoot) {
-      return element
-    }
-
-    // when we don't find a shadow root
-    if (!element.parentNode) {
-      return null
-    }
-
-    return Util.findShadowRoot(element.parentNode)
-  },
-
-  jQueryDetection() {
-    if (typeof $ === 'undefined') {
-      throw new TypeError('Bootstrap\'s JavaScript requires jQuery. jQuery must be included before Bootstrap\'s JavaScript.')
-    }
-
-    const version = $.fn.jquery.split(' ')[0].split('.')
-    const minMajor = 1
-    const ltMajor = 2
-    const minMinor = 9
-    const minPatch = 1
-    const maxMajor = 4
-
-    if (version[0] < ltMajor && version[1] < minMinor || version[0] === minMajor && version[1] === minMinor && version[2] < minPatch || version[0] >= maxMajor) {
-      throw new Error('Bootstrap\'s JavaScript requires at least jQuery v1.9.1 but less than v4.0.0')
-    }
-  }
-}
-
-Util.jQueryDetection()
-setTransitionEndSupport()
-
-export default Util

+ 149 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/backdrop.js

@@ -0,0 +1,149 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/backdrop.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import EventHandler from '../dom/event-handler.js'
+import Config from './config.js'
+import { execute, executeAfterTransition, getElement, reflow } from './index.js'
+
+/**
+ * Constants
+ */
+
+const NAME = 'backdrop'
+const CLASS_NAME_FADE = 'fade'
+const CLASS_NAME_SHOW = 'show'
+const EVENT_MOUSEDOWN = `mousedown.bs.${NAME}`
+
+const Default = {
+  className: 'modal-backdrop',
+  clickCallback: null,
+  isAnimated: false,
+  isVisible: true, // if false, we use the backdrop helper without adding any element to the dom
+  rootElement: 'body' // give the choice to place backdrop under different elements
+}
+
+const DefaultType = {
+  className: 'string',
+  clickCallback: '(function|null)',
+  isAnimated: 'boolean',
+  isVisible: 'boolean',
+  rootElement: '(element|string)'
+}
+
+/**
+ * Class definition
+ */
+
+class Backdrop extends Config {
+  constructor(config) {
+    super()
+    this._config = this._getConfig(config)
+    this._isAppended = false
+    this._element = null
+  }
+
+  // Getters
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
+  }
+
+  // Public
+  show(callback) {
+    if (!this._config.isVisible) {
+      execute(callback)
+      return
+    }
+
+    this._append()
+
+    const element = this._getElement()
+    if (this._config.isAnimated) {
+      reflow(element)
+    }
+
+    element.classList.add(CLASS_NAME_SHOW)
+
+    this._emulateAnimation(() => {
+      execute(callback)
+    })
+  }
+
+  hide(callback) {
+    if (!this._config.isVisible) {
+      execute(callback)
+      return
+    }
+
+    this._getElement().classList.remove(CLASS_NAME_SHOW)
+
+    this._emulateAnimation(() => {
+      this.dispose()
+      execute(callback)
+    })
+  }
+
+  dispose() {
+    if (!this._isAppended) {
+      return
+    }
+
+    EventHandler.off(this._element, EVENT_MOUSEDOWN)
+
+    this._element.remove()
+    this._isAppended = false
+  }
+
+  // Private
+  _getElement() {
+    if (!this._element) {
+      const backdrop = document.createElement('div')
+      backdrop.className = this._config.className
+      if (this._config.isAnimated) {
+        backdrop.classList.add(CLASS_NAME_FADE)
+      }
+
+      this._element = backdrop
+    }
+
+    return this._element
+  }
+
+  _configAfterMerge(config) {
+    // use getElement() with the default "body" to get a fresh Element on each instantiation
+    config.rootElement = getElement(config.rootElement)
+    return config
+  }
+
+  _append() {
+    if (this._isAppended) {
+      return
+    }
+
+    const element = this._getElement()
+    this._config.rootElement.append(element)
+
+    EventHandler.on(element, EVENT_MOUSEDOWN, () => {
+      execute(this._config.clickCallback)
+    })
+
+    this._isAppended = true
+  }
+
+  _emulateAnimation(callback) {
+    executeAfterTransition(callback, this._getElement(), this._config.isAnimated)
+  }
+}
+
+export default Backdrop

+ 35 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/component-functions.js

@@ -0,0 +1,35 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/component-functions.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import EventHandler from '../dom/event-handler.js'
+import SelectorEngine from '../dom/selector-engine.js'
+import { isDisabled } from './index.js'
+
+const enableDismissTrigger = (component, method = 'hide') => {
+  const clickEvent = `click.dismiss${component.EVENT_KEY}`
+  const name = component.NAME
+
+  EventHandler.on(document, clickEvent, `[data-bs-dismiss="${name}"]`, function (event) {
+    if (['A', 'AREA'].includes(this.tagName)) {
+      event.preventDefault()
+    }
+
+    if (isDisabled(this)) {
+      return
+    }
+
+    const target = SelectorEngine.getElementFromSelector(this) || this.closest(`.${name}`)
+    const instance = component.getOrCreateInstance(target)
+
+    // Method argument is left, for Alert and only, as it doesn't implement the 'hide' method
+    instance[method]()
+  })
+}
+
+export {
+  enableDismissTrigger
+}

+ 65 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/config.js

@@ -0,0 +1,65 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/config.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import Manipulator from '../dom/manipulator.js'
+import { isElement, toType } from './index.js'
+
+/**
+ * Class definition
+ */
+
+class Config {
+  // Getters
+  static get Default() {
+    return {}
+  }
+
+  static get DefaultType() {
+    return {}
+  }
+
+  static get NAME() {
+    throw new Error('You have to implement the static method "NAME", for each component!')
+  }
+
+  _getConfig(config) {
+    config = this._mergeConfigObj(config)
+    config = this._configAfterMerge(config)
+    this._typeCheckConfig(config)
+    return config
+  }
+
+  _configAfterMerge(config) {
+    return config
+  }
+
+  _mergeConfigObj(config, element) {
+    const jsonConfig = isElement(element) ? Manipulator.getDataAttribute(element, 'config') : {} // try to parse
+
+    return {
+      ...this.constructor.Default,
+      ...(typeof jsonConfig === 'object' ? jsonConfig : {}),
+      ...(isElement(element) ? Manipulator.getDataAttributes(element) : {}),
+      ...(typeof config === 'object' ? config : {})
+    }
+  }
+
+  _typeCheckConfig(config, configTypes = this.constructor.DefaultType) {
+    for (const [property, expectedTypes] of Object.entries(configTypes)) {
+      const value = config[property]
+      const valueType = isElement(value) ? 'element' : toType(value)
+
+      if (!new RegExp(expectedTypes).test(valueType)) {
+        throw new TypeError(
+          `${this.constructor.NAME.toUpperCase()}: Option "${property}" provided type "${valueType}" but expected type "${expectedTypes}".`
+        )
+      }
+    }
+  }
+}
+
+export default Config

+ 115 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/focustrap.js

@@ -0,0 +1,115 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/focustrap.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import EventHandler from '../dom/event-handler.js'
+import SelectorEngine from '../dom/selector-engine.js'
+import Config from './config.js'
+
+/**
+ * Constants
+ */
+
+const NAME = 'focustrap'
+const DATA_KEY = 'bs.focustrap'
+const EVENT_KEY = `.${DATA_KEY}`
+const EVENT_FOCUSIN = `focusin${EVENT_KEY}`
+const EVENT_KEYDOWN_TAB = `keydown.tab${EVENT_KEY}`
+
+const TAB_KEY = 'Tab'
+const TAB_NAV_FORWARD = 'forward'
+const TAB_NAV_BACKWARD = 'backward'
+
+const Default = {
+  autofocus: true,
+  trapElement: null // The element to trap focus inside of
+}
+
+const DefaultType = {
+  autofocus: 'boolean',
+  trapElement: 'element'
+}
+
+/**
+ * Class definition
+ */
+
+class FocusTrap extends Config {
+  constructor(config) {
+    super()
+    this._config = this._getConfig(config)
+    this._isActive = false
+    this._lastTabNavDirection = null
+  }
+
+  // Getters
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
+  }
+
+  // Public
+  activate() {
+    if (this._isActive) {
+      return
+    }
+
+    if (this._config.autofocus) {
+      this._config.trapElement.focus()
+    }
+
+    EventHandler.off(document, EVENT_KEY) // guard against infinite focus loop
+    EventHandler.on(document, EVENT_FOCUSIN, event => this._handleFocusin(event))
+    EventHandler.on(document, EVENT_KEYDOWN_TAB, event => this._handleKeydown(event))
+
+    this._isActive = true
+  }
+
+  deactivate() {
+    if (!this._isActive) {
+      return
+    }
+
+    this._isActive = false
+    EventHandler.off(document, EVENT_KEY)
+  }
+
+  // Private
+  _handleFocusin(event) {
+    const { trapElement } = this._config
+
+    if (event.target === document || event.target === trapElement || trapElement.contains(event.target)) {
+      return
+    }
+
+    const elements = SelectorEngine.focusableChildren(trapElement)
+
+    if (elements.length === 0) {
+      trapElement.focus()
+    } else if (this._lastTabNavDirection === TAB_NAV_BACKWARD) {
+      elements[elements.length - 1].focus()
+    } else {
+      elements[0].focus()
+    }
+  }
+
+  _handleKeydown(event) {
+    if (event.key !== TAB_KEY) {
+      return
+    }
+
+    this._lastTabNavDirection = event.shiftKey ? TAB_NAV_BACKWARD : TAB_NAV_FORWARD
+  }
+}
+
+export default FocusTrap

+ 306 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/index.js

@@ -0,0 +1,306 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/index.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+const MAX_UID = 1_000_000
+const MILLISECONDS_MULTIPLIER = 1000
+const TRANSITION_END = 'transitionend'
+
+/**
+ * Properly escape IDs selectors to handle weird IDs
+ * @param {string} selector
+ * @returns {string}
+ */
+const parseSelector = selector => {
+  if (selector && window.CSS && window.CSS.escape) {
+    // document.querySelector needs escaping to handle IDs (html5+) containing for instance /
+    selector = selector.replace(/#([^\s"#']+)/g, (match, id) => `#${CSS.escape(id)}`)
+  }
+
+  return selector
+}
+
+// Shout-out Angus Croll (https://goo.gl/pxwQGp)
+const toType = object => {
+  if (object === null || object === undefined) {
+    return `${object}`
+  }
+
+  return Object.prototype.toString.call(object).match(/\s([a-z]+)/i)[1].toLowerCase()
+}
+
+/**
+ * Public Util API
+ */
+
+const getUID = prefix => {
+  do {
+    prefix += Math.floor(Math.random() * MAX_UID)
+  } while (document.getElementById(prefix))
+
+  return prefix
+}
+
+const getTransitionDurationFromElement = element => {
+  if (!element) {
+    return 0
+  }
+
+  // Get transition-duration of the element
+  let { transitionDuration, transitionDelay } = window.getComputedStyle(element)
+
+  const floatTransitionDuration = Number.parseFloat(transitionDuration)
+  const floatTransitionDelay = Number.parseFloat(transitionDelay)
+
+  // Return 0 if element or transition duration is not found
+  if (!floatTransitionDuration && !floatTransitionDelay) {
+    return 0
+  }
+
+  // If multiple durations are defined, take the first
+  transitionDuration = transitionDuration.split(',')[0]
+  transitionDelay = transitionDelay.split(',')[0]
+
+  return (Number.parseFloat(transitionDuration) + Number.parseFloat(transitionDelay)) * MILLISECONDS_MULTIPLIER
+}
+
+const triggerTransitionEnd = element => {
+  element.dispatchEvent(new Event(TRANSITION_END))
+}
+
+const isElement = object => {
+  if (!object || typeof object !== 'object') {
+    return false
+  }
+
+  if (typeof object.jquery !== 'undefined') {
+    object = object[0]
+  }
+
+  return typeof object.nodeType !== 'undefined'
+}
+
+const getElement = object => {
+  // it's a jQuery object or a node element
+  if (isElement(object)) {
+    return object.jquery ? object[0] : object
+  }
+
+  if (typeof object === 'string' && object.length > 0) {
+    return document.querySelector(parseSelector(object))
+  }
+
+  return null
+}
+
+const isVisible = element => {
+  if (!isElement(element) || element.getClientRects().length === 0) {
+    return false
+  }
+
+  const elementIsVisible = getComputedStyle(element).getPropertyValue('visibility') === 'visible'
+  // Handle `details` element as its content may falsie appear visible when it is closed
+  const closedDetails = element.closest('details:not([open])')
+
+  if (!closedDetails) {
+    return elementIsVisible
+  }
+
+  if (closedDetails !== element) {
+    const summary = element.closest('summary')
+    if (summary && summary.parentNode !== closedDetails) {
+      return false
+    }
+
+    if (summary === null) {
+      return false
+    }
+  }
+
+  return elementIsVisible
+}
+
+const isDisabled = element => {
+  if (!element || element.nodeType !== Node.ELEMENT_NODE) {
+    return true
+  }
+
+  if (element.classList.contains('disabled')) {
+    return true
+  }
+
+  if (typeof element.disabled !== 'undefined') {
+    return element.disabled
+  }
+
+  return element.hasAttribute('disabled') && element.getAttribute('disabled') !== 'false'
+}
+
+const findShadowRoot = element => {
+  if (!document.documentElement.attachShadow) {
+    return null
+  }
+
+  // Can find the shadow root otherwise it'll return the document
+  if (typeof element.getRootNode === 'function') {
+    const root = element.getRootNode()
+    return root instanceof ShadowRoot ? root : null
+  }
+
+  if (element instanceof ShadowRoot) {
+    return element
+  }
+
+  // when we don't find a shadow root
+  if (!element.parentNode) {
+    return null
+  }
+
+  return findShadowRoot(element.parentNode)
+}
+
+const noop = () => {}
+
+/**
+ * Trick to restart an element's animation
+ *
+ * @param {HTMLElement} element
+ * @return void
+ *
+ * @see https://www.charistheo.io/blog/2021/02/restart-a-css-animation-with-javascript/#restarting-a-css-animation
+ */
+const reflow = element => {
+  element.offsetHeight // eslint-disable-line no-unused-expressions
+}
+
+const getjQuery = () => {
+  if (window.jQuery && !document.body.hasAttribute('data-bs-no-jquery')) {
+    return window.jQuery
+  }
+
+  return null
+}
+
+const DOMContentLoadedCallbacks = []
+
+const onDOMContentLoaded = callback => {
+  if (document.readyState === 'loading') {
+    // add listener on the first call when the document is in loading state
+    if (!DOMContentLoadedCallbacks.length) {
+      document.addEventListener('DOMContentLoaded', () => {
+        for (const callback of DOMContentLoadedCallbacks) {
+          callback()
+        }
+      })
+    }
+
+    DOMContentLoadedCallbacks.push(callback)
+  } else {
+    callback()
+  }
+}
+
+const isRTL = () => document.documentElement.dir === 'rtl'
+
+const defineJQueryPlugin = plugin => {
+  onDOMContentLoaded(() => {
+    const $ = getjQuery()
+    /* istanbul ignore if */
+    if ($) {
+      const name = plugin.NAME
+      const JQUERY_NO_CONFLICT = $.fn[name]
+      $.fn[name] = plugin.jQueryInterface
+      $.fn[name].Constructor = plugin
+      $.fn[name].noConflict = () => {
+        $.fn[name] = JQUERY_NO_CONFLICT
+        return plugin.jQueryInterface
+      }
+    }
+  })
+}
+
+const execute = (possibleCallback, args = [], defaultValue = possibleCallback) => {
+  return typeof possibleCallback === 'function' ? possibleCallback(...args) : defaultValue
+}
+
+const executeAfterTransition = (callback, transitionElement, waitForTransition = true) => {
+  if (!waitForTransition) {
+    execute(callback)
+    return
+  }
+
+  const durationPadding = 5
+  const emulatedDuration = getTransitionDurationFromElement(transitionElement) + durationPadding
+
+  let called = false
+
+  const handler = ({ target }) => {
+    if (target !== transitionElement) {
+      return
+    }
+
+    called = true
+    transitionElement.removeEventListener(TRANSITION_END, handler)
+    execute(callback)
+  }
+
+  transitionElement.addEventListener(TRANSITION_END, handler)
+  setTimeout(() => {
+    if (!called) {
+      triggerTransitionEnd(transitionElement)
+    }
+  }, emulatedDuration)
+}
+
+/**
+ * Return the previous/next element of a list.
+ *
+ * @param {array} list    The list of elements
+ * @param activeElement   The active element
+ * @param shouldGetNext   Choose to get next or previous element
+ * @param isCycleAllowed
+ * @return {Element|elem} The proper element
+ */
+const getNextActiveElement = (list, activeElement, shouldGetNext, isCycleAllowed) => {
+  const listLength = list.length
+  let index = list.indexOf(activeElement)
+
+  // if the element does not exist in the list return an element
+  // depending on the direction and if cycle is allowed
+  if (index === -1) {
+    return !shouldGetNext && isCycleAllowed ? list[listLength - 1] : list[0]
+  }
+
+  index += shouldGetNext ? 1 : -1
+
+  if (isCycleAllowed) {
+    index = (index + listLength) % listLength
+  }
+
+  return list[Math.max(0, Math.min(index, listLength - 1))]
+}
+
+export {
+  defineJQueryPlugin,
+  execute,
+  executeAfterTransition,
+  findShadowRoot,
+  getElement,
+  getjQuery,
+  getNextActiveElement,
+  getTransitionDurationFromElement,
+  getUID,
+  isDisabled,
+  isElement,
+  isRTL,
+  isVisible,
+  noop,
+  onDOMContentLoaded,
+  parseSelector,
+  reflow,
+  triggerTransitionEnd,
+  toType
+}

+ 114 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/sanitizer.js

@@ -0,0 +1,114 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/sanitizer.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+// js-docs-start allow-list
+const ARIA_ATTRIBUTE_PATTERN = /^aria-[\w-]*$/i
+
+export const DefaultAllowlist = {
+  // Global attributes allowed on any supplied element below.
+  '*': ['class', 'dir', 'id', 'lang', 'role', ARIA_ATTRIBUTE_PATTERN],
+  a: ['target', 'href', 'title', 'rel'],
+  area: [],
+  b: [],
+  br: [],
+  col: [],
+  code: [],
+  div: [],
+  em: [],
+  hr: [],
+  h1: [],
+  h2: [],
+  h3: [],
+  h4: [],
+  h5: [],
+  h6: [],
+  i: [],
+  img: ['src', 'srcset', 'alt', 'title', 'width', 'height'],
+  li: [],
+  ol: [],
+  p: [],
+  pre: [],
+  s: [],
+  small: [],
+  span: [],
+  sub: [],
+  sup: [],
+  strong: [],
+  u: [],
+  ul: []
+}
+// js-docs-end allow-list
+
+const uriAttributes = new Set([
+  'background',
+  'cite',
+  'href',
+  'itemtype',
+  'longdesc',
+  'poster',
+  'src',
+  'xlink:href'
+])
+
+/**
+ * A pattern that recognizes URLs that are safe wrt. XSS in URL navigation
+ * contexts.
+ *
+ * Shout-out to Angular https://github.com/angular/angular/blob/15.2.8/packages/core/src/sanitization/url_sanitizer.ts#L38
+ */
+// eslint-disable-next-line unicorn/better-regex
+const SAFE_URL_PATTERN = /^(?!javascript:)(?:[a-z0-9+.-]+:|[^&:/?#]*(?:[/?#]|$))/i
+
+const allowedAttribute = (attribute, allowedAttributeList) => {
+  const attributeName = attribute.nodeName.toLowerCase()
+
+  if (allowedAttributeList.includes(attributeName)) {
+    if (uriAttributes.has(attributeName)) {
+      return Boolean(SAFE_URL_PATTERN.test(attribute.nodeValue))
+    }
+
+    return true
+  }
+
+  // Check if a regular expression validates the attribute.
+  return allowedAttributeList.filter(attributeRegex => attributeRegex instanceof RegExp)
+    .some(regex => regex.test(attributeName))
+}
+
+export function sanitizeHtml(unsafeHtml, allowList, sanitizeFunction) {
+  if (!unsafeHtml.length) {
+    return unsafeHtml
+  }
+
+  if (sanitizeFunction && typeof sanitizeFunction === 'function') {
+    return sanitizeFunction(unsafeHtml)
+  }
+
+  const domParser = new window.DOMParser()
+  const createdDocument = domParser.parseFromString(unsafeHtml, 'text/html')
+  const elements = [].concat(...createdDocument.body.querySelectorAll('*'))
+
+  for (const element of elements) {
+    const elementName = element.nodeName.toLowerCase()
+
+    if (!Object.keys(allowList).includes(elementName)) {
+      element.remove()
+      continue
+    }
+
+    const attributeList = [].concat(...element.attributes)
+    const allowedAttributes = [].concat(allowList['*'] || [], allowList[elementName] || [])
+
+    for (const attribute of attributeList) {
+      if (!allowedAttribute(attribute, allowedAttributes)) {
+        element.removeAttribute(attribute.nodeName)
+      }
+    }
+  }
+
+  return createdDocument.body.innerHTML
+}

+ 114 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/scrollbar.js

@@ -0,0 +1,114 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/scrollBar.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import Manipulator from '../dom/manipulator.js'
+import SelectorEngine from '../dom/selector-engine.js'
+import { isElement } from './index.js'
+
+/**
+ * Constants
+ */
+
+const SELECTOR_FIXED_CONTENT = '.fixed-top, .fixed-bottom, .is-fixed, .sticky-top'
+const SELECTOR_STICKY_CONTENT = '.sticky-top'
+const PROPERTY_PADDING = 'padding-right'
+const PROPERTY_MARGIN = 'margin-right'
+
+/**
+ * Class definition
+ */
+
+class ScrollBarHelper {
+  constructor() {
+    this._element = document.body
+  }
+
+  // Public
+  getWidth() {
+    // https://developer.mozilla.org/en-US/docs/Web/API/Window/innerWidth#usage_notes
+    const documentWidth = document.documentElement.clientWidth
+    return Math.abs(window.innerWidth - documentWidth)
+  }
+
+  hide() {
+    const width = this.getWidth()
+    this._disableOverFlow()
+    // give padding to element to balance the hidden scrollbar width
+    this._setElementAttributes(this._element, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
+    // trick: We adjust positive paddingRight and negative marginRight to sticky-top elements to keep showing fullwidth
+    this._setElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING, calculatedValue => calculatedValue + width)
+    this._setElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN, calculatedValue => calculatedValue - width)
+  }
+
+  reset() {
+    this._resetElementAttributes(this._element, 'overflow')
+    this._resetElementAttributes(this._element, PROPERTY_PADDING)
+    this._resetElementAttributes(SELECTOR_FIXED_CONTENT, PROPERTY_PADDING)
+    this._resetElementAttributes(SELECTOR_STICKY_CONTENT, PROPERTY_MARGIN)
+  }
+
+  isOverflowing() {
+    return this.getWidth() > 0
+  }
+
+  // Private
+  _disableOverFlow() {
+    this._saveInitialAttribute(this._element, 'overflow')
+    this._element.style.overflow = 'hidden'
+  }
+
+  _setElementAttributes(selector, styleProperty, callback) {
+    const scrollbarWidth = this.getWidth()
+    const manipulationCallBack = element => {
+      if (element !== this._element && window.innerWidth > element.clientWidth + scrollbarWidth) {
+        return
+      }
+
+      this._saveInitialAttribute(element, styleProperty)
+      const calculatedValue = window.getComputedStyle(element).getPropertyValue(styleProperty)
+      element.style.setProperty(styleProperty, `${callback(Number.parseFloat(calculatedValue))}px`)
+    }
+
+    this._applyManipulationCallback(selector, manipulationCallBack)
+  }
+
+  _saveInitialAttribute(element, styleProperty) {
+    const actualValue = element.style.getPropertyValue(styleProperty)
+    if (actualValue) {
+      Manipulator.setDataAttribute(element, styleProperty, actualValue)
+    }
+  }
+
+  _resetElementAttributes(selector, styleProperty) {
+    const manipulationCallBack = element => {
+      const value = Manipulator.getDataAttribute(element, styleProperty)
+      // We only want to remove the property if the value is `null`; the value can also be zero
+      if (value === null) {
+        element.style.removeProperty(styleProperty)
+        return
+      }
+
+      Manipulator.removeDataAttribute(element, styleProperty)
+      element.style.setProperty(styleProperty, value)
+    }
+
+    this._applyManipulationCallback(selector, manipulationCallBack)
+  }
+
+  _applyManipulationCallback(selector, callBack) {
+    if (isElement(selector)) {
+      callBack(selector)
+      return
+    }
+
+    for (const sel of SelectorEngine.find(selector, this._element)) {
+      callBack(sel)
+    }
+  }
+}
+
+export default ScrollBarHelper

+ 146 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/swipe.js

@@ -0,0 +1,146 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/swipe.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import EventHandler from '../dom/event-handler.js'
+import Config from './config.js'
+import { execute } from './index.js'
+
+/**
+ * Constants
+ */
+
+const NAME = 'swipe'
+const EVENT_KEY = '.bs.swipe'
+const EVENT_TOUCHSTART = `touchstart${EVENT_KEY}`
+const EVENT_TOUCHMOVE = `touchmove${EVENT_KEY}`
+const EVENT_TOUCHEND = `touchend${EVENT_KEY}`
+const EVENT_POINTERDOWN = `pointerdown${EVENT_KEY}`
+const EVENT_POINTERUP = `pointerup${EVENT_KEY}`
+const POINTER_TYPE_TOUCH = 'touch'
+const POINTER_TYPE_PEN = 'pen'
+const CLASS_NAME_POINTER_EVENT = 'pointer-event'
+const SWIPE_THRESHOLD = 40
+
+const Default = {
+  endCallback: null,
+  leftCallback: null,
+  rightCallback: null
+}
+
+const DefaultType = {
+  endCallback: '(function|null)',
+  leftCallback: '(function|null)',
+  rightCallback: '(function|null)'
+}
+
+/**
+ * Class definition
+ */
+
+class Swipe extends Config {
+  constructor(element, config) {
+    super()
+    this._element = element
+
+    if (!element || !Swipe.isSupported()) {
+      return
+    }
+
+    this._config = this._getConfig(config)
+    this._deltaX = 0
+    this._supportPointerEvents = Boolean(window.PointerEvent)
+    this._initEvents()
+  }
+
+  // Getters
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
+  }
+
+  // Public
+  dispose() {
+    EventHandler.off(this._element, EVENT_KEY)
+  }
+
+  // Private
+  _start(event) {
+    if (!this._supportPointerEvents) {
+      this._deltaX = event.touches[0].clientX
+
+      return
+    }
+
+    if (this._eventIsPointerPenTouch(event)) {
+      this._deltaX = event.clientX
+    }
+  }
+
+  _end(event) {
+    if (this._eventIsPointerPenTouch(event)) {
+      this._deltaX = event.clientX - this._deltaX
+    }
+
+    this._handleSwipe()
+    execute(this._config.endCallback)
+  }
+
+  _move(event) {
+    this._deltaX = event.touches && event.touches.length > 1 ?
+      0 :
+      event.touches[0].clientX - this._deltaX
+  }
+
+  _handleSwipe() {
+    const absDeltaX = Math.abs(this._deltaX)
+
+    if (absDeltaX <= SWIPE_THRESHOLD) {
+      return
+    }
+
+    const direction = absDeltaX / this._deltaX
+
+    this._deltaX = 0
+
+    if (!direction) {
+      return
+    }
+
+    execute(direction > 0 ? this._config.rightCallback : this._config.leftCallback)
+  }
+
+  _initEvents() {
+    if (this._supportPointerEvents) {
+      EventHandler.on(this._element, EVENT_POINTERDOWN, event => this._start(event))
+      EventHandler.on(this._element, EVENT_POINTERUP, event => this._end(event))
+
+      this._element.classList.add(CLASS_NAME_POINTER_EVENT)
+    } else {
+      EventHandler.on(this._element, EVENT_TOUCHSTART, event => this._start(event))
+      EventHandler.on(this._element, EVENT_TOUCHMOVE, event => this._move(event))
+      EventHandler.on(this._element, EVENT_TOUCHEND, event => this._end(event))
+    }
+  }
+
+  _eventIsPointerPenTouch(event) {
+    return this._supportPointerEvents && (event.pointerType === POINTER_TYPE_PEN || event.pointerType === POINTER_TYPE_TOUCH)
+  }
+
+  // Static
+  static isSupported() {
+    return 'ontouchstart' in document.documentElement || navigator.maxTouchPoints > 0
+  }
+}
+
+export default Swipe

+ 160 - 0
coderedcms/static/coderedcms/vendor/bootstrap/js/src/util/template-factory.js

@@ -0,0 +1,160 @@
+/**
+ * --------------------------------------------------------------------------
+ * Bootstrap util/template-factory.js
+ * Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
+ * --------------------------------------------------------------------------
+ */
+
+import SelectorEngine from '../dom/selector-engine.js'
+import Config from './config.js'
+import { DefaultAllowlist, sanitizeHtml } from './sanitizer.js'
+import { execute, getElement, isElement } from './index.js'
+
+/**
+ * Constants
+ */
+
+const NAME = 'TemplateFactory'
+
+const Default = {
+  allowList: DefaultAllowlist,
+  content: {}, // { selector : text ,  selector2 : text2 , }
+  extraClass: '',
+  html: false,
+  sanitize: true,
+  sanitizeFn: null,
+  template: '<div></div>'
+}
+
+const DefaultType = {
+  allowList: 'object',
+  content: 'object',
+  extraClass: '(string|function)',
+  html: 'boolean',
+  sanitize: 'boolean',
+  sanitizeFn: '(null|function)',
+  template: 'string'
+}
+
+const DefaultContentType = {
+  entry: '(string|element|function|null)',
+  selector: '(string|element)'
+}
+
+/**
+ * Class definition
+ */
+
+class TemplateFactory extends Config {
+  constructor(config) {
+    super()
+    this._config = this._getConfig(config)
+  }
+
+  // Getters
+  static get Default() {
+    return Default
+  }
+
+  static get DefaultType() {
+    return DefaultType
+  }
+
+  static get NAME() {
+    return NAME
+  }
+
+  // Public
+  getContent() {
+    return Object.values(this._config.content)
+      .map(config => this._resolvePossibleFunction(config))
+      .filter(Boolean)
+  }
+
+  hasContent() {
+    return this.getContent().length > 0
+  }
+
+  changeContent(content) {
+    this._checkContent(content)
+    this._config.content = { ...this._config.content, ...content }
+    return this
+  }
+
+  toHtml() {
+    const templateWrapper = document.createElement('div')
+    templateWrapper.innerHTML = this._maybeSanitize(this._config.template)
+
+    for (const [selector, text] of Object.entries(this._config.content)) {
+      this._setContent(templateWrapper, text, selector)
+    }
+
+    const template = templateWrapper.children[0]
+    const extraClass = this._resolvePossibleFunction(this._config.extraClass)
+
+    if (extraClass) {
+      template.classList.add(...extraClass.split(' '))
+    }
+
+    return template
+  }
+
+  // Private
+  _typeCheckConfig(config) {
+    super._typeCheckConfig(config)
+    this._checkContent(config.content)
+  }
+
+  _checkContent(arg) {
+    for (const [selector, content] of Object.entries(arg)) {
+      super._typeCheckConfig({ selector, entry: content }, DefaultContentType)
+    }
+  }
+
+  _setContent(template, content, selector) {
+    const templateElement = SelectorEngine.findOne(selector, template)
+
+    if (!templateElement) {
+      return
+    }
+
+    content = this._resolvePossibleFunction(content)
+
+    if (!content) {
+      templateElement.remove()
+      return
+    }
+
+    if (isElement(content)) {
+      this._putElementInTemplate(getElement(content), templateElement)
+      return
+    }
+
+    if (this._config.html) {
+      templateElement.innerHTML = this._maybeSanitize(content)
+      return
+    }
+
+    templateElement.textContent = content
+  }
+
+  _maybeSanitize(arg) {
+    return this._config.sanitize ? sanitizeHtml(arg, this._config.allowList, this._config.sanitizeFn) : arg
+  }
+
+  _resolvePossibleFunction(arg) {
+    return execute(arg, [this])
+  }
+
+  _putElementInTemplate(element, templateElement) {
+    if (this._config.html) {
+      templateElement.innerHTML = ''
+      templateElement.append(element)
+      return
+    }
+
+    templateElement.textContent = element.textContent
+  }
+}
+
+export default TemplateFactory

+ 16 - 4
coderedcms/static/coderedcms/vendor/bootstrap/scss/_accordion.scss

@@ -4,7 +4,7 @@
 
 .accordion {
   // scss-docs-start accordion-css-vars
-  --#{$prefix}accordion-color: #{color-contrast($accordion-bg)};
+  --#{$prefix}accordion-color: #{$accordion-color};
   --#{$prefix}accordion-bg: #{$accordion-bg};
   --#{$prefix}accordion-transition: #{$accordion-transition};
   --#{$prefix}accordion-border-color: #{$accordion-border-color};
@@ -13,7 +13,7 @@
   --#{$prefix}accordion-inner-border-radius: #{$accordion-inner-border-radius};
   --#{$prefix}accordion-btn-padding-x: #{$accordion-button-padding-x};
   --#{$prefix}accordion-btn-padding-y: #{$accordion-button-padding-y};
-  --#{$prefix}accordion-btn-color: #{$accordion-color};
+  --#{$prefix}accordion-btn-color: #{$accordion-button-color};
   --#{$prefix}accordion-btn-bg: #{$accordion-button-bg};
   --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon)};
   --#{$prefix}accordion-btn-icon-width: #{$accordion-icon-width};
@@ -47,7 +47,7 @@
   &:not(.collapsed) {
     color: var(--#{$prefix}accordion-active-color);
     background-color: var(--#{$prefix}accordion-active-bg);
-    box-shadow: inset 0 calc(var(--#{$prefix}accordion-border-width) * -1) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list
+    box-shadow: inset 0 calc(-1 * var(--#{$prefix}accordion-border-width)) 0 var(--#{$prefix}accordion-border-color); // stylelint-disable-line function-disallowed-list
 
     &::after {
       background-image: var(--#{$prefix}accordion-btn-active-icon);
@@ -140,7 +140,19 @@
     &:last-child { border-bottom: 0; }
 
     .accordion-button {
-      @include border-radius(0);
+      &,
+      &.collapsed {
+        @include border-radius(0);
+      }
+    }
+  }
+}
+
+@if $enable-dark-mode {
+  @include color-mode(dark) {
+    .accordion-button::after {
+      --#{$prefix}accordion-btn-icon: #{escape-svg($accordion-button-icon-dark)};
+      --#{$prefix}accordion-btn-active-icon: #{escape-svg($accordion-button-active-icon-dark)};
     }
   }
 }

+ 8 - 11
coderedcms/static/coderedcms/vendor/bootstrap/scss/_alert.scss

@@ -12,6 +12,7 @@
   --#{$prefix}alert-border-color: transparent;
   --#{$prefix}alert-border: #{$alert-border-width} solid var(--#{$prefix}alert-border-color);
   --#{$prefix}alert-border-radius: #{$alert-border-radius};
+  --#{$prefix}alert-link-color: inherit;
   // scss-docs-end alert-css-vars
 
   position: relative;
@@ -32,6 +33,7 @@
 // Provide class for links that match alerts
 .alert-link {
   font-weight: $alert-link-font-weight;
+  color: var(--#{$prefix}alert-link-color);
 }
 
 
@@ -54,18 +56,13 @@
 
 
 // scss-docs-start alert-modifiers
-// Generate contextual modifier classes for colorizing the alert.
-
-@each $state, $value in $theme-colors {
-  $alert-background: shift-color($value, $alert-bg-scale);
-  $alert-border: shift-color($value, $alert-border-scale);
-  $alert-color: shift-color($value, $alert-color-scale);
-
-  @if (contrast-ratio($alert-background, $alert-color) < $min-contrast-ratio) {
-    $alert-color: mix($value, color-contrast($alert-background), abs($alert-color-scale));
-  }
+// Generate contextual modifier classes for colorizing the alert
+@each $state in map-keys($theme-colors) {
   .alert-#{$state} {
-    @include alert-variant($alert-background, $alert-border, $alert-color);
+    --#{$prefix}alert-color: var(--#{$prefix}#{$state}-text-emphasis);
+    --#{$prefix}alert-bg: var(--#{$prefix}#{$state}-bg-subtle);
+    --#{$prefix}alert-border-color: var(--#{$prefix}#{$state}-border-subtle);
+    --#{$prefix}alert-link-color: var(--#{$prefix}#{$state}-text-emphasis);
   }
 }
 // scss-docs-end alert-modifiers

+ 3 - 3
coderedcms/static/coderedcms/vendor/bootstrap/scss/_button-group.scss

@@ -37,9 +37,9 @@
   @include border-radius($btn-border-radius);
 
   // Prevent double borders when buttons are next to each other
-  > .btn:not(:first-child),
+  > :not(.btn-check:first-child) + .btn,
   > .btn-group:not(:first-child) {
-    margin-left: -$btn-border-width;
+    margin-left: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
   }
 
   // Reset rounded corners
@@ -126,7 +126,7 @@
 
   > .btn:not(:first-child),
   > .btn-group:not(:first-child) {
-    margin-top: -$btn-border-width;
+    margin-top: calc(#{$btn-border-width} * -1); // stylelint-disable-line function-disallowed-list
   }
 
   // Reset rounded corners

+ 31 - 10
coderedcms/static/coderedcms/vendor/bootstrap/scss/_buttons.scss

@@ -10,11 +10,12 @@
   @include rfs($btn-font-size, --#{$prefix}btn-font-size);
   --#{$prefix}btn-font-weight: #{$btn-font-weight};
   --#{$prefix}btn-line-height: #{$btn-line-height};
-  --#{$prefix}btn-color: #{$body-color};
+  --#{$prefix}btn-color: #{$btn-color};
   --#{$prefix}btn-bg: transparent;
   --#{$prefix}btn-border-width: #{$btn-border-width};
   --#{$prefix}btn-border-color: transparent;
   --#{$prefix}btn-border-radius: #{$btn-border-radius};
+  --#{$prefix}btn-hover-border-color: transparent;
   --#{$prefix}btn-box-shadow: #{$btn-box-shadow};
   --#{$prefix}btn-disabled-opacity: #{$btn-disabled-opacity};
   --#{$prefix}btn-focus-box-shadow: 0 0 0 #{$btn-focus-width} rgba(var(--#{$prefix}btn-focus-shadow-rgb), .5);
@@ -46,8 +47,14 @@
     border-color: var(--#{$prefix}btn-hover-border-color);
   }
 
-  .btn-check:focus + &,
-  &:focus {
+  .btn-check + &:hover {
+    // override for the checkbox/radio buttons
+    color: var(--#{$prefix}btn-color);
+    background-color: var(--#{$prefix}btn-bg);
+    border-color: var(--#{$prefix}btn-border-color);
+  }
+
+  &:focus-visible {
     color: var(--#{$prefix}btn-hover-color);
     @include gradient-bg(var(--#{$prefix}btn-hover-bg));
     border-color: var(--#{$prefix}btn-hover-border-color);
@@ -60,9 +67,20 @@
     }
   }
 
+  .btn-check:focus-visible + & {
+    border-color: var(--#{$prefix}btn-hover-border-color);
+    outline: 0;
+    // Avoid using mixin so we can pass custom focus shadow properly
+    @if $enable-shadows {
+      box-shadow: var(--#{$prefix}btn-box-shadow), var(--#{$prefix}btn-focus-box-shadow);
+    } @else {
+      box-shadow: var(--#{$prefix}btn-focus-box-shadow);
+    }
+  }
+
   .btn-check:checked + &,
-  .btn-check:active + &,
-  &:active,
+  :not(.btn-check) + &:active,
+  &:first-child:active,
   &.active,
   &.show {
     color: var(--#{$prefix}btn-active-color);
@@ -72,7 +90,7 @@
     border-color: var(--#{$prefix}btn-active-border-color);
     @include box-shadow(var(--#{$prefix}btn-active-shadow));
 
-    &:focus {
+    &:focus-visible {
       // Avoid using mixin so we can pass custom focus shadow properly
       @if $enable-shadows {
         box-shadow: var(--#{$prefix}btn-active-shadow), var(--#{$prefix}btn-focus-box-shadow);
@@ -151,17 +169,20 @@
   --#{$prefix}btn-active-border-color: transparent;
   --#{$prefix}btn-disabled-color: #{$btn-link-disabled-color};
   --#{$prefix}btn-disabled-border-color: transparent;
-  --#{$prefix}btn-box-shadow: none;
-  --#{$prefix}btn-focus-shadow-rgb: #{to-rgb(mix(color-contrast($primary), $primary, 15%))};
+  --#{$prefix}btn-box-shadow: 0 0 0 #000; // Can't use `none` as keyword negates all values when used with multiple shadows
+  --#{$prefix}btn-focus-shadow-rgb: #{$btn-link-focus-shadow-rgb};
 
   text-decoration: $link-decoration;
+  @if $enable-gradients {
+    background-image: none;
+  }
 
   &:hover,
-  &:focus {
+  &:focus-visible {
     text-decoration: $link-hover-decoration;
   }
 
-  &:focus {
+  &:focus-visible {
     color: var(--#{$prefix}btn-color);
   }
 

+ 5 - 0
coderedcms/static/coderedcms/vendor/bootstrap/scss/_card.scss

@@ -7,6 +7,8 @@
   --#{$prefix}card-spacer-y: #{$card-spacer-y};
   --#{$prefix}card-spacer-x: #{$card-spacer-x};
   --#{$prefix}card-title-spacer-y: #{$card-title-spacer-y};
+  --#{$prefix}card-title-color: #{$card-title-color};
+  --#{$prefix}card-subtitle-color: #{$card-subtitle-color};
   --#{$prefix}card-border-width: #{$card-border-width};
   --#{$prefix}card-border-color: #{$card-border-color};
   --#{$prefix}card-border-radius: #{$card-border-radius};
@@ -28,6 +30,7 @@
   flex-direction: column;
   min-width: 0; // See https://github.com/twbs/bootstrap/pull/22740#issuecomment-305868106
   height: var(--#{$prefix}card-height);
+  color: var(--#{$prefix}body-color);
   word-wrap: break-word;
   background-color: var(--#{$prefix}card-bg);
   background-clip: border-box;
@@ -73,11 +76,13 @@
 
 .card-title {
   margin-bottom: var(--#{$prefix}card-title-spacer-y);
+  color: var(--#{$prefix}card-title-color);
 }
 
 .card-subtitle {
   margin-top: calc(-.5 * var(--#{$prefix}card-title-spacer-y)); // stylelint-disable-line function-disallowed-list
   margin-bottom: 0;
+  color: var(--#{$prefix}card-subtitle-color);
 }
 
 .card-text:last-child {

+ 20 - 5
coderedcms/static/coderedcms/vendor/bootstrap/scss/_carousel.scss

@@ -42,7 +42,6 @@
   display: block;
 }
 
-/* rtl:begin:ignore */
 .carousel-item-next:not(.carousel-item-start),
 .active.carousel-item-end {
   transform: translateX(100%);
@@ -53,8 +52,6 @@
   transform: translateX(-100%);
 }
 
-/* rtl:end:ignore */
-
 
 //
 // Alternate transitions
@@ -168,7 +165,6 @@
   margin-right: $carousel-control-width;
   margin-bottom: 1rem;
   margin-left: $carousel-control-width;
-  list-style: none;
 
   [data-bs-target] {
     box-sizing: content-box;
@@ -213,7 +209,7 @@
 
 // Dark mode carousel
 
-.carousel-dark {
+@mixin carousel-dark() {
   .carousel-control-prev-icon,
   .carousel-control-next-icon {
     filter: $carousel-dark-control-icon-filter;
@@ -227,3 +223,22 @@
     color: $carousel-dark-caption-color;
   }
 }
+
+.carousel-dark {
+  @include carousel-dark();
+}
+
+@if $enable-dark-mode {
+  @include color-mode(dark) {
+    @if $color-mode-type == "media-query" {
+      .carousel {
+        @include carousel-dark();
+      }
+    } @else {
+      .carousel,
+      &.carousel {
+        @include carousel-dark();
+      }
+    }
+  }
+}

+ 32 - 9
coderedcms/static/coderedcms/vendor/bootstrap/scss/_close.scss

@@ -4,37 +4,60 @@
 // See https://developer.mozilla.org/en-US/docs/Web/Events/click#Safari_Mobile
 
 .btn-close {
+  // scss-docs-start close-css-vars
+  --#{$prefix}btn-close-color: #{$btn-close-color};
+  --#{$prefix}btn-close-bg: #{ escape-svg($btn-close-bg) };
+  --#{$prefix}btn-close-opacity: #{$btn-close-opacity};
+  --#{$prefix}btn-close-hover-opacity: #{$btn-close-hover-opacity};
+  --#{$prefix}btn-close-focus-shadow: #{$btn-close-focus-shadow};
+  --#{$prefix}btn-close-focus-opacity: #{$btn-close-focus-opacity};
+  --#{$prefix}btn-close-disabled-opacity: #{$btn-close-disabled-opacity};
+  --#{$prefix}btn-close-white-filter: #{$btn-close-white-filter};
+  // scss-docs-end close-css-vars
+
   box-sizing: content-box;
   width: $btn-close-width;
   height: $btn-close-height;
   padding: $btn-close-padding-y $btn-close-padding-x;
-  color: $btn-close-color;
-  background: transparent escape-svg($btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
+  color: var(--#{$prefix}btn-close-color);
+  background: transparent var(--#{$prefix}btn-close-bg) center / $btn-close-width auto no-repeat; // include transparent for button elements
   border: 0; // for button elements
   @include border-radius();
-  opacity: $btn-close-opacity;
+  opacity: var(--#{$prefix}btn-close-opacity);
 
   // Override <a>'s hover style
   &:hover {
-    color: $btn-close-color;
+    color: var(--#{$prefix}btn-close-color);
     text-decoration: none;
-    opacity: $btn-close-hover-opacity;
+    opacity: var(--#{$prefix}btn-close-hover-opacity);
   }
 
   &:focus {
     outline: 0;
-    box-shadow: $btn-close-focus-shadow;
-    opacity: $btn-close-focus-opacity;
+    box-shadow: var(--#{$prefix}btn-close-focus-shadow);
+    opacity: var(--#{$prefix}btn-close-focus-opacity);
   }
 
   &:disabled,
   &.disabled {
     pointer-events: none;
     user-select: none;
-    opacity: $btn-close-disabled-opacity;
+    opacity: var(--#{$prefix}btn-close-disabled-opacity);
   }
 }
 
+@mixin btn-close-white() {
+  filter: var(--#{$prefix}btn-close-white-filter);
+}
+
 .btn-close-white {
-  filter: $btn-close-white-filter;
+  @include btn-close-white();
+}
+
+@if $enable-dark-mode {
+  @include color-mode(dark) {
+    .btn-close {
+      @include btn-close-white();
+    }
+  }
 }

+ 3 - 1
coderedcms/static/coderedcms/vendor/bootstrap/scss/_dropdown.scss

@@ -18,6 +18,7 @@
 // The dropdown menu
 .dropdown-menu {
   // scss-docs-start dropdown-css-vars
+  --#{$prefix}dropdown-zindex: #{$zindex-dropdown};
   --#{$prefix}dropdown-min-width: #{$dropdown-min-width};
   --#{$prefix}dropdown-padding-x: #{$dropdown-padding-x};
   --#{$prefix}dropdown-padding-y: #{$dropdown-padding-y};
@@ -46,7 +47,7 @@
   // scss-docs-end dropdown-css-vars
 
   position: absolute;
-  z-index: $zindex-dropdown;
+  z-index: var(--#{$prefix}dropdown-zindex);
   display: none; // none by default, but block on "open" of the menu
   min-width: var(--#{$prefix}dropdown-min-width);
   padding: var(--#{$prefix}dropdown-padding-y) var(--#{$prefix}dropdown-padding-x);
@@ -183,6 +184,7 @@
   white-space: nowrap; // prevent links from randomly breaking onto new lines
   background-color: transparent; // For `<button>`s
   border: 0; // For `<button>`s
+  @include border-radius(var(--#{$prefix}dropdown-item-border-radius, 0));
 
   &:hover,
   &:focus {

+ 3 - 3
coderedcms/static/coderedcms/vendor/bootstrap/scss/_functions.scss

@@ -109,7 +109,7 @@
 // Replace `$search` with `$replace` in `$string`
 // Used on our SVG icon backgrounds for custom forms.
 //
-// @author Hugo Giraudel
+// @author Kitty Giraudel
 // @param {String} $string - Initial string
 // @param {String} $search - Substring to replace
 // @param {String} $replace ('') - New value
@@ -188,7 +188,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
   );
 
   @each $name, $value in $rgb {
-    $value: if(divide($value, 255) < .03928, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
+    $value: if(divide($value, 255) < .04045, divide(divide($value, 255), 12.92), nth($_luminance-list, $value + 1));
     $rgb: map-merge($rgb, ($name: $value));
   }
 
@@ -198,7 +198,7 @@ $_luminance-list: .0008 .001 .0011 .0013 .0015 .0017 .002 .0022 .0025 .0027 .003
 // Return opaque color
 // opaque(#fff, rgba(0, 0, 0, .5)) => #808080
 @function opaque($background, $foreground) {
-  @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100);
+  @return mix(rgba($foreground, 1), $background, opacity($foreground) * 100%);
 }
 
 // scss-docs-start color-functions

+ 6 - 0
coderedcms/static/coderedcms/vendor/bootstrap/scss/_grid.scss

@@ -2,6 +2,12 @@
 //
 // Rows contain your columns.
 
+:root {
+  @each $name, $value in $grid-breakpoints {
+    --#{$prefix}breakpoint-#{$name}: #{$value};
+  }
+}
+
 @if $enable-grid-classes {
   .row {
     @include make-row();

+ 2 - 0
coderedcms/static/coderedcms/vendor/bootstrap/scss/_helpers.scss

@@ -1,6 +1,8 @@
 @import "helpers/clearfix";
 @import "helpers/color-bg";
 @import "helpers/colored-links";
+@import "helpers/focus-ring";
+@import "helpers/icon-link";
 @import "helpers/ratio";
 @import "helpers/position";
 @import "helpers/stacks";

+ 18 - 12
coderedcms/static/coderedcms/vendor/bootstrap/scss/_list-group.scss

@@ -104,11 +104,12 @@
     border-color: var(--#{$prefix}list-group-active-border-color);
   }
 
-  & + & {
+  // stylelint-disable-next-line scss/selector-no-redundant-nesting-selector
+  & + .list-group-item {
     border-top-width: 0;
 
     &.active {
-      margin-top: calc(var(--#{$prefix}list-group-border-width) * -1); // stylelint-disable-line function-disallowed-list
+      margin-top: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
       border-top-width: var(--#{$prefix}list-group-border-width);
     }
   }
@@ -126,12 +127,12 @@
       flex-direction: row;
 
       > .list-group-item {
-        &:first-child {
+        &:first-child:not(:last-child) {
           @include border-bottom-start-radius(var(--#{$prefix}list-group-border-radius));
           @include border-top-end-radius(0);
         }
 
-        &:last-child {
+        &:last-child:not(:first-child) {
           @include border-top-end-radius(var(--#{$prefix}list-group-border-radius));
           @include border-bottom-start-radius(0);
         }
@@ -145,7 +146,7 @@
           border-left-width: 0;
 
           &.active {
-            margin-left: calc(var(--#{$prefix}list-group-border-width) * -1); // stylelint-disable-line function-disallowed-list
+            margin-left: calc(-1 * var(--#{$prefix}list-group-border-width)); // stylelint-disable-line function-disallowed-list
             border-left-width: var(--#{$prefix}list-group-border-width);
           }
         }
@@ -179,13 +180,18 @@
 // Add modifier classes to change text and background color on individual items.
 // Organizationally, this must come after the `:hover` states.
 
-@each $state, $value in $theme-colors {
-  $list-group-variant-bg: shift-color($value, $list-group-item-bg-scale);
-  $list-group-variant-color: shift-color($value, $list-group-item-color-scale);
-  @if (contrast-ratio($list-group-variant-bg, $list-group-variant-color) < $min-contrast-ratio) {
-    $list-group-variant-color: mix($value, color-contrast($list-group-variant-bg), abs($list-group-item-color-scale));
+@each $state in map-keys($theme-colors) {
+  .list-group-item-#{$state} {
+    --#{$prefix}list-group-color: var(--#{$prefix}#{$state}-text-emphasis);
+    --#{$prefix}list-group-bg: var(--#{$prefix}#{$state}-bg-subtle);
+    --#{$prefix}list-group-border-color: var(--#{$prefix}#{$state}-border-subtle);
+    --#{$prefix}list-group-action-hover-color: var(--#{$prefix}emphasis-color);
+    --#{$prefix}list-group-action-hover-bg: var(--#{$prefix}#{$state}-border-subtle);
+    --#{$prefix}list-group-action-active-color: var(--#{$prefix}emphasis-color);
+    --#{$prefix}list-group-action-active-bg: var(--#{$prefix}#{$state}-border-subtle);
+    --#{$prefix}list-group-active-color: var(--#{$prefix}#{$state}-bg-subtle);
+    --#{$prefix}list-group-active-bg: var(--#{$prefix}#{$state}-text-emphasis);
+    --#{$prefix}list-group-active-border-color: var(--#{$prefix}#{$state}-text-emphasis);
   }
-
-  @include list-group-item-variant($state, $list-group-variant-bg, $list-group-variant-color);
 }
 // scss-docs-end list-group-modifiers

+ 120 - 0
coderedcms/static/coderedcms/vendor/bootstrap/scss/_maps.scss

@@ -6,6 +6,90 @@
 $theme-colors-rgb: map-loop($theme-colors, to-rgb, "$value") !default;
 // scss-docs-end theme-colors-rgb
 
+// scss-docs-start theme-text-map
+$theme-colors-text: (
+  "primary": $primary-text-emphasis,
+  "secondary": $secondary-text-emphasis,
+  "success": $success-text-emphasis,
+  "info": $info-text-emphasis,
+  "warning": $warning-text-emphasis,
+  "danger": $danger-text-emphasis,
+  "light": $light-text-emphasis,
+  "dark": $dark-text-emphasis,
+) !default;
+// scss-docs-end theme-text-map
+
+// scss-docs-start theme-bg-subtle-map
+$theme-colors-bg-subtle: (
+  "primary": $primary-bg-subtle,
+  "secondary": $secondary-bg-subtle,
+  "success": $success-bg-subtle,
+  "info": $info-bg-subtle,
+  "warning": $warning-bg-subtle,
+  "danger": $danger-bg-subtle,
+  "light": $light-bg-subtle,
+  "dark": $dark-bg-subtle,
+) !default;
+// scss-docs-end theme-bg-subtle-map
+
+// scss-docs-start theme-border-subtle-map
+$theme-colors-border-subtle: (
+  "primary": $primary-border-subtle,
+  "secondary": $secondary-border-subtle,
+  "success": $success-border-subtle,
+  "info": $info-border-subtle,
+  "warning": $warning-border-subtle,
+  "danger": $danger-border-subtle,
+  "light": $light-border-subtle,
+  "dark": $dark-border-subtle,
+) !default;
+// scss-docs-end theme-border-subtle-map
+
+$theme-colors-text-dark: null !default;
+$theme-colors-bg-subtle-dark: null !default;
+$theme-colors-border-subtle-dark: null !default;
+
+@if $enable-dark-mode {
+  // scss-docs-start theme-text-dark-map
+  $theme-colors-text-dark: (
+    "primary": $primary-text-emphasis-dark,
+    "secondary": $secondary-text-emphasis-dark,
+    "success": $success-text-emphasis-dark,
+    "info": $info-text-emphasis-dark,
+    "warning": $warning-text-emphasis-dark,
+    "danger": $danger-text-emphasis-dark,
+    "light": $light-text-emphasis-dark,
+    "dark": $dark-text-emphasis-dark,
+  ) !default;
+  // scss-docs-end theme-text-dark-map
+
+  // scss-docs-start theme-bg-subtle-dark-map
+  $theme-colors-bg-subtle-dark: (
+    "primary": $primary-bg-subtle-dark,
+    "secondary": $secondary-bg-subtle-dark,
+    "success": $success-bg-subtle-dark,
+    "info": $info-bg-subtle-dark,
+    "warning": $warning-bg-subtle-dark,
+    "danger": $danger-bg-subtle-dark,
+    "light": $light-bg-subtle-dark,
+    "dark": $dark-bg-subtle-dark,
+  ) !default;
+  // scss-docs-end theme-bg-subtle-dark-map
+
+  // scss-docs-start theme-border-subtle-dark-map
+  $theme-colors-border-subtle-dark: (
+    "primary": $primary-border-subtle-dark,
+    "secondary": $secondary-border-subtle-dark,
+    "success": $success-border-subtle-dark,
+    "info": $info-border-subtle-dark,
+    "warning": $warning-border-subtle-dark,
+    "danger": $danger-border-subtle-dark,
+    "light": $light-border-subtle-dark,
+    "dark": $dark-border-subtle-dark,
+  ) !default;
+  // scss-docs-end theme-border-subtle-dark-map
+}
+
 // Utilities maps
 //
 // Extends the default `$theme-colors` maps to help create our utilities.
@@ -25,6 +109,17 @@ $utilities-text: map-merge(
   )
 ) !default;
 $utilities-text-colors: map-loop($utilities-text, rgba-css-var, "$key", "text") !default;
+
+$utilities-text-emphasis-colors: (
+  "primary-emphasis": var(--#{$prefix}primary-text-emphasis),
+  "secondary-emphasis": var(--#{$prefix}secondary-text-emphasis),
+  "success-emphasis": var(--#{$prefix}success-text-emphasis),
+  "info-emphasis": var(--#{$prefix}info-text-emphasis),
+  "warning-emphasis": var(--#{$prefix}warning-text-emphasis),
+  "danger-emphasis": var(--#{$prefix}danger-text-emphasis),
+  "light-emphasis": var(--#{$prefix}light-text-emphasis),
+  "dark-emphasis": var(--#{$prefix}dark-text-emphasis)
+) !default;
 // scss-docs-end utilities-text-colors
 
 // scss-docs-start utilities-bg-colors
@@ -37,18 +132,43 @@ $utilities-bg: map-merge(
   )
 ) !default;
 $utilities-bg-colors: map-loop($utilities-bg, rgba-css-var, "$key", "bg") !default;
+
+$utilities-bg-subtle: (
+  "primary-subtle": var(--#{$prefix}primary-bg-subtle),
+  "secondary-subtle": var(--#{$prefix}secondary-bg-subtle),
+  "success-subtle": var(--#{$prefix}success-bg-subtle),
+  "info-subtle": var(--#{$prefix}info-bg-subtle),
+  "warning-subtle": var(--#{$prefix}warning-bg-subtle),
+  "danger-subtle": var(--#{$prefix}danger-bg-subtle),
+  "light-subtle": var(--#{$prefix}light-bg-subtle),
+  "dark-subtle": var(--#{$prefix}dark-bg-subtle)
+) !default;
 // scss-docs-end utilities-bg-colors
 
 // scss-docs-start utilities-border-colors
 $utilities-border: map-merge(
   $utilities-colors,
   (
+    "black": to-rgb($black),
     "white": to-rgb($white)
   )
 ) !default;
 $utilities-border-colors: map-loop($utilities-border, rgba-css-var, "$key", "border") !default;
+
+$utilities-border-subtle: (
+  "primary-subtle": var(--#{$prefix}primary-border-subtle),
+  "secondary-subtle": var(--#{$prefix}secondary-border-subtle),
+  "success-subtle": var(--#{$prefix}success-border-subtle),
+  "info-subtle": var(--#{$prefix}info-border-subtle),
+  "warning-subtle": var(--#{$prefix}warning-border-subtle),
+  "danger-subtle": var(--#{$prefix}danger-border-subtle),
+  "light-subtle": var(--#{$prefix}light-border-subtle),
+  "dark-subtle": var(--#{$prefix}dark-border-subtle)
+) !default;
 // scss-docs-end utilities-border-colors
 
+$utilities-links-underline: map-loop($utilities-colors, rgba-css-var, "$key", "link-underline") !default;
+
 $negative-spacers: if($enable-negative-margins, negativify-map($spacers), null) !default;
 
 $gutters: $spacers !default;

+ 1 - 2
coderedcms/static/coderedcms/vendor/bootstrap/scss/_mixins.scss

@@ -10,6 +10,7 @@
 
 // Helpers
 @import "mixins/breakpoints";
+@import "mixins/color-mode";
 @import "mixins/color-scheme";
 @import "mixins/image";
 @import "mixins/resize";
@@ -21,13 +22,11 @@
 @import "mixins/utilities";
 
 // Components
-@import "mixins/alert";
 @import "mixins/backdrop";
 @import "mixins/buttons";
 @import "mixins/caret";
 @import "mixins/pagination";
 @import "mixins/lists";
-@import "mixins/list-group";
 @import "mixins/forms";
 @import "mixins/table-variants";
 

+ 1 - 1
coderedcms/static/coderedcms/vendor/bootstrap/scss/_modal.scss

@@ -133,7 +133,7 @@
 
   .btn-close {
     padding: calc(var(--#{$prefix}modal-header-padding-y) * .5) calc(var(--#{$prefix}modal-header-padding-x) * .5);
-    margin: calc(var(--#{$prefix}modal-header-padding-y) * -.5) calc(var(--#{$prefix}modal-header-padding-x) * -.5) calc(var(--#{$prefix}modal-header-padding-y) * -.5) auto;
+    margin: calc(-.5 * var(--#{$prefix}modal-header-padding-y)) calc(-.5 * var(--#{$prefix}modal-header-padding-x)) calc(-.5 * var(--#{$prefix}modal-header-padding-y)) auto;
   }
 }
 

+ 44 - 19
coderedcms/static/coderedcms/vendor/bootstrap/scss/_nav.scss

@@ -28,6 +28,8 @@
   font-weight: var(--#{$prefix}nav-link-font-weight);
   color: var(--#{$prefix}nav-link-color);
   text-decoration: if($link-decoration == none, null, none);
+  background: none;
+  border: 0;
   @include transition($nav-link-transition);
 
   &:hover,
@@ -36,8 +38,14 @@
     text-decoration: if($link-hover-decoration == underline, none, null);
   }
 
+  &:focus-visible {
+    outline: 0;
+    box-shadow: $nav-link-focus-box-shadow;
+  }
+
   // Disabled state lightens text
-  &.disabled {
+  &.disabled,
+  &:disabled {
     color: var(--#{$prefix}nav-link-disabled-color);
     pointer-events: none;
     cursor: default;
@@ -62,8 +70,7 @@
   border-bottom: var(--#{$prefix}nav-tabs-border-width) solid var(--#{$prefix}nav-tabs-border-color);
 
   .nav-link {
-    margin-bottom: calc(var(--#{$prefix}nav-tabs-border-width) * -1); // stylelint-disable-line function-disallowed-list
-    background: none;
+    margin-bottom: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
     border: var(--#{$prefix}nav-tabs-border-width) solid transparent;
     @include border-top-radius(var(--#{$prefix}nav-tabs-border-radius));
 
@@ -73,13 +80,6 @@
       isolation: isolate;
       border-color: var(--#{$prefix}nav-tabs-link-hover-border-color);
     }
-
-    &.disabled,
-    &:disabled {
-      color: var(--#{$prefix}nav-link-disabled-color);
-      background-color: transparent;
-      border-color: transparent;
-    }
   }
 
   .nav-link.active,
@@ -91,7 +91,7 @@
 
   .dropdown-menu {
     // Make dropdown border overlap tab border
-    margin-top: calc(var(--#{$prefix}nav-tabs-border-width) * -1); // stylelint-disable-line function-disallowed-list
+    margin-top: calc(-1 * var(--#{$prefix}nav-tabs-border-width)); // stylelint-disable-line function-disallowed-list
     // Remove the top rounded corners here since there is a hard edge above the menu
     @include border-top-radius(0);
   }
@@ -110,15 +110,7 @@
   // scss-docs-end nav-pills-css-vars
 
   .nav-link {
-    background: none;
-    border: 0;
     @include border-radius(var(--#{$prefix}nav-pills-border-radius));
-
-    &:disabled {
-      color: var(--#{$prefix}nav-link-disabled-color);
-      background-color: transparent;
-      border-color: transparent;
-    }
   }
 
   .nav-link.active,
@@ -129,6 +121,39 @@
 }
 
 
+//
+// Underline
+//
+
+.nav-underline {
+  // scss-docs-start nav-underline-css-vars
+  --#{$prefix}nav-underline-gap: #{$nav-underline-gap};
+  --#{$prefix}nav-underline-border-width: #{$nav-underline-border-width};
+  --#{$prefix}nav-underline-link-active-color: #{$nav-underline-link-active-color};
+  // scss-docs-end nav-underline-css-vars
+
+  gap: var(--#{$prefix}nav-underline-gap);
+
+  .nav-link {
+    padding-right: 0;
+    padding-left: 0;
+    border-bottom: var(--#{$prefix}nav-underline-border-width) solid transparent;
+
+    &:hover,
+    &:focus {
+      border-bottom-color: currentcolor;
+    }
+  }
+
+  .nav-link.active,
+  .show > .nav-link {
+    font-weight: $font-weight-bold;
+    color: var(--#{$prefix}nav-underline-link-active-color);
+    border-bottom-color: currentcolor;
+  }
+}
+
+
 //
 // Justified variants
 //

+ 17 - 4
coderedcms/static/coderedcms/vendor/bootstrap/scss/_navbar.scss

@@ -100,9 +100,11 @@
   margin-bottom: 0;
   list-style: none;
 
-  .show > .nav-link,
-  .nav-link.active {
-    color: var(--#{$prefix}navbar-active-color);
+  .nav-link {
+    &.active,
+    &.show {
+      color: var(--#{$prefix}navbar-active-color);
+    }
   }
 
   .dropdown-menu {
@@ -264,7 +266,9 @@
   @include deprecate("`.navbar-light`", "v5.2.0", "v6.0.0", true);
 }
 
-.navbar-dark {
+.navbar-dark,
+.navbar[data-bs-theme="dark"] {
+  // scss-docs-start navbar-dark-css-vars
   --#{$prefix}navbar-color: #{$navbar-dark-color};
   --#{$prefix}navbar-hover-color: #{$navbar-dark-hover-color};
   --#{$prefix}navbar-disabled-color: #{$navbar-dark-disabled-color};
@@ -273,4 +277,13 @@
   --#{$prefix}navbar-brand-hover-color: #{$navbar-dark-brand-hover-color};
   --#{$prefix}navbar-toggler-border-color: #{$navbar-dark-toggler-border-color};
   --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
+  // scss-docs-end navbar-dark-css-vars
+}
+
+@if $enable-dark-mode {
+  @include color-mode(dark) {
+    .navbar-toggler-icon {
+      --#{$prefix}navbar-toggler-icon-bg: #{escape-svg($navbar-dark-toggler-icon-bg)};
+    }
+  }
 }

+ 9 - 6
coderedcms/static/coderedcms/vendor/bootstrap/scss/_offcanvas.scss

@@ -2,6 +2,7 @@
 
 %offcanvas-css-vars {
   // scss-docs-start offcanvas-css-vars
+  --#{$prefix}offcanvas-zindex: #{$zindex-offcanvas};
   --#{$prefix}offcanvas-width: #{$offcanvas-horizontal-width};
   --#{$prefix}offcanvas-height: #{$offcanvas-vertical-height};
   --#{$prefix}offcanvas-padding-x: #{$offcanvas-padding-x};
@@ -11,6 +12,8 @@
   --#{$prefix}offcanvas-border-width: #{$offcanvas-border-width};
   --#{$prefix}offcanvas-border-color: #{$offcanvas-border-color};
   --#{$prefix}offcanvas-box-shadow: #{$offcanvas-box-shadow};
+  --#{$prefix}offcanvas-transition: #{transform $offcanvas-transition-duration ease-in-out};
+  --#{$prefix}offcanvas-title-line-height: #{$offcanvas-title-line-height};
   // scss-docs-end offcanvas-css-vars
 }
 
@@ -31,7 +34,7 @@
     @include media-breakpoint-down($next) {
       position: fixed;
       bottom: 0;
-      z-index: $zindex-offcanvas;
+      z-index: var(--#{$prefix}offcanvas-zindex);
       display: flex;
       flex-direction: column;
       max-width: 100%;
@@ -41,7 +44,7 @@
       background-clip: padding-box;
       outline: 0;
       @include box-shadow(var(--#{$prefix}offcanvas-box-shadow));
-      @include transition(transform $offcanvas-transition-duration ease-in-out);
+      @include transition(var(--#{$prefix}offcanvas-transition));
 
       &.offcanvas-start {
         top: 0;
@@ -125,15 +128,15 @@
 
   .btn-close {
     padding: calc(var(--#{$prefix}offcanvas-padding-y) * .5) calc(var(--#{$prefix}offcanvas-padding-x) * .5);
-    margin-top: calc(var(--#{$prefix}offcanvas-padding-y) * -.5);
-    margin-right: calc(var(--#{$prefix}offcanvas-padding-x) * -.5);
-    margin-bottom: calc(var(--#{$prefix}offcanvas-padding-y) * -.5);
+    margin-top: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));
+    margin-right: calc(-.5 * var(--#{$prefix}offcanvas-padding-x));
+    margin-bottom: calc(-.5 * var(--#{$prefix}offcanvas-padding-y));
   }
 }
 
 .offcanvas-title {
   margin-bottom: 0;
-  line-height: $offcanvas-title-line-height;
+  line-height: var(--#{$prefix}offcanvas-title-line-height);
 }
 
 .offcanvas-body {

+ 1 - 1
coderedcms/static/coderedcms/vendor/bootstrap/scss/_pagination.scss

@@ -75,7 +75,7 @@
     margin-left: $pagination-margin-start;
   }
 
-  @if $pagination-margin-start == (calc($pagination-border-width * -1)) {
+  @if $pagination-margin-start == calc(#{$pagination-border-width} * -1) {
     &:first-child {
       .page-link {
         @include border-start-radius(var(--#{$prefix}pagination-border-radius));

+ 5 - 5
coderedcms/static/coderedcms/vendor/bootstrap/scss/_popover.scss

@@ -56,7 +56,7 @@
 
 .bs-popover-top {
   > .popover-arrow {
-    bottom: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
+    bottom: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
 
     &::before,
     &::after {
@@ -78,7 +78,7 @@
 /* rtl:begin:ignore */
 .bs-popover-end {
   > .popover-arrow {
-    left: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
+    left: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
     width: var(--#{$prefix}popover-arrow-height);
     height: var(--#{$prefix}popover-arrow-width);
 
@@ -103,7 +103,7 @@
 
 .bs-popover-bottom {
   > .popover-arrow {
-    top: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
+    top: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
 
     &::before,
     &::after {
@@ -128,7 +128,7 @@
     left: 50%;
     display: block;
     width: var(--#{$prefix}popover-arrow-width);
-    margin-left: calc(var(--#{$prefix}popover-arrow-width) * -.5); // stylelint-disable-line function-disallowed-list
+    margin-left: calc(-.5 * var(--#{$prefix}popover-arrow-width)); // stylelint-disable-line function-disallowed-list
     content: "";
     border-bottom: var(--#{$prefix}popover-border-width) solid var(--#{$prefix}popover-header-bg);
   }
@@ -137,7 +137,7 @@
 /* rtl:begin:ignore */
 .bs-popover-start {
   > .popover-arrow {
-    right: calc((var(--#{$prefix}popover-arrow-height) * -1) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
+    right: calc(-1 * (var(--#{$prefix}popover-arrow-height)) - var(--#{$prefix}popover-border-width)); // stylelint-disable-line function-disallowed-list
     width: var(--#{$prefix}popover-arrow-height);
     height: var(--#{$prefix}popover-arrow-width);
 

+ 10 - 1
coderedcms/static/coderedcms/vendor/bootstrap/scss/_progress.scss

@@ -8,7 +8,8 @@
 }
 // scss-docs-end progress-keyframes
 
-.progress {
+.progress,
+.progress-stacked {
   // scss-docs-start progress-css-vars
   --#{$prefix}progress-height: #{$progress-height};
   @include rfs($progress-font-size, --#{$prefix}progress-font-size);
@@ -46,6 +47,14 @@
   background-size: var(--#{$prefix}progress-height) var(--#{$prefix}progress-height);
 }
 
+.progress-stacked > .progress {
+  overflow: visible;
+}
+
+.progress-stacked > .progress > .progress-bar {
+  width: 100%;
+}
+
 @if $enable-transitions {
   .progress-bar-animated {
     animation: $progress-bar-animation-timing progress-bar-stripes;

+ 8 - 7
coderedcms/static/coderedcms/vendor/bootstrap/scss/_reboot.scss

@@ -87,7 +87,7 @@ hr {
   font-style: $headings-font-style;
   font-weight: $headings-font-weight;
   line-height: $headings-line-height;
-  color: $headings-color;
+  color: var(--#{$prefix}heading-color);
 }
 
 h1 {
@@ -217,6 +217,7 @@ small {
 
 mark {
   padding: $mark-padding;
+  color: var(--#{$prefix}highlight-color);
   background-color: var(--#{$prefix}highlight-bg);
 }
 
@@ -241,11 +242,11 @@ sup { top: -.5em; }
 // Links
 
 a {
-  color: var(--#{$prefix}link-color);
+  color: rgba(var(--#{$prefix}link-color-rgb), var(--#{$prefix}link-opacity, 1));
   text-decoration: $link-decoration;
 
   &:hover {
-    color: var(--#{$prefix}link-hover-color);
+    --#{$prefix}link-color-rgb: var(--#{$prefix}link-hover-color-rgb);
     text-decoration: $link-hover-decoration;
   }
 }
@@ -524,15 +525,15 @@ legend {
   height: auto;
 }
 
-// 1. Correct the outline style in Safari.
-// 2. This overrides the extra rounded corners on search inputs in iOS so that our
+// 1. This overrides the extra rounded corners on search inputs in iOS so that our
 //    `.form-control` class can properly style them. Note that this cannot simply
 //    be added to `.form-control` as it's not specific enough. For details, see
 //    https://github.com/twbs/bootstrap/issues/11586.
+// 2. Correct the outline style in Safari.
 
 [type="search"] {
-  outline-offset: -2px; // 1
-  -webkit-appearance: textfield; // 2
+  -webkit-appearance: textfield; // 1
+  outline-offset: -2px; // 2
 }
 
 // 1. A few input types should stay LTR

+ 124 - 10
coderedcms/static/coderedcms/vendor/bootstrap/scss/_root.scss

@@ -1,4 +1,5 @@
-:root {
+:root,
+[data-bs-theme="light"] {
   // Note: Custom variable values only support SassScript inside `#{}`.
 
   // Colors
@@ -21,10 +22,20 @@
     --#{$prefix}#{$color}-rgb: #{$value};
   }
 
+  @each $color, $value in $theme-colors-text {
+    --#{$prefix}#{$color}-text-emphasis: #{$value};
+  }
+
+  @each $color, $value in $theme-colors-bg-subtle {
+    --#{$prefix}#{$color}-bg-subtle: #{$value};
+  }
+
+  @each $color, $value in $theme-colors-border-subtle {
+    --#{$prefix}#{$color}-border-subtle: #{$value};
+  }
+
   --#{$prefix}white-rgb: #{to-rgb($white)};
   --#{$prefix}black-rgb: #{to-rgb($black)};
-  --#{$prefix}body-color-rgb: #{to-rgb($body-color)};
-  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};
 
   // Fonts
 
@@ -39,17 +50,50 @@
   @if $font-size-root != null {
     --#{$prefix}root-font-size: #{$font-size-root};
   }
-  --#{$prefix}body-font-family: #{$font-family-base};
+  --#{$prefix}body-font-family: #{inspect($font-family-base)};
   @include rfs($font-size-base, --#{$prefix}body-font-size);
   --#{$prefix}body-font-weight: #{$font-weight-base};
   --#{$prefix}body-line-height: #{$line-height-base};
-  --#{$prefix}body-color: #{$body-color};
   @if $body-text-align != null {
     --#{$prefix}body-text-align: #{$body-text-align};
   }
+
+  --#{$prefix}body-color: #{$body-color};
+  --#{$prefix}body-color-rgb: #{to-rgb($body-color)};
   --#{$prefix}body-bg: #{$body-bg};
+  --#{$prefix}body-bg-rgb: #{to-rgb($body-bg)};
+
+  --#{$prefix}emphasis-color: #{$body-emphasis-color};
+  --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color)};
+
+  --#{$prefix}secondary-color: #{$body-secondary-color};
+  --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color)};
+  --#{$prefix}secondary-bg: #{$body-secondary-bg};
+  --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg)};
+
+  --#{$prefix}tertiary-color: #{$body-tertiary-color};
+  --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color)};
+  --#{$prefix}tertiary-bg: #{$body-tertiary-bg};
+  --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg)};
   // scss-docs-end root-body-variables
 
+  --#{$prefix}heading-color: #{$headings-color};
+
+  --#{$prefix}link-color: #{$link-color};
+  --#{$prefix}link-color-rgb: #{to-rgb($link-color)};
+  --#{$prefix}link-decoration: #{$link-decoration};
+
+  --#{$prefix}link-hover-color: #{$link-hover-color};
+  --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color)};
+
+  @if $link-hover-decoration != null {
+    --#{$prefix}link-hover-decoration: #{$link-hover-decoration};
+  }
+
+  --#{$prefix}code-color: #{$code-color};
+  --#{$prefix}highlight-color: #{$mark-color};
+  --#{$prefix}highlight-bg: #{$mark-bg};
+
   // scss-docs-start root-border-var
   --#{$prefix}border-width: #{$border-width};
   --#{$prefix}border-style: #{$border-style};
@@ -60,14 +104,84 @@
   --#{$prefix}border-radius-sm: #{$border-radius-sm};
   --#{$prefix}border-radius-lg: #{$border-radius-lg};
   --#{$prefix}border-radius-xl: #{$border-radius-xl};
-  --#{$prefix}border-radius-2xl: #{$border-radius-2xl};
+  --#{$prefix}border-radius-xxl: #{$border-radius-xxl};
+  --#{$prefix}border-radius-2xl: var(--#{$prefix}border-radius-xxl); // Deprecated in v5.3.0 for consistency
   --#{$prefix}border-radius-pill: #{$border-radius-pill};
   // scss-docs-end root-border-var
 
-  --#{$prefix}link-color: #{$link-color};
-  --#{$prefix}link-hover-color: #{$link-hover-color};
+  --#{$prefix}box-shadow: #{$box-shadow};
+  --#{$prefix}box-shadow-sm: #{$box-shadow-sm};
+  --#{$prefix}box-shadow-lg: #{$box-shadow-lg};
+  --#{$prefix}box-shadow-inset: #{$box-shadow-inset};
 
-  --#{$prefix}code-color: #{$code-color};
+  // Focus styles
+  // scss-docs-start root-focus-variables
+  --#{$prefix}focus-ring-width: #{$focus-ring-width};
+  --#{$prefix}focus-ring-opacity: #{$focus-ring-opacity};
+  --#{$prefix}focus-ring-color: #{$focus-ring-color};
+  // scss-docs-end root-focus-variables
 
-  --#{$prefix}highlight-bg: #{$mark-bg};
+  // scss-docs-start root-form-validation-variables
+  --#{$prefix}form-valid-color: #{$form-valid-color};
+  --#{$prefix}form-valid-border-color: #{$form-valid-border-color};
+  --#{$prefix}form-invalid-color: #{$form-invalid-color};
+  --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color};
+  // scss-docs-end root-form-validation-variables
+}
+
+@if $enable-dark-mode {
+  @include color-mode(dark, true) {
+    color-scheme: dark;
+
+    // scss-docs-start root-dark-mode-vars
+    --#{$prefix}body-color: #{$body-color-dark};
+    --#{$prefix}body-color-rgb: #{to-rgb($body-color-dark)};
+    --#{$prefix}body-bg: #{$body-bg-dark};
+    --#{$prefix}body-bg-rgb: #{to-rgb($body-bg-dark)};
+
+    --#{$prefix}emphasis-color: #{$body-emphasis-color-dark};
+    --#{$prefix}emphasis-color-rgb: #{to-rgb($body-emphasis-color-dark)};
+
+    --#{$prefix}secondary-color: #{$body-secondary-color-dark};
+    --#{$prefix}secondary-color-rgb: #{to-rgb($body-secondary-color-dark)};
+    --#{$prefix}secondary-bg: #{$body-secondary-bg-dark};
+    --#{$prefix}secondary-bg-rgb: #{to-rgb($body-secondary-bg-dark)};
+
+    --#{$prefix}tertiary-color: #{$body-tertiary-color-dark};
+    --#{$prefix}tertiary-color-rgb: #{to-rgb($body-tertiary-color-dark)};
+    --#{$prefix}tertiary-bg: #{$body-tertiary-bg-dark};
+    --#{$prefix}tertiary-bg-rgb: #{to-rgb($body-tertiary-bg-dark)};
+
+    @each $color, $value in $theme-colors-text-dark {
+      --#{$prefix}#{$color}-text-emphasis: #{$value};
+    }
+
+    @each $color, $value in $theme-colors-bg-subtle-dark {
+      --#{$prefix}#{$color}-bg-subtle: #{$value};
+    }
+
+    @each $color, $value in $theme-colors-border-subtle-dark {
+      --#{$prefix}#{$color}-border-subtle: #{$value};
+    }
+
+    --#{$prefix}heading-color: #{$headings-color-dark};
+
+    --#{$prefix}link-color: #{$link-color-dark};
+    --#{$prefix}link-hover-color: #{$link-hover-color-dark};
+    --#{$prefix}link-color-rgb: #{to-rgb($link-color-dark)};
+    --#{$prefix}link-hover-color-rgb: #{to-rgb($link-hover-color-dark)};
+
+    --#{$prefix}code-color: #{$code-color-dark};
+    --#{$prefix}highlight-color: #{$mark-color-dark};
+    --#{$prefix}highlight-bg: #{$mark-bg-dark};
+
+    --#{$prefix}border-color: #{$border-color-dark};
+    --#{$prefix}border-color-translucent: #{$border-color-translucent-dark};
+
+    --#{$prefix}form-valid-color: #{$form-valid-color-dark};
+    --#{$prefix}form-valid-border-color: #{$form-valid-border-color-dark};
+    --#{$prefix}form-invalid-color: #{$form-invalid-color-dark};
+    --#{$prefix}form-invalid-border-color: #{$form-invalid-border-color-dark};
+    // scss-docs-end root-dark-mode-vars
+  }
 }

+ 18 - 11
coderedcms/static/coderedcms/vendor/bootstrap/scss/_tables.scss

@@ -3,6 +3,12 @@
 //
 
 .table {
+  // Reset needed for nesting tables
+  --#{$prefix}table-color-type: initial;
+  --#{$prefix}table-bg-type: initial;
+  --#{$prefix}table-color-state: initial;
+  --#{$prefix}table-bg-state: initial;
+  // End of reset
   --#{$prefix}table-color: #{$table-color};
   --#{$prefix}table-bg: #{$table-bg};
   --#{$prefix}table-border-color: #{$table-border-color};
@@ -16,7 +22,6 @@
 
   width: 100%;
   margin-bottom: $spacer;
-  color: var(--#{$prefix}table-color);
   vertical-align: $table-cell-vertical-align;
   border-color: var(--#{$prefix}table-border-color);
 
@@ -27,9 +32,11 @@
   // stylelint-disable-next-line selector-max-universal
   > :not(caption) > * > * {
     padding: $table-cell-padding-y $table-cell-padding-x;
+    // Following the precept of cascades: https://codepen.io/miriamsuzanne/full/vYNgodb
+    color: var(--#{$prefix}table-color-state, var(--#{$prefix}table-color-type, var(--#{$prefix}table-color)));
     background-color: var(--#{$prefix}table-bg);
     border-bottom-width: $table-border-width;
-    box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-accent-bg);
+    box-shadow: inset 0 0 0 9999px var(--#{$prefix}table-bg-state, var(--#{$prefix}table-bg-type, var(--#{$prefix}table-accent-bg)));
   }
 
   > tbody {
@@ -42,7 +49,7 @@
 }
 
 .table-group-divider {
-  border-top: ($table-border-width * 2) solid $table-group-separator-color;
+  border-top: calc(#{$table-border-width} * 2) solid $table-group-separator-color; // stylelint-disable-line function-disallowed-list
 }
 
 //
@@ -104,16 +111,16 @@
 // For rows
 .table-striped {
   > tbody > tr:nth-of-type(#{$table-striped-order}) > * {
-    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);
-    color: var(--#{$prefix}table-striped-color);
+    --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
+    --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
   }
 }
 
 // For columns
 .table-striped-columns {
   > :not(caption) > tr > :nth-child(#{$table-striped-columns-order}) {
-    --#{$prefix}table-accent-bg: var(--#{$prefix}table-striped-bg);
-    color: var(--#{$prefix}table-striped-color);
+    --#{$prefix}table-color-type: var(--#{$prefix}table-striped-color);
+    --#{$prefix}table-bg-type: var(--#{$prefix}table-striped-bg);
   }
 }
 
@@ -122,8 +129,8 @@
 // The `.table-active` class can be added to highlight rows or cells
 
 .table-active {
-  --#{$prefix}table-accent-bg: var(--#{$prefix}table-active-bg);
-  color: var(--#{$prefix}table-active-color);
+  --#{$prefix}table-color-state: var(--#{$prefix}table-active-color);
+  --#{$prefix}table-bg-state: var(--#{$prefix}table-active-bg);
 }
 
 // Hover effect
@@ -132,8 +139,8 @@
 
 .table-hover {
   > tbody > tr:hover > * {
-    --#{$prefix}table-accent-bg: var(--#{$prefix}table-hover-bg);
-    color: var(--#{$prefix}table-hover-color);
+    --#{$prefix}table-color-state: var(--#{$prefix}table-hover-color);
+    --#{$prefix}table-bg-state: var(--#{$prefix}table-hover-bg);
   }
 }
 

部分文件因文件數量過多而無法顯示