stimulus-library 0.3.19 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +14 -0
- package/dist/controllers/ajax/async_block_controller.d.ts +18 -18
- package/dist/controllers/ajax/lazy_block_controller.d.ts +9 -9
- package/dist/controllers/ajax/load_block_controller.d.ts +19 -19
- package/dist/controllers/ajax/poll_block_controller.d.ts +16 -16
- package/dist/controllers/anchor_spy_controller.d.ts +15 -15
- package/dist/controllers/back_link_controller.d.ts +19 -19
- package/dist/controllers/clipboard_controller.d.ts +18 -18
- package/dist/controllers/confirm_controller.d.ts +13 -13
- package/dist/controllers/confirm_navigation_controller.d.ts +15 -15
- package/dist/controllers/debug_controller.d.ts +6 -6
- package/dist/controllers/disable_with_controller.d.ts +25 -25
- package/dist/controllers/dismissable_controller.d.ts +6 -6
- package/dist/controllers/element_save_controller.d.ts +25 -25
- package/dist/controllers/empty_dom_controller.d.ts +29 -29
- package/dist/controllers/forms/auto_submit_form_controller.d.ts +15 -14
- package/dist/controllers/forms/auto_submit_form_controller.d.ts.map +1 -1
- package/dist/controllers/forms/autosize_controller.d.ts +9 -9
- package/dist/controllers/forms/char_count_controller.d.ts +26 -26
- package/dist/controllers/forms/checkbox_select_all_controller.d.ts +14 -14
- package/dist/controllers/forms/detect_dirty_controller.d.ts +16 -16
- package/dist/controllers/forms/detect_dirty_form_controller.d.ts +19 -19
- package/dist/controllers/forms/disable_inputs_controller.d.ts +16 -16
- package/dist/controllers/forms/enable_inputs_controller.d.ts +16 -16
- package/dist/controllers/forms/form_rc_controller.d.ts +13 -7
- package/dist/controllers/forms/form_rc_controller.d.ts.map +1 -1
- package/dist/controllers/forms/form_save_controller.d.ts +33 -33
- package/dist/controllers/forms/limited_selection_checkboxes_controller.d.ts +17 -17
- package/dist/controllers/forms/navigate_form_errors_controller.d.ts +34 -34
- package/dist/controllers/forms/nested_form_controller.d.ts +21 -21
- package/dist/controllers/forms/password_confirm_controller.d.ts +17 -17
- package/dist/controllers/forms/password_peek_controller.d.ts +8 -8
- package/dist/controllers/forms/remote_form_controller.d.ts +13 -13
- package/dist/controllers/forms/sync_inputs_controller.d.ts +21 -21
- package/dist/controllers/forms/value_warn_controller.d.ts +39 -39
- package/dist/controllers/forms/word_count_controller.d.ts +26 -26
- package/dist/controllers/media/fallback_image_controller.d.ts +27 -27
- package/dist/controllers/media/lightbox_image_controller.d.ts +29 -29
- package/dist/controllers/media/media_player_controller.d.ts +12 -12
- package/dist/controllers/prefetch_controller.d.ts +18 -18
- package/dist/controllers/responsive_iframe_controller.d.ts +23 -23
- package/dist/controllers/scroll/scroll_container_controller.d.ts +21 -21
- package/dist/controllers/scroll/scroll_into_focus_controller.d.ts +15 -15
- package/dist/controllers/scroll/scroll_to_bottom_controller.d.ts +11 -11
- package/dist/controllers/scroll/scroll_to_controller.d.ts +17 -17
- package/dist/controllers/scroll/scroll_to_top_controller.d.ts +11 -11
- package/dist/controllers/self_destruct_controller.d.ts +10 -10
- package/dist/controllers/sticky_controller.d.ts +19 -19
- package/dist/controllers/tables/table_sort_controller.d.ts +20 -20
- package/dist/controllers/tables/table_truncate_controller.d.ts +26 -26
- package/dist/controllers/teleport_controller.d.ts +15 -15
- package/dist/controllers/temporary_state_controller.d.ts +28 -28
- package/dist/controllers/toggle_class_controller.d.ts +35 -35
- package/dist/controllers/turbo_frame_rc_controller.d.ts +20 -20
- package/dist/controllers/turbo_frame_refresh_controller.d.ts +16 -16
- package/dist/controllers/utility/intersection_controller.d.ts +13 -13
- package/dist/controllers/utility/interval_controller.d.ts +13 -13
- package/dist/controllers/utility/presence_controller.d.ts +5 -5
- package/dist/controllers/utility/timeout_controller.d.ts +12 -12
- package/dist/controllers/utility/user_focus_controller.d.ts +10 -10
- package/dist/controllers/visual/clock_controller.d.ts +18 -18
- package/dist/controllers/visual/countdown_controller.d.ts +53 -53
- package/dist/controllers/visual/duration_controller.d.ts +27 -27
- package/dist/controllers/visual/tabs_controller.d.ts +37 -37
- package/dist/controllers/visual/time_distance_controller.d.ts +18 -18
- package/dist/controllers/visual/tree_view_controller.d.ts +29 -29
- package/dist/index.d.ts +66 -66
- package/dist/stimulus-library.cjs.js +2 -0
- package/dist/stimulus-library.cjs.js.map +1 -0
- package/dist/stimulus-library.es.js +2 -0
- package/dist/stimulus-library.es.js.map +1 -0
- package/dist/stimulus-library.umd.js +1 -1
- package/dist/stimulus-library.umd.js.map +1 -1
- package/dist/utilities/base_controller.d.ts +13 -13
- package/dist/utilities/base_controller.d.ts.map +1 -1
- package/dist/utilities/elements.d.ts +13 -13
- package/dist/utilities/ephemeral_controller.d.ts +5 -5
- package/dist/utilities/event_bus.d.ts +3 -3
- package/dist/utilities/requestSubmit.d.ts +2 -2
- package/dist/utilities/scroll.d.ts +10 -10
- package/dist/utilities/turbo.d.ts +1 -1
- package/package.json +16 -10
- package/dist/stimulus-library.js +0 -2
- package/dist/stimulus-library.js.map +0 -1
- package/dist/stimulus-library.modern.js +0 -2
- package/dist/stimulus-library.modern.js.map +0 -1
- package/dist/stimulus-library.module.js +0 -2
- package/dist/stimulus-library.module.js.map +0 -1
- package/src/controllers/ajax/async_block_controller.ts +0 -28
- package/src/controllers/ajax/lazy_block_controller.ts +0 -31
- package/src/controllers/ajax/load_block_controller.ts +0 -59
- package/src/controllers/ajax/poll_block_controller.ts +0 -32
- package/src/controllers/anchor_spy_controller.ts +0 -47
- package/src/controllers/back_link_controller.ts +0 -49
- package/src/controllers/clipboard_controller.ts +0 -47
- package/src/controllers/confirm_controller.ts +0 -50
- package/src/controllers/confirm_navigation_controller.ts +0 -51
- package/src/controllers/debug_controller.ts +0 -11
- package/src/controllers/disable_with_controller.ts +0 -116
- package/src/controllers/dismissable_controller.ts +0 -12
- package/src/controllers/element_save_controller.ts +0 -93
- package/src/controllers/empty_dom_controller.ts +0 -105
- package/src/controllers/forms/auto_submit_form_controller.ts +0 -59
- package/src/controllers/forms/autosize_controller.ts +0 -41
- package/src/controllers/forms/char_count_controller.ts +0 -91
- package/src/controllers/forms/checkbox_select_all_controller.ts +0 -57
- package/src/controllers/forms/detect_dirty_controller.ts +0 -116
- package/src/controllers/forms/detect_dirty_form_controller.ts +0 -127
- package/src/controllers/forms/disable_inputs_controller.ts +0 -44
- package/src/controllers/forms/enable_inputs_controller.ts +0 -44
- package/src/controllers/forms/form_rc_controller.ts +0 -20
- package/src/controllers/forms/form_save_controller.ts +0 -141
- package/src/controllers/forms/limited_selection_checkboxes_controller.ts +0 -44
- package/src/controllers/forms/navigate_form_errors_controller.ts +0 -144
- package/src/controllers/forms/nested_form_controller.ts +0 -68
- package/src/controllers/forms/password_confirm_controller.ts +0 -68
- package/src/controllers/forms/password_peek_controller.ts +0 -27
- package/src/controllers/forms/remote_form_controller.ts +0 -34
- package/src/controllers/forms/sync_inputs_controller.ts +0 -89
- package/src/controllers/forms/value_warn_controller.ts +0 -107
- package/src/controllers/forms/word_count_controller.ts +0 -86
- package/src/controllers/media/fallback_image_controller.ts +0 -108
- package/src/controllers/media/lightbox_image_controller.ts +0 -89
- package/src/controllers/media/media_player_controller.ts +0 -37
- package/src/controllers/prefetch_controller.ts +0 -99
- package/src/controllers/responsive_iframe_controller.ts +0 -75
- package/src/controllers/scroll/scroll_container_controller.ts +0 -73
- package/src/controllers/scroll/scroll_into_focus_controller.ts +0 -34
- package/src/controllers/scroll/scroll_to_bottom_controller.ts +0 -35
- package/src/controllers/scroll/scroll_to_controller.ts +0 -38
- package/src/controllers/scroll/scroll_to_top_controller.ts +0 -35
- package/src/controllers/self_destruct_controller.ts +0 -23
- package/src/controllers/sticky_controller.ts +0 -84
- package/src/controllers/tables/table_sort_controller.ts +0 -105
- package/src/controllers/tables/table_truncate_controller.ts +0 -106
- package/src/controllers/teleport_controller.ts +0 -64
- package/src/controllers/temporary_state_controller.ts +0 -82
- package/src/controllers/toggle_class_controller.ts +0 -149
- package/src/controllers/turbo_frame_rc_controller.ts +0 -77
- package/src/controllers/turbo_frame_refresh_controller.ts +0 -51
- package/src/controllers/utility/intersection_controller.ts +0 -51
- package/src/controllers/utility/interval_controller.ts +0 -34
- package/src/controllers/utility/presence_controller.ts +0 -13
- package/src/controllers/utility/timeout_controller.ts +0 -30
- package/src/controllers/utility/user_focus_controller.ts +0 -40
- package/src/controllers/visual/clock_controller.ts +0 -75
- package/src/controllers/visual/countdown_controller.ts +0 -198
- package/src/controllers/visual/duration_controller.ts +0 -106
- package/src/controllers/visual/tabs_controller.ts +0 -162
- package/src/controllers/visual/time_distance_controller.ts +0 -66
- package/src/controllers/visual/tree_view_controller.ts +0 -154
- package/src/index.ts +0 -71
- package/src/utilities/base_controller.ts +0 -143
- package/src/utilities/elements.ts +0 -47
- package/src/utilities/ephemeral_controller.ts +0 -45
- package/src/utilities/event_bus.ts +0 -3
- package/src/utilities/requestSubmit.ts +0 -23
- package/src/utilities/scroll.ts +0 -101
- package/src/utilities/turbo.ts +0 -3
- package/src/utilities/types.d.ts +0 -4
- package/tsconfig.json +0 -27
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import {BaseController} from '../../utilities/base_controller';
|
|
2
|
-
import {requestReset, requestSubmit} from "../../utilities/requestSubmit";
|
|
3
|
-
|
|
4
|
-
export class FormRcController extends BaseController {
|
|
5
|
-
|
|
6
|
-
static targets = ["form"];
|
|
7
|
-
|
|
8
|
-
declare readonly formTarget: HTMLFormElement;
|
|
9
|
-
|
|
10
|
-
submit(event?: Event) {
|
|
11
|
-
event?.preventDefault();
|
|
12
|
-
requestSubmit(this.formTarget);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
reset(event?: Event) {
|
|
16
|
-
event?.preventDefault();
|
|
17
|
-
requestReset(this.formTarget)
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
}
|
|
@@ -1,141 +0,0 @@
|
|
|
1
|
-
import {BaseController} from '../../utilities/base_controller';
|
|
2
|
-
import {isHTMLFormElement, isHTMLInputElement} from "../../utilities/elements";
|
|
3
|
-
|
|
4
|
-
interface FormSavePayload {
|
|
5
|
-
[idx: string]: {
|
|
6
|
-
[idx: string]: string | boolean
|
|
7
|
-
}
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class FormSaveController extends BaseController {
|
|
11
|
-
|
|
12
|
-
static values = {
|
|
13
|
-
id: String,
|
|
14
|
-
restoreOnLoad: Boolean,
|
|
15
|
-
clearOnSubmit: Boolean,
|
|
16
|
-
};
|
|
17
|
-
|
|
18
|
-
declare readonly idValue: string;
|
|
19
|
-
declare readonly hasIdValue: boolean;
|
|
20
|
-
declare readonly restoreOnLoadValue: boolean;
|
|
21
|
-
declare readonly hasRestoreOnLoadValue: boolean;
|
|
22
|
-
declare readonly clearOnSubmitValue: boolean;
|
|
23
|
-
declare readonly hasClearOnSubmitValue: boolean;
|
|
24
|
-
|
|
25
|
-
get _formID() {
|
|
26
|
-
if (this.hasIdValue) {
|
|
27
|
-
return this.idValue;
|
|
28
|
-
}
|
|
29
|
-
let elementID = (this.el as HTMLFormElement).id;
|
|
30
|
-
|
|
31
|
-
if (elementID !== "") {
|
|
32
|
-
return elementID;
|
|
33
|
-
} else {
|
|
34
|
-
throw new Error(`No ID value to uniquely identify this form. Please either specify data-${this.identifier}-id-value or give this form an 'id' attribute. `);
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
get _formIdentifier() {
|
|
39
|
-
const url = location.href;
|
|
40
|
-
return `${url} ${this._formID}`;
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
get _formElements() {
|
|
44
|
-
return (this.el as HTMLFormElement).elements;
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
get _formData(): FormSavePayload {
|
|
48
|
-
let data: FormSavePayload = {[this._formIdentifier]: {}};
|
|
49
|
-
for (const element of this._formElements) {
|
|
50
|
-
let el = element as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
51
|
-
if (el.name.length > 0) {
|
|
52
|
-
if (isHTMLInputElement(el) && el.type == "checkbox") {
|
|
53
|
-
data[this._formIdentifier][el.name] = el.checked;
|
|
54
|
-
} else if (isHTMLInputElement(el) && el.type == "radio") {
|
|
55
|
-
if (el.checked) {
|
|
56
|
-
data[this._formIdentifier][el.name] = el.value;
|
|
57
|
-
}
|
|
58
|
-
} else {
|
|
59
|
-
data[this._formIdentifier][el.name] = el.value;
|
|
60
|
-
}
|
|
61
|
-
}
|
|
62
|
-
}
|
|
63
|
-
return data;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
get _restoreOnLoad() {
|
|
67
|
-
return this.hasRestoreOnLoadValue ? this.restoreOnLoadValue : true;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
get _clearOnSubmit() {
|
|
71
|
-
return this.hasClearOnSubmitValue ? this.clearOnSubmitValue : true;
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
initialize() {
|
|
75
|
-
this._clear = this._clear.bind(this);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
connect() {
|
|
79
|
-
requestAnimationFrame(() => {
|
|
80
|
-
let element = this.el;
|
|
81
|
-
if (!isHTMLFormElement(element)) {
|
|
82
|
-
throw new Error('Expected controller to be mounted on a form element.');
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
if (this._restoreOnLoad) {
|
|
86
|
-
this.restore();
|
|
87
|
-
}
|
|
88
|
-
if (this._clearOnSubmit) {
|
|
89
|
-
this.el.addEventListener('submit', this._clear);
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
disconnect() {
|
|
95
|
-
if (this._clearOnSubmit) {
|
|
96
|
-
this.el.removeEventListener('submit', this._clear);
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
_clear() {
|
|
101
|
-
localStorage.removeItem(this._formIdentifier);
|
|
102
|
-
this.dispatch(this.el, `form-save:cleared`);
|
|
103
|
-
}
|
|
104
|
-
|
|
105
|
-
clear(event?: Event) {
|
|
106
|
-
event?.preventDefault();
|
|
107
|
-
this._clear();
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
save(event: Event) {
|
|
111
|
-
event.preventDefault();
|
|
112
|
-
let data = this._formData;
|
|
113
|
-
localStorage.setItem(this._formIdentifier, JSON.stringify(data[this._formIdentifier]));
|
|
114
|
-
this.dispatch(this.el, `form-save:save:success`);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
restore(event?: Event) {
|
|
118
|
-
event?.preventDefault();
|
|
119
|
-
if (localStorage.getItem(this._formIdentifier)) {
|
|
120
|
-
const savedData = JSON.parse(localStorage.getItem(this._formIdentifier)!); // get and parse the saved data from localStorage
|
|
121
|
-
for (const element of this._formElements) {
|
|
122
|
-
let el = element as HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
123
|
-
if (el.name in savedData) {
|
|
124
|
-
if (isHTMLInputElement(el) && el.type == "checkbox") {
|
|
125
|
-
el.checked = savedData[el.name];
|
|
126
|
-
} else if (isHTMLInputElement(el) && el.type == "radio") {
|
|
127
|
-
if (el.value == savedData[el.name]) {
|
|
128
|
-
el.checked = true;
|
|
129
|
-
}
|
|
130
|
-
} else {
|
|
131
|
-
el.value = savedData[el.name];
|
|
132
|
-
}
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
this.dispatch(this.el, `form-save:restore:success`);
|
|
136
|
-
} else {
|
|
137
|
-
this.dispatch(this.el, `form-save:restore:empty`);
|
|
138
|
-
}
|
|
139
|
-
}
|
|
140
|
-
|
|
141
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
|
|
3
|
-
export class LimitedSelectionCheckboxesController extends BaseController {
|
|
4
|
-
|
|
5
|
-
static targets = ["input", "error"];
|
|
6
|
-
static values = {max: Number, message: String};
|
|
7
|
-
|
|
8
|
-
declare readonly hasErrorTarget: boolean;
|
|
9
|
-
declare readonly errorTarget: HTMLElement;
|
|
10
|
-
declare readonly inputTargets: HTMLInputElement[];
|
|
11
|
-
declare readonly maxValue: number;
|
|
12
|
-
declare readonly messageValue: string;
|
|
13
|
-
|
|
14
|
-
initialize() {
|
|
15
|
-
this.handleInputs = this.handleInputs.bind(this);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
connect() {
|
|
19
|
-
this.inputTargets.forEach((el) => el.addEventListener("change", this.handleInputs));
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
disconnect() {
|
|
23
|
-
this.inputTargets.forEach((el) => el.removeEventListener("change", this.handleInputs));
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
handleInputs(event: Event) {
|
|
27
|
-
let tickedInputs = this.inputTargets.reduce((previousValue, el) => el.checked ? previousValue + 1 : previousValue, 0);
|
|
28
|
-
let target = event.target as HTMLInputElement;
|
|
29
|
-
if (tickedInputs > this.maxValue) {
|
|
30
|
-
event.preventDefault();
|
|
31
|
-
target.checked = false;
|
|
32
|
-
this.dispatch(target, "change");
|
|
33
|
-
this.dispatch(target, "limited-selection:too-many");
|
|
34
|
-
if (this.hasErrorTarget) {
|
|
35
|
-
this.errorTarget.innerHTML = this.messageValue;
|
|
36
|
-
}
|
|
37
|
-
} else {
|
|
38
|
-
this.dispatch(target, "limited-selection:selection");
|
|
39
|
-
if (this.hasErrorTarget) {
|
|
40
|
-
this.errorTarget.innerHTML = "";
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
}
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
import {scrollToElement} from "../../utilities/scroll";
|
|
3
|
-
import {clamp} from "lodash-es";
|
|
4
|
-
|
|
5
|
-
export class NavigateFormErrorsController extends BaseController {
|
|
6
|
-
static values = {
|
|
7
|
-
selector: String,
|
|
8
|
-
index: Number,
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
static targets = ["next", "current", "previous"];
|
|
12
|
-
|
|
13
|
-
declare readonly hasNextTarget: boolean;
|
|
14
|
-
declare readonly nextTarget: HTMLElement;
|
|
15
|
-
declare readonly hasPreviousTarget: boolean;
|
|
16
|
-
declare readonly previousTarget: HTMLElement;
|
|
17
|
-
declare readonly hasCurrentTarget: boolean;
|
|
18
|
-
declare readonly currentTarget: HTMLElement;
|
|
19
|
-
|
|
20
|
-
declare selectorValue: string;
|
|
21
|
-
declare readonly hasSelectorValue: boolean;
|
|
22
|
-
declare indexValue: number;
|
|
23
|
-
declare readonly hasIndexValue: boolean;
|
|
24
|
-
|
|
25
|
-
_errors: HTMLElement[] = [];
|
|
26
|
-
_firstClick = false;
|
|
27
|
-
|
|
28
|
-
get _errorCount(): number {
|
|
29
|
-
return this._errors.length;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
get _previousIndex(): number {
|
|
33
|
-
let index = this._index - 1;
|
|
34
|
-
if (index < 0) {
|
|
35
|
-
return 0;
|
|
36
|
-
}
|
|
37
|
-
return index;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
get _nextIndex(): number {
|
|
41
|
-
let index = this._index + 1;
|
|
42
|
-
if (index > this._errors.length - 1) {
|
|
43
|
-
return this._errors.length - 1;
|
|
44
|
-
}
|
|
45
|
-
return index;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
get _index(): number {
|
|
49
|
-
return clamp(this.hasIndexValue ? this.indexValue : 0, 0, this._errors.length);
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
get _selector(): string {
|
|
53
|
-
if (this.hasSelectorValue) {
|
|
54
|
-
return this.selectorValue;
|
|
55
|
-
} else {
|
|
56
|
-
throw new Error("Expected `selectorValue` to be present");
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
get _currentError(): HTMLElement {
|
|
61
|
-
return this._errors[this._index];
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
connect() {
|
|
65
|
-
requestAnimationFrame(() => {
|
|
66
|
-
this._firstClick = true;
|
|
67
|
-
this._toggleButtons();
|
|
68
|
-
this._toggleVisibility();
|
|
69
|
-
},
|
|
70
|
-
);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
async current(event?: Event) {
|
|
74
|
-
event?.preventDefault();
|
|
75
|
-
if (this._firstClick) {
|
|
76
|
-
this._firstClick = false;
|
|
77
|
-
this._toggleButtons();
|
|
78
|
-
}
|
|
79
|
-
await scrollToElement(this._currentError, {behavior: "smooth", block: "center", inline: "center"});
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
async next(event?: Event) {
|
|
83
|
-
event?.preventDefault();
|
|
84
|
-
if (this._firstClick) {
|
|
85
|
-
this._firstClick = false;
|
|
86
|
-
this._toggleButtons();
|
|
87
|
-
} else {
|
|
88
|
-
this.indexValue = this._nextIndex;
|
|
89
|
-
}
|
|
90
|
-
await scrollToElement(this._currentError, {behavior: "smooth", block: "center", inline: "center"});
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
async previous(event?: Event) {
|
|
94
|
-
event?.preventDefault();
|
|
95
|
-
if (this._firstClick) {
|
|
96
|
-
this._firstClick = false;
|
|
97
|
-
this._toggleButtons();
|
|
98
|
-
} else {
|
|
99
|
-
this.indexValue = this._previousIndex;
|
|
100
|
-
}
|
|
101
|
-
await scrollToElement(this._currentError, {behavior: "smooth", block: "center", inline: "center"});
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
indexValueChanged() {
|
|
105
|
-
this._toggleButtons();
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
selectorValueChanged() {
|
|
109
|
-
this._errors = Array.from(document.querySelectorAll(this._selector));
|
|
110
|
-
this.indexValue = 0;
|
|
111
|
-
this._toggleButtons();
|
|
112
|
-
this._toggleVisibility();
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
private _toggleVisibility() {
|
|
116
|
-
if (this._errorCount === 0) {
|
|
117
|
-
this.el.style.display = "none";
|
|
118
|
-
} else {
|
|
119
|
-
this.el.style.display = "";
|
|
120
|
-
}
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
private _toggleButtons() {
|
|
124
|
-
if (this.hasNextTarget) {
|
|
125
|
-
// If there is no "Current Error" button, then enable the next error button when there is only 1 error.
|
|
126
|
-
if (!this.hasCurrentTarget && this._firstClick && this.indexValue == this._errorCount - 1) {
|
|
127
|
-
this.nextTarget.removeAttribute("disabled");
|
|
128
|
-
return;
|
|
129
|
-
} else if (this.indexValue >= this._errorCount - 1) {
|
|
130
|
-
this.nextTarget.setAttribute("disabled", "true");
|
|
131
|
-
} else {
|
|
132
|
-
this.nextTarget.removeAttribute("disabled");
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
if (this.hasPreviousTarget) {
|
|
136
|
-
if (this.indexValue <= 0) {
|
|
137
|
-
this.previousTarget.setAttribute("disabled", "true");
|
|
138
|
-
} else {
|
|
139
|
-
this.previousTarget.removeAttribute("disabled");
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
|
|
3
|
-
export class NestedFormController extends BaseController {
|
|
4
|
-
static targets = ['target', 'template'];
|
|
5
|
-
static values = {
|
|
6
|
-
insertMode: String,
|
|
7
|
-
wrapperClass: String,
|
|
8
|
-
};
|
|
9
|
-
|
|
10
|
-
declare readonly targetTarget: HTMLElement;
|
|
11
|
-
declare readonly templateTarget: HTMLTemplateElement | HTMLScriptElement;
|
|
12
|
-
|
|
13
|
-
declare readonly wrapperClassValue: string;
|
|
14
|
-
declare readonly hasWrapperSelectorValue: boolean;
|
|
15
|
-
declare readonly insertModeValue: InsertPosition;
|
|
16
|
-
declare readonly hasInsertModeValue: boolean;
|
|
17
|
-
|
|
18
|
-
get _wrapperClass() {
|
|
19
|
-
return this.hasWrapperSelectorValue ? this.wrapperClassValue : 'nested-fields';
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
get _insertMode(): InsertPosition {
|
|
23
|
-
return this.hasInsertModeValue ? this.insertModeValue : 'beforeend';
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
connect() {
|
|
27
|
-
this._checkStructure();
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
add(event?: Event) {
|
|
31
|
-
event?.preventDefault();
|
|
32
|
-
|
|
33
|
-
const content = this.templateTarget.innerHTML.replace(/NEW_RECORD/g, this._generateID());
|
|
34
|
-
this.targetTarget.insertAdjacentHTML(this._insertMode, content);
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
remove(event: Event) {
|
|
38
|
-
event.preventDefault();
|
|
39
|
-
const wrapper: HTMLElement | null = (event.target as HTMLElement).closest(`.${this._wrapperClass}`);
|
|
40
|
-
if (wrapper == null) {
|
|
41
|
-
throw new Error(`#remove was clicked from outside of a child record. Could not find an ancestor with class .${this._wrapperClass}`);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (wrapper.dataset.newRecord === 'true') {
|
|
45
|
-
wrapper.remove();
|
|
46
|
-
} else {
|
|
47
|
-
wrapper.style.display = 'none';
|
|
48
|
-
let destroyInput = wrapper.querySelector("input[name*='_destroy']") as HTMLInputElement | null;
|
|
49
|
-
if (destroyInput == null) {
|
|
50
|
-
throw new Error(`Could not find a hidden input with name '_destroy'. NestedForm cannot remove an already persisted record without it.`);
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
destroyInput.value = "1";
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
private _generateID(): string {
|
|
58
|
-
return new Date().getTime().toString() + Math.random().toString().slice(2);
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
private _checkStructure() {
|
|
62
|
-
let template = this.templateTarget.innerHTML;
|
|
63
|
-
|
|
64
|
-
if (template.indexOf('NEW_RECORD')) {
|
|
65
|
-
throw new Error("Could not find 'NEW_RECORD' in the provided template. Please make sure you've passed `child_index: 'NEW_RECORD'` to `fields_for`");
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
|
|
3
|
-
export class PasswordConfirmController extends BaseController {
|
|
4
|
-
|
|
5
|
-
static targets = ["password"];
|
|
6
|
-
static classes = ["error"];
|
|
7
|
-
|
|
8
|
-
declare readonly passwordTargets: HTMLInputElement[];
|
|
9
|
-
|
|
10
|
-
declare readonly errorClass: string;
|
|
11
|
-
declare readonly hasErrorClass: boolean;
|
|
12
|
-
|
|
13
|
-
get _errorClasses(): string[] {
|
|
14
|
-
return this.errorClass.split(' ');
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
get _defaultErrorClasses(): string[] {
|
|
18
|
-
return [];
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
initialize() {
|
|
22
|
-
this._checkPasswordsMatch = this._checkPasswordsMatch.bind(this);
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
connect() {
|
|
26
|
-
this.passwordTargets.forEach((el) => el.addEventListener("change", this._checkPasswordsMatch));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
disconnect() {
|
|
30
|
-
this.passwordTargets.forEach((el) => el.removeEventListener("change", this._checkPasswordsMatch));
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
private _addErrorClasses(el: HTMLElement = this.el) {
|
|
34
|
-
if (this.hasErrorClass) {
|
|
35
|
-
el.classList.add(...this._errorClasses);
|
|
36
|
-
} else {
|
|
37
|
-
el.classList.add(...this._defaultErrorClasses);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
private _removeErrorClasses(el: HTMLElement = this.el) {
|
|
42
|
-
if (this.hasErrorClass) {
|
|
43
|
-
el.classList.remove(...this._errorClasses);
|
|
44
|
-
} else {
|
|
45
|
-
el.classList.remove(...this._defaultErrorClasses);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
private _allPasswordsMatch(): boolean {
|
|
50
|
-
let values = new Set(this.passwordTargets.map(el => el.value)); // Create a unique set of the password values
|
|
51
|
-
return values.has("") || values.size == 1; // If any of the passwords are still blank, or there is only one distinct password value (i.e. they all are the same)
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
private _checkPasswordsMatch() {
|
|
55
|
-
let element = this.el;
|
|
56
|
-
if (this._allPasswordsMatch()) {
|
|
57
|
-
this.dispatch(element, "password-confirm:match");
|
|
58
|
-
if (this.hasErrorClass) {
|
|
59
|
-
this.passwordTargets.forEach(el => this._removeErrorClasses(el));
|
|
60
|
-
}
|
|
61
|
-
} else {
|
|
62
|
-
this.dispatch(element, "password-confirm:no-match");
|
|
63
|
-
if (this.hasErrorClass) {
|
|
64
|
-
this.passwordTargets.forEach(el => this._addErrorClasses(el));
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
}
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
|
|
3
|
-
export class PasswordPeekController extends BaseController {
|
|
4
|
-
|
|
5
|
-
static targets = ["password"];
|
|
6
|
-
|
|
7
|
-
declare readonly passwordTarget: HTMLInputElement;
|
|
8
|
-
|
|
9
|
-
peak(event?: Event) {
|
|
10
|
-
event?.preventDefault();
|
|
11
|
-
this.passwordTarget.type = "text";
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
hide(event?: Event) {
|
|
15
|
-
event?.preventDefault();
|
|
16
|
-
this.passwordTarget.type = "password";
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
toggle(event?: Event) {
|
|
20
|
-
event?.preventDefault();
|
|
21
|
-
if (this.passwordTarget.type === "password") {
|
|
22
|
-
this.peak();
|
|
23
|
-
} else {
|
|
24
|
-
this.hide();
|
|
25
|
-
}
|
|
26
|
-
}
|
|
27
|
-
}
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
|
|
3
|
-
export class RemoteFormController extends BaseController {
|
|
4
|
-
static targets = [];
|
|
5
|
-
|
|
6
|
-
static values = {selector: String};
|
|
7
|
-
|
|
8
|
-
declare readonly hasSelectorValue: boolean;
|
|
9
|
-
declare readonly selectorValue: string;
|
|
10
|
-
|
|
11
|
-
get _selector(): string {
|
|
12
|
-
return this.hasSelectorValue ? this.selectorValue : `[data-controller~="${this.identifier}"]`;
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
replace(event: { detail: [Element, any, XMLHttpRequest] }) {
|
|
16
|
-
const [data, status, xhr] = event.detail;
|
|
17
|
-
if (data instanceof Node) {
|
|
18
|
-
let newElement: HTMLElement | null = data.querySelector(this._selector);
|
|
19
|
-
|
|
20
|
-
if (newElement == null) {
|
|
21
|
-
throw new Error(`expected new form DOM with [data-controller="${this.identifier}"] to be present in returned payload`);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
let parentNode = this.el.parentNode;
|
|
25
|
-
if (parentNode == null) {
|
|
26
|
-
throw new Error('expected form to have a DOM parent, could not execute replaceChild');
|
|
27
|
-
}
|
|
28
|
-
parentNode.replaceChild(newElement, this.el);
|
|
29
|
-
this.dispatch(newElement, 'remote-form:replace');
|
|
30
|
-
} else {
|
|
31
|
-
console.log('Unknown', data);
|
|
32
|
-
}
|
|
33
|
-
}
|
|
34
|
-
}
|
|
@@ -1,89 +0,0 @@
|
|
|
1
|
-
import {BaseController} from "../../utilities/base_controller";
|
|
2
|
-
import {isHTMLInputElement, isHTMLSelectElement, isHTMLTextAreaElement, isTypeOfFormInputElement} from "../../utilities/elements";
|
|
3
|
-
import {EventBus} from "../../utilities/event_bus";
|
|
4
|
-
|
|
5
|
-
export interface SyncValuePayload {
|
|
6
|
-
value: string | boolean;
|
|
7
|
-
dispatcher: HTMLElement;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
export class SyncInputsController extends BaseController {
|
|
11
|
-
static values = {
|
|
12
|
-
key: String,
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
declare readonly keyValue: string;
|
|
16
|
-
declare readonly hasKeyValue: boolean;
|
|
17
|
-
|
|
18
|
-
get _eventName(): string {
|
|
19
|
-
return `sync:${this._key}`;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
get _key(): string {
|
|
23
|
-
if (this.hasKeyValue) {
|
|
24
|
-
return this.keyValue;
|
|
25
|
-
}
|
|
26
|
-
throw new Error("Expected `keyValue` to be present");
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
get _value(): string | boolean {
|
|
30
|
-
let el = this.el as | HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
|
|
31
|
-
if (isHTMLInputElement(el) && el.type === "checkbox") {
|
|
32
|
-
return el.checked;
|
|
33
|
-
} else if (isHTMLInputElement(el) && el.type === "radio") {
|
|
34
|
-
return el.checked ? el.value : "";
|
|
35
|
-
} else {
|
|
36
|
-
return el.value;
|
|
37
|
-
}
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
set _value(val: string | boolean) {
|
|
41
|
-
let el = this.el;
|
|
42
|
-
if (isHTMLInputElement(el) && el.type === "checkbox") {
|
|
43
|
-
el.checked = val.toString() === "true";
|
|
44
|
-
} else if (isHTMLInputElement(el) && el.type === "radio") {
|
|
45
|
-
el.checked = el.value === val;
|
|
46
|
-
} else if (isHTMLInputElement(el) || isHTMLTextAreaElement(el) || isHTMLSelectElement(el)) {
|
|
47
|
-
el.value = val.toString();
|
|
48
|
-
} else {
|
|
49
|
-
el.innerHTML = val.toString();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
initialize() {
|
|
54
|
-
this._read = this._read.bind(this);
|
|
55
|
-
this._emit = this._emit.bind(this);
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
connect() {
|
|
59
|
-
EventBus.on(this._eventName, this._read);
|
|
60
|
-
|
|
61
|
-
requestAnimationFrame(() => {
|
|
62
|
-
if (isTypeOfFormInputElement(this.el)) {
|
|
63
|
-
this._emit();
|
|
64
|
-
this.el.addEventListener("input", this._emit);
|
|
65
|
-
}
|
|
66
|
-
});
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
disconnect() {
|
|
70
|
-
EventBus.off(this._eventName, this._read);
|
|
71
|
-
if (isTypeOfFormInputElement(this.el)) {
|
|
72
|
-
this.el.removeEventListener("input", this._emit);
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
_emit() {
|
|
77
|
-
EventBus.emit(this._eventName, {value: this._value, dispatcher: this.el} as SyncValuePayload);
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
_read(payload?: SyncValuePayload) {
|
|
81
|
-
if (payload === undefined) {
|
|
82
|
-
throw new Error("No payload received");
|
|
83
|
-
}
|
|
84
|
-
let {dispatcher, value} = payload;
|
|
85
|
-
if (dispatcher !== this.el) {
|
|
86
|
-
this._value = value;
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
}
|