bootstrap5-toggle 4.3.5 → 5.0.0-alpha

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,346 +1,495 @@
1
- /* Copyright Notice
2
- * bootstrap5-toggle v4.3.5
3
- * https://palcarazm.github.io/bootstrap5-toggle/
4
- * @author 2011-2014 Min Hur (https://github.com/minhur)
5
- * @author 2018-2019 Brent Ely (https://github.com/gitbrent)
6
- * @author 2022 Pablo Alcaraz Martínez (https://github.com/palcarazm)
7
- * @funding GitHub Sponsors
8
- * @see https://github.com/sponsors/palcarazm
9
- * @license MIT
10
- * @see https://github.com/palcarazm/bootstrap5-toggle/blob/master/LICENSE
11
- */
12
-
13
-
14
- 'use strict';
15
-
16
- (function() {
17
- /**
18
- * `Toggle` is instantiated for each toggle-button
19
- */
20
- class Toggle {
21
- constructor(element, options) {
22
- const DEFAULTS = {
23
- on: 'On',
24
- onstyle: 'primary',
25
- onvalue: null,
26
- off: 'Off',
27
- offstyle: 'secondary',
28
- offvalue: null,
29
- size: '',
30
- style: '',
31
- width: null,
32
- height: null,
33
- tabindex: 0,
34
- tristate: false,
35
- name: null
36
- };
37
- options = options || {};
38
-
39
- // A: Capture ref to HMTL element
40
- this.element = element;
41
-
42
- // B: Set options
43
- this.options = {
44
- on: this.element.getAttribute('data-on') || options.on || DEFAULTS.on,
45
- onstyle: this.element.getAttribute('data-onstyle') || options.onstyle || DEFAULTS.onstyle,
46
- onvalue: this.element.getAttribute('value') || this.element.getAttribute('data-onvalue') || options.onvalue || DEFAULTS.onvalue,
47
- off: this.element.getAttribute('data-off') || options.off || DEFAULTS.off,
48
- offstyle: this.element.getAttribute('data-offstyle') || options.offstyle || DEFAULTS.offstyle,
49
- offvalue: this.element.getAttribute('data-offvalue') || options.offvalue || DEFAULTS.offvalue,
50
- size: this.element.getAttribute('data-size') || options.size || DEFAULTS.size,
51
- style: this.element.getAttribute('data-style') || options.style || DEFAULTS.style,
52
- width: this.element.getAttribute('data-width') || options.width || DEFAULTS.width,
53
- height: this.element.getAttribute('data-height') || options.height || DEFAULTS.height,
54
- tabindex: this.element.getAttribute('tabindex') || options.tabindex || DEFAULTS.tabindex,
55
- tristate: this.element.hasAttribute('tristate') || options.tristate || DEFAULTS.tristate,
56
- name: this.element.getAttribute('name') || options.name || DEFAULTS.name,
57
- };
58
-
59
- // LAST: Render Toggle
60
- this.render();
61
- }
62
- render() {
63
- function calcH(el) {
64
- const styles = window.getComputedStyle(el);
65
- const height = el.offsetHeight;
66
- const borderTopWidth = parseFloat(styles.borderTopWidth);
67
- const borderBottomWidth = parseFloat(styles.borderBottomWidth);
68
- const paddingTop = parseFloat(styles.paddingTop);
69
- const paddingBottom = parseFloat(styles.paddingBottom);
70
-
71
- return height - borderBottomWidth - borderTopWidth - paddingTop - paddingBottom;
72
- }
73
- // 0: Parse size
74
- let size;
75
- switch (this.options.size ) {
76
- case 'large':
77
- case 'lg':
78
- size = 'btn-lg';
79
- break;
80
- case 'small':
81
- case 'sm':
82
- size = 'btn-sm';
83
- break;
84
- case 'mini':
85
- case 'xs':
86
- size = 'btn-xs';
87
- break;
88
- default:
89
- size = ''
90
- break;
91
- }
92
-
93
- // 1: On
94
- let ecmasToggleOn = document.createElement('label');
95
- ecmasToggleOn.setAttribute('class', 'btn btn-' + this.options.onstyle + ' ' + size);
96
- ecmasToggleOn.setAttribute('for', this.element.id);
97
- ecmasToggleOn.innerHTML = this.options.on;
98
-
99
- // 2: Off
100
- let ecmasToggleOff = document.createElement('label');
101
- ecmasToggleOff.setAttribute('class', 'btn btn-' + this.options.offstyle + ' ' + size);
102
- ecmasToggleOff.setAttribute('for', this.element.id);
103
- ecmasToggleOff.innerHTML = this.options.off;
104
-
105
- // 3: Handle
106
- let ecmasToggleHandle = document.createElement('span');
107
- ecmasToggleHandle.setAttribute('class', 'toggle-handle btn ' + size);
108
-
109
- // 4: Toggle Group
110
- let ecmasToggleGroup = document.createElement('div');
111
- ecmasToggleGroup.setAttribute('class', 'toggle-group');
112
- ecmasToggleGroup.appendChild(ecmasToggleOn);
113
- ecmasToggleGroup.appendChild(ecmasToggleOff);
114
- ecmasToggleGroup.appendChild(ecmasToggleHandle);
115
-
116
- // 5: Toggle
117
- let ecmasToggle = document.createElement('div');
118
- ecmasToggle.setAttribute('class', 'toggle btn');
119
- ecmasToggle.classList.add(this.element.checked ? 'btn-' + this.options.onstyle : 'btn-' + this.options.offstyle);
120
- ecmasToggle.setAttribute('tabindex',this.options.tabindex);
121
- if (!this.element.checked) ecmasToggle.classList.add('off');
122
- if (this.options.size) ecmasToggle.classList.add(size);
123
- if (this.options.style) {
124
- (this.options.style).split(' ').forEach((style)=>{
125
- ecmasToggle.classList.add(style);
126
- });
127
- }
128
- if (this.element.disabled || this.element.readOnly){
129
- ecmasToggle.classList.add('disabled');
130
- ecmasToggle.setAttribute('disabled', 'disabled');
131
- }
132
-
133
- // 6: Set form values
134
- if(this.options.onvalue) this.element.setAttribute('value', this.options.onvalue);
135
- let invElement = null;
136
- if(this.options.offvalue){
137
- invElement = this.element.cloneNode();
138
- invElement.setAttribute('value',this.options.offvalue);
139
- invElement.setAttribute('data-toggle', 'invert-toggle');
140
- invElement.removeAttribute('id');
141
- invElement.checked = !this.element.checked;
142
- }
143
-
144
- // 7: Replace HTML checkbox with Toggle-Button
145
- this.element.parentElement.insertBefore(ecmasToggle, this.element);
146
- ecmasToggle.appendChild(this.element);
147
- if(invElement) ecmasToggle.appendChild(invElement);
148
- ecmasToggle.appendChild(ecmasToggleGroup);
149
-
150
- // 8: Set button W/H, lineHeight
151
- {
152
- // A: Set style W/H
153
- // NOTE: `offsetWidth` returns *rounded* integer values, so use `getBoundingClientRect` instead.
154
- ecmasToggle.style.width =
155
- (this.options.width ||
156
- Math.max(ecmasToggleOn.getBoundingClientRect().width, ecmasToggleOff.getBoundingClientRect().width) + ecmasToggleHandle.getBoundingClientRect().width / 2) + 'px';
157
- ecmasToggle.style.height = (this.options.height || Math.max(ecmasToggleOn.getBoundingClientRect().height, ecmasToggleOff.getBoundingClientRect().height)) + 'px';
158
-
159
- // B: Apply on/off class
160
- ecmasToggleOn.classList.add('toggle-on');
161
- ecmasToggleOff.classList.add('toggle-off');
162
-
163
- // C: Finally, set lineHeight if needed
164
- if (this.options.height) {
165
- ecmasToggleOn.style.lineHeight = calcH(ecmasToggleOn) + 'px';
166
- ecmasToggleOff.style.lineHeight = calcH(ecmasToggleOff) + 'px';
167
- }
168
- }
169
-
170
- // 9: Add listeners
171
- ecmasToggle.addEventListener('touchstart', (e)=>{
172
- this.#toggleActionPerformed(e)
173
- });
174
- ecmasToggle.addEventListener('click', (e)=>{
175
- this.#toggleActionPerformed(e)
176
- });
177
- ecmasToggle.addEventListener('keypress', (e)=>{
178
- if(e.key == " "){
179
- this.#toggleActionPerformed(e)
180
- }
181
- });
182
-
183
- // 10: Set elements to bootstrap object
184
- this.ecmasToggle = ecmasToggle;
185
- this.invElement = invElement;
186
-
187
- // 11: Keep reference to this instance for subsequent calls via `getElementById().bootstrapToggle()`
188
- this.element.bsToggle = this;
189
- }
190
-
191
- /**
192
- * Trigger actions
193
- * @param {Event} e event
194
- */
195
- #toggleActionPerformed(e){
196
- if(this.options.tristate){
197
- if(this.ecmasToggle.classList.contains('indeterminate')){
198
- this.determinate(true);
199
- this.toggle();
200
- }else{
201
- this.indeterminate();
202
- }
203
- }else{
204
- this.toggle()
205
- }
206
- e.preventDefault()
207
- }
208
-
209
- toggle(silent = false) {
210
- if (this.element.checked) this.off(silent);
211
- else this.on(silent);
212
- }
213
-
214
- on(silent = false) {
215
- if (this.element.disabled || this.element.readOnly) return false;
216
- this.ecmasToggle.classList.remove('btn-' + this.options.offstyle);
217
- this.ecmasToggle.classList.add('btn-' + this.options.onstyle);
218
- this.ecmasToggle.classList.remove('off');
219
- this.element.checked = true;
220
- if(this.invElement) this.invElement.checked = false;
221
- if (!silent) this.trigger();
222
- }
223
-
224
- off(silent = false) {
225
- if (this.element.disabled || this.element.readOnly) return false;
226
- this.ecmasToggle.classList.remove('btn-' + this.options.onstyle);
227
- this.ecmasToggle.classList.add('btn-' + this.options.offstyle);
228
- this.ecmasToggle.classList.add('off');
229
- this.element.checked = false;
230
- if(this.invElement) this.invElement.checked = true;
231
- if (!silent) this.trigger();
232
- }
233
-
234
- indeterminate(silent = false) {
235
- if (!this.options.tristate || this.element.disabled || this.element.readOnly) return false;
236
- this.ecmasToggle.classList.add('indeterminate');
237
- this.element.indeterminate = true;
238
- this.element.removeAttribute('name');
239
- if(this.invElement) this.invElement.indeterminate = true;
240
- if(this.invElement) this.invElement.removeAttribute('name');
241
- if (!silent) this.trigger()
242
- }
243
-
244
- determinate(silent = false) {
245
- if (!this.options.tristate || this.element.disabled || this.element.readOnly) return false;
246
- this.ecmasToggle.classList.remove('indeterminate');
247
- this.element.indeterminate = false;
248
- if(this.options.name) this.element.setAttribute('name', this.options.name);
249
- if(this.invElement) this.invElement.indeterminate = false;
250
- if(this.invElement && this.options.name) this.invElement.setAttribute('name', this.options.name);
251
- if (!silent) this.trigger()
252
- }
253
-
254
- enable() {
255
- this.ecmasToggle.classList.remove('disabled');
256
- this.ecmasToggle.removeAttribute('disabled');
257
- this.element.removeAttribute('disabled');
258
- this.element.removeAttribute('readonly');
259
- if(this.invElement) {
260
- this.invElement.removeAttribute('disabled');
261
- this.invElement.removeAttribute('readonly');
262
- }
263
- }
264
-
265
- disable() {
266
- this.ecmasToggle.classList.add('disabled');
267
- this.ecmasToggle.setAttribute('disabled', '');
268
- this.element.setAttribute('disabled', '');
269
- this.element.removeAttribute('readonly');
270
- if(this.invElement) {
271
- this.invElement.setAttribute('disabled', '');
272
- this.invElement.removeAttribute('readonly');
273
- }
274
- }
275
-
276
- readonly() {
277
- this.ecmasToggle.classList.add('disabled');
278
- this.ecmasToggle.setAttribute('disabled', '');
279
- this.element.removeAttribute('disabled');
280
- this.element.setAttribute('readonly', '');
281
- if(this.invElement) {
282
- this.invElement.removeAttribute('disabled');
283
- this.invElement.setAttribute('readonly', '');
284
- }
285
- }
286
-
287
- update(silent) {
288
- if (this.element.disabled) this.disable();
289
- else if (this.element.readOnly) this.readonly();
290
- else this.enable();
291
- if (this.element.checked) this.on(silent);
292
- else this.off(silent);
293
- }
294
-
295
- trigger(silent) {
296
- if (!silent) this.element.dispatchEvent(new Event('change', { bubbles: true }));
297
- }
298
-
299
- destroy() {
300
- // A: Remove button-group from UI, replace checkbox element
301
- this.ecmasToggle.parentNode.insertBefore(this.element, this.ecmasToggle);
302
- this.ecmasToggle.parentNode.removeChild(this.ecmasToggle);
303
-
304
- // B: Delete internal refs
305
- delete this.element.bsToggle;
306
- delete this.ecmasToggle;
307
- }
308
- }
309
-
310
- /**
311
- * Add `bootstrapToggle` prototype function to HTML Elements
312
- * Enables execution when used with HTML - ex: `document.getElementById('toggle').bootstrapToggle('on')`
313
- */
314
- Element.prototype.bootstrapToggle = function(options, silent) {
315
- let _bsToggle = this.bsToggle || new Toggle(this, options);
316
-
317
- // Execute method calls
318
- if (options && typeof options === 'string') {
319
- if (options.toLowerCase() == 'toggle') _bsToggle.toggle(silent);
320
- else if (options.toLowerCase() == 'on') _bsToggle.on(silent);
321
- else if (options.toLowerCase() == 'off') _bsToggle.off(silent);
322
- else if (options.toLowerCase() == 'indeterminate') _bsToggle.indeterminate(silent);
323
- else if (options.toLowerCase() == 'determinate') _bsToggle.determinate(silent);
324
- else if (options.toLowerCase() == 'enable') _bsToggle.enable();
325
- else if (options.toLowerCase() == 'disable') _bsToggle.disable();
326
- else if (options.toLowerCase() == 'readonly') _bsToggle.readonly();
327
- else if (options.toLowerCase() == 'destroy') _bsToggle.destroy();
328
- }
329
- };
330
-
331
- /**
332
- * Replace all `input[type=checkbox][data-toggle="toggle"]` inputs with "Bootstrap-Toggle"
333
- * Executes once page elements have rendered enabling script to be placed in `<head>`
334
- */
335
- if (typeof window !== 'undefined')
336
- window.onload = function() {
337
- document.querySelectorAll('input[type=checkbox][data-toggle="toggle"]').forEach(function(ele) {
338
- ele.bootstrapToggle();
339
- });
340
- };
341
-
342
- // Export library if possible
343
- if (typeof module !== 'undefined' && module.exports) {
344
- module.exports = Toggle;
345
- }
346
- })();
1
+ /* Copyright Notice
2
+ * bootstrap5-toggle v5.0.0-alpha
3
+ * https://palcarazm.github.io/bootstrap5-toggle/
4
+ * @author 2011-2014 Min Hur (https://github.com/minhur)
5
+ * @author 2018-2019 Brent Ely (https://github.com/gitbrent)
6
+ * @author 2022 Pablo Alcaraz Martínez (https://github.com/palcarazm)
7
+ * @funding GitHub Sponsors
8
+ * @see https://github.com/sponsors/palcarazm
9
+ * @license MIT
10
+ * @see https://github.com/palcarazm/bootstrap5-toggle/blob/master/LICENSE
11
+ */
12
+
13
+
14
+ "use strict";
15
+
16
+ (function () {
17
+ /**
18
+ * `Toggle` is instantiated for each toggle-button
19
+ */
20
+ class Toggle {
21
+ constructor(element, options) {
22
+ const DEPRECATION = {
23
+ value:
24
+ "BOOTSTRAP TOGGLE DEPRECATION CHECK -- a0Jhux0QySypjjs4tLtEo8xT2kx0AbYaq9K6mgNjWSs0HF0L8T8J0M0o3Kr7zkm7 --",
25
+ ATTRIBUTE: "attribute",
26
+ OPTION: "option",
27
+ log: function (type, oldlabel, newlabel) {
28
+ console.warn(
29
+ `Bootstrap Toggle deprecation warning: Using ${oldlabel} ${type} is deprected. Use ${newlabel} instead.`
30
+ );
31
+ },
32
+ };
33
+ const DEFAULTS = {
34
+ onlabel: "On",
35
+ onstyle: "primary",
36
+ onvalue: null,
37
+ ontitle: null,
38
+ offlabel: "Off",
39
+ offstyle: "secondary",
40
+ offvalue: null,
41
+ offtitle: null,
42
+ size: "",
43
+ style: "",
44
+ width: null,
45
+ height: null,
46
+ tabindex: 0,
47
+ tristate: false,
48
+ name: null,
49
+ };
50
+ options = options || {};
51
+
52
+ // A: Capture ref to HMTL element
53
+ this.element = element;
54
+
55
+ // B: Set options
56
+ this.options = {
57
+ onlabel:
58
+ this.element.getAttribute("data-onlabel") ||
59
+ options.onlabel ||
60
+ DEPRECATION.value ||
61
+ DEFAULTS.onlabel,
62
+ onstyle:
63
+ this.element.getAttribute("data-onstyle") ||
64
+ options.onstyle ||
65
+ DEFAULTS.onstyle,
66
+ onvalue:
67
+ this.element.getAttribute("value") ||
68
+ this.element.getAttribute("data-onvalue") ||
69
+ options.onvalue ||
70
+ DEFAULTS.onvalue,
71
+ ontitle:
72
+ this.element.getAttribute("data-ontitle") ||
73
+ options.ontitle ||
74
+ this.element.getAttribute("title") ||
75
+ DEFAULTS.ontitle,
76
+ offlabel:
77
+ this.element.getAttribute("data-offlabel") ||
78
+ options.offlabel ||
79
+ DEPRECATION.value ||
80
+ DEFAULTS.offlabel,
81
+ offstyle:
82
+ this.element.getAttribute("data-offstyle") ||
83
+ options.offstyle ||
84
+ DEFAULTS.offstyle,
85
+ offvalue:
86
+ this.element.getAttribute("data-offvalue") ||
87
+ options.offvalue ||
88
+ DEFAULTS.offvalue,
89
+ offtitle:
90
+ this.element.getAttribute("data-offtitle") ||
91
+ options.offtitle ||
92
+ this.element.getAttribute("title") ||
93
+ DEFAULTS.offtitle,
94
+ size:
95
+ this.element.getAttribute("data-size") ||
96
+ options.size ||
97
+ DEFAULTS.size,
98
+ style:
99
+ this.element.getAttribute("data-style") ||
100
+ options.style ||
101
+ DEFAULTS.style,
102
+ width:
103
+ this.element.getAttribute("data-width") ||
104
+ options.width ||
105
+ DEFAULTS.width,
106
+ height:
107
+ this.element.getAttribute("data-height") ||
108
+ options.height ||
109
+ DEFAULTS.height,
110
+ tabindex:
111
+ this.element.getAttribute("tabindex") ||
112
+ options.tabindex ||
113
+ DEFAULTS.tabindex,
114
+ tristate:
115
+ this.element.hasAttribute("tristate") ||
116
+ options.tristate ||
117
+ DEFAULTS.tristate,
118
+ name:
119
+ this.element.getAttribute("name") || options.name || DEFAULTS.name,
120
+ };
121
+
122
+ // C: Check deprecations
123
+ if (this.options.onlabel === DEPRECATION.value) {
124
+ if (this.element.getAttribute("data-on")) {
125
+ DEPRECATION.log(DEPRECATION.ATTRIBUTE, "data-on", "data-onlabel");
126
+ this.options.onlabel = this.element.getAttribute("data-on");
127
+ } else if (options.on) {
128
+ DEPRECATION.log(DEPRECATION.OPTION, "on", "onlabel");
129
+ this.options.onlabel = options.on;
130
+ } else {
131
+ this.options.onlabel = DEFAULTS.onlabel;
132
+ }
133
+ }
134
+ if (this.options.offlabel === DEPRECATION.value) {
135
+ if (this.element.getAttribute("data-off")) {
136
+ DEPRECATION.log(DEPRECATION.ATTRIBUTE, "data-off", "data-offlabel");
137
+ this.options.offlabel = this.element.getAttribute("data-off");
138
+ } else if (options.off) {
139
+ DEPRECATION.log(DEPRECATION.OPTION, "off", "offlabel");
140
+ this.options.offlabel = options.off;
141
+ } else {
142
+ this.options.offlabel = DEFAULTS.offlabel;
143
+ }
144
+ }
145
+
146
+ // LAST: Render Toggle
147
+ this.render();
148
+ }
149
+ render() {
150
+ function calcH(el) {
151
+ const styles = window.getComputedStyle(el);
152
+ const height = el.offsetHeight;
153
+ const borderTopWidth = parseFloat(styles.borderTopWidth);
154
+ const borderBottomWidth = parseFloat(styles.borderBottomWidth);
155
+ const paddingTop = parseFloat(styles.paddingTop);
156
+ const paddingBottom = parseFloat(styles.paddingBottom);
157
+
158
+ return (
159
+ height -
160
+ borderBottomWidth -
161
+ borderTopWidth -
162
+ paddingTop -
163
+ paddingBottom
164
+ );
165
+ }
166
+ // 0: Parse size
167
+ let size;
168
+ switch (this.options.size) {
169
+ case "large":
170
+ case "lg":
171
+ size = "btn-lg";
172
+ break;
173
+ case "small":
174
+ case "sm":
175
+ size = "btn-sm";
176
+ break;
177
+ case "mini":
178
+ case "xs":
179
+ size = "btn-xs";
180
+ break;
181
+ default:
182
+ size = "";
183
+ break;
184
+ }
185
+
186
+ // 1: On
187
+ let ecmasToggleOn = document.createElement("span");
188
+ ecmasToggleOn.setAttribute(
189
+ "class",
190
+ "btn btn-" + this.options.onstyle + " " + size
191
+ );
192
+ ecmasToggleOn.innerHTML = this.options.onlabel;
193
+ if (this.options.ontitle) {
194
+ ecmasToggleOn.setAttribute("title", this.options.ontitle);
195
+ }
196
+
197
+ // 2: Off
198
+ let ecmasToggleOff = document.createElement("span");
199
+ ecmasToggleOff.setAttribute(
200
+ "class",
201
+ "btn btn-" + this.options.offstyle + " " + size
202
+ );
203
+ ecmasToggleOff.innerHTML = this.options.offlabel;
204
+ if (this.options.offtitle) {
205
+ ecmasToggleOff.setAttribute("title", this.options.offtitle);
206
+ }
207
+
208
+ // 3: Handle
209
+ let ecmasToggleHandle = document.createElement("span");
210
+ ecmasToggleHandle.setAttribute("class", "toggle-handle btn " + size);
211
+
212
+ // 4: Toggle Group
213
+ let ecmasToggleGroup = document.createElement("div");
214
+ ecmasToggleGroup.setAttribute("class", "toggle-group");
215
+ ecmasToggleGroup.appendChild(ecmasToggleOn);
216
+ ecmasToggleGroup.appendChild(ecmasToggleOff);
217
+ ecmasToggleGroup.appendChild(ecmasToggleHandle);
218
+
219
+ // 5: Toggle
220
+ let ecmasToggle = document.createElement("div");
221
+ ecmasToggle.setAttribute("class", "toggle btn");
222
+ ecmasToggle.classList.add(
223
+ this.element.checked
224
+ ? "btn-" + this.options.onstyle
225
+ : "btn-" + this.options.offstyle
226
+ );
227
+ ecmasToggle.setAttribute("tabindex", this.options.tabindex);
228
+ if (!this.element.checked) ecmasToggle.classList.add("off");
229
+ if (this.options.size) ecmasToggle.classList.add(size);
230
+ if (this.options.style) {
231
+ this.options.style.split(" ").forEach((style) => {
232
+ ecmasToggle.classList.add(style);
233
+ });
234
+ }
235
+ if (this.element.disabled || this.element.readOnly) {
236
+ ecmasToggle.classList.add("disabled");
237
+ ecmasToggle.setAttribute("disabled", "disabled");
238
+ }
239
+
240
+ // 6: Set form values
241
+ if (this.options.onvalue)
242
+ this.element.setAttribute("value", this.options.onvalue);
243
+ let invElement = null;
244
+ if (this.options.offvalue) {
245
+ invElement = this.element.cloneNode();
246
+ invElement.setAttribute("value", this.options.offvalue);
247
+ invElement.setAttribute("data-toggle", "invert-toggle");
248
+ invElement.removeAttribute("id");
249
+ invElement.checked = !this.element.checked;
250
+ }
251
+
252
+ // 7: Replace HTML checkbox with Toggle-Button
253
+ this.element.parentElement.insertBefore(ecmasToggle, this.element);
254
+ ecmasToggle.appendChild(this.element);
255
+ if (invElement) ecmasToggle.appendChild(invElement);
256
+ ecmasToggle.appendChild(ecmasToggleGroup);
257
+
258
+ // 8: Set button W/H, lineHeight
259
+ {
260
+ // A: Set style W/H
261
+ // NOTE: `offsetWidth` returns *rounded* integer values, so use `getBoundingClientRect` instead.
262
+ ecmasToggle.style.width =
263
+ (this.options.width ||
264
+ Math.max(
265
+ ecmasToggleOn.getBoundingClientRect().width,
266
+ ecmasToggleOff.getBoundingClientRect().width
267
+ ) +
268
+ ecmasToggleHandle.getBoundingClientRect().width / 2) + "px";
269
+ ecmasToggle.style.height =
270
+ (this.options.height ||
271
+ Math.max(
272
+ ecmasToggleOn.getBoundingClientRect().height,
273
+ ecmasToggleOff.getBoundingClientRect().height
274
+ )) + "px";
275
+
276
+ // B: Apply on/off class
277
+ ecmasToggleOn.classList.add("toggle-on");
278
+ ecmasToggleOff.classList.add("toggle-off");
279
+
280
+ // C: Finally, set lineHeight if needed
281
+ if (this.options.height) {
282
+ ecmasToggleOn.style.lineHeight = calcH(ecmasToggleOn) + "px";
283
+ ecmasToggleOff.style.lineHeight = calcH(ecmasToggleOff) + "px";
284
+ }
285
+ }
286
+
287
+ // 9: Add listeners
288
+ ecmasToggle.addEventListener("touchstart", (e) => {
289
+ this.#toggleActionPerformed(e);
290
+ });
291
+ ecmasToggle.addEventListener("click", (e) => {
292
+ this.#toggleActionPerformed(e);
293
+ });
294
+ ecmasToggle.addEventListener("keypress", (e) => {
295
+ if (e.key == " ") {
296
+ this.#toggleActionPerformed(e);
297
+ }
298
+ });
299
+
300
+ if (this.element.id) {
301
+ document
302
+ .querySelectorAll('label[for="' + this.element.id + '"]')
303
+ .forEach((label) => {
304
+ label.addEventListener("touchstart", (_e) => {
305
+ this.toggle();
306
+ ecmasToggle.focus();
307
+ });
308
+ label.addEventListener("click", (_e) => {
309
+ this.toggle();
310
+ ecmasToggle.focus();
311
+ });
312
+ });
313
+ }
314
+
315
+ // 10: Set elements to bootstrap object
316
+ this.ecmasToggle = ecmasToggle;
317
+ this.invElement = invElement;
318
+
319
+ // 11: Keep reference to this instance for subsequent calls via `getElementById().bootstrapToggle()`
320
+ this.element.bsToggle = this;
321
+ }
322
+
323
+ /**
324
+ * Trigger actions
325
+ * @param {Event} e event
326
+ */
327
+ #toggleActionPerformed(e) {
328
+ if (this.options.tristate) {
329
+ if (this.ecmasToggle.classList.contains("indeterminate")) {
330
+ this.determinate(true);
331
+ this.toggle();
332
+ } else {
333
+ this.indeterminate();
334
+ }
335
+ } else {
336
+ this.toggle();
337
+ }
338
+ e.preventDefault();
339
+ }
340
+
341
+ toggle(silent = false) {
342
+ if (this.element.checked) this.off(silent);
343
+ else this.on(silent);
344
+ }
345
+
346
+ on(silent = false) {
347
+ if (this.element.disabled || this.element.readOnly) return false;
348
+ this.ecmasToggle.classList.remove("btn-" + this.options.offstyle);
349
+ this.ecmasToggle.classList.add("btn-" + this.options.onstyle);
350
+ this.ecmasToggle.classList.remove("off");
351
+ this.element.checked = true;
352
+ if (this.invElement) this.invElement.checked = false;
353
+ if (!silent) this.trigger();
354
+ }
355
+
356
+ off(silent = false) {
357
+ if (this.element.disabled || this.element.readOnly) return false;
358
+ this.ecmasToggle.classList.remove("btn-" + this.options.onstyle);
359
+ this.ecmasToggle.classList.add("btn-" + this.options.offstyle);
360
+ this.ecmasToggle.classList.add("off");
361
+ this.element.checked = false;
362
+ if (this.invElement) this.invElement.checked = true;
363
+ if (!silent) this.trigger();
364
+ }
365
+
366
+ indeterminate(silent = false) {
367
+ if (
368
+ !this.options.tristate ||
369
+ this.element.disabled ||
370
+ this.element.readOnly
371
+ )
372
+ return false;
373
+ this.ecmasToggle.classList.add("indeterminate");
374
+ this.element.indeterminate = true;
375
+ this.element.removeAttribute("name");
376
+ if (this.invElement) this.invElement.indeterminate = true;
377
+ if (this.invElement) this.invElement.removeAttribute("name");
378
+ if (!silent) this.trigger();
379
+ }
380
+
381
+ determinate(silent = false) {
382
+ if (
383
+ !this.options.tristate ||
384
+ this.element.disabled ||
385
+ this.element.readOnly
386
+ )
387
+ return false;
388
+ this.ecmasToggle.classList.remove("indeterminate");
389
+ this.element.indeterminate = false;
390
+ if (this.options.name)
391
+ this.element.setAttribute("name", this.options.name);
392
+ if (this.invElement) this.invElement.indeterminate = false;
393
+ if (this.invElement && this.options.name)
394
+ this.invElement.setAttribute("name", this.options.name);
395
+ if (!silent) this.trigger();
396
+ }
397
+
398
+ enable() {
399
+ this.ecmasToggle.classList.remove("disabled");
400
+ this.ecmasToggle.removeAttribute("disabled");
401
+ this.element.removeAttribute("disabled");
402
+ this.element.removeAttribute("readonly");
403
+ if (this.invElement) {
404
+ this.invElement.removeAttribute("disabled");
405
+ this.invElement.removeAttribute("readonly");
406
+ }
407
+ }
408
+
409
+ disable() {
410
+ this.ecmasToggle.classList.add("disabled");
411
+ this.ecmasToggle.setAttribute("disabled", "");
412
+ this.element.setAttribute("disabled", "");
413
+ this.element.removeAttribute("readonly");
414
+ if (this.invElement) {
415
+ this.invElement.setAttribute("disabled", "");
416
+ this.invElement.removeAttribute("readonly");
417
+ }
418
+ }
419
+
420
+ readonly() {
421
+ this.ecmasToggle.classList.add("disabled");
422
+ this.ecmasToggle.setAttribute("disabled", "");
423
+ this.element.removeAttribute("disabled");
424
+ this.element.setAttribute("readonly", "");
425
+ if (this.invElement) {
426
+ this.invElement.removeAttribute("disabled");
427
+ this.invElement.setAttribute("readonly", "");
428
+ }
429
+ }
430
+
431
+ update(silent) {
432
+ if (this.element.disabled) this.disable();
433
+ else if (this.element.readOnly) this.readonly();
434
+ else this.enable();
435
+ if (this.element.checked) this.on(silent);
436
+ else this.off(silent);
437
+ }
438
+
439
+ trigger(silent) {
440
+ if (!silent)
441
+ this.element.dispatchEvent(new Event("change", { bubbles: true }));
442
+ }
443
+
444
+ destroy() {
445
+ // A: Remove button-group from UI, replace checkbox element
446
+ this.ecmasToggle.parentNode.insertBefore(this.element, this.ecmasToggle);
447
+ this.ecmasToggle.parentNode.removeChild(this.ecmasToggle);
448
+
449
+ // B: Delete internal refs
450
+ delete this.element.bsToggle;
451
+ delete this.ecmasToggle;
452
+ }
453
+ }
454
+
455
+ /**
456
+ * Add `bootstrapToggle` prototype function to HTML Elements
457
+ * Enables execution when used with HTML - ex: `document.getElementById('toggle').bootstrapToggle('on')`
458
+ */
459
+ Element.prototype.bootstrapToggle = function (options, silent) {
460
+ let _bsToggle = this.bsToggle || new Toggle(this, options);
461
+
462
+ // Execute method calls
463
+ if (options && typeof options === "string") {
464
+ if (options.toLowerCase() == "toggle") _bsToggle.toggle(silent);
465
+ else if (options.toLowerCase() == "on") _bsToggle.on(silent);
466
+ else if (options.toLowerCase() == "off") _bsToggle.off(silent);
467
+ else if (options.toLowerCase() == "indeterminate")
468
+ _bsToggle.indeterminate(silent);
469
+ else if (options.toLowerCase() == "determinate")
470
+ _bsToggle.determinate(silent);
471
+ else if (options.toLowerCase() == "enable") _bsToggle.enable();
472
+ else if (options.toLowerCase() == "disable") _bsToggle.disable();
473
+ else if (options.toLowerCase() == "readonly") _bsToggle.readonly();
474
+ else if (options.toLowerCase() == "destroy") _bsToggle.destroy();
475
+ }
476
+ };
477
+
478
+ /**
479
+ * Replace all `input[type=checkbox][data-toggle="toggle"]` inputs with "Bootstrap-Toggle"
480
+ * Executes once page elements have rendered enabling script to be placed in `<head>`
481
+ */
482
+ if (typeof window !== "undefined")
483
+ window.onload = function () {
484
+ document
485
+ .querySelectorAll('input[type=checkbox][data-toggle="toggle"]')
486
+ .forEach(function (ele) {
487
+ ele.bootstrapToggle();
488
+ });
489
+ };
490
+
491
+ // Export library if possible
492
+ if (typeof module !== "undefined" && module.exports) {
493
+ module.exports = Toggle;
494
+ }
495
+ })();