flexi_admin 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +42 -0
- data/Rakefile +7 -0
- data/lib/flexi_admin/components/actions/checkbox_component.html.slim +8 -0
- data/lib/flexi_admin/components/actions/checkbox_component.rb +13 -0
- data/lib/flexi_admin/components/actions/select_component.html.slim +11 -0
- data/lib/flexi_admin/components/actions/select_component.rb +17 -0
- data/lib/flexi_admin/components/base_component.rb +19 -0
- data/lib/flexi_admin/components/form/field_component.rb +11 -0
- data/lib/flexi_admin/components/form/label_component.html.slim +2 -0
- data/lib/flexi_admin/components/form/label_component.rb +13 -0
- data/lib/flexi_admin/components/form/rows_component.rb +9 -0
- data/lib/flexi_admin/components/form/text_input_component.html.slim +5 -0
- data/lib/flexi_admin/components/form/text_input_component.rb +17 -0
- data/lib/flexi_admin/components/helpers/action_button_helper.rb +28 -0
- data/lib/flexi_admin/components/helpers/action_helper.rb +12 -0
- data/lib/flexi_admin/components/helpers/icon_helper.rb +11 -0
- data/lib/flexi_admin/components/helpers/link_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/resource_helper.rb +71 -0
- data/lib/flexi_admin/components/helpers/selectable.rb +11 -0
- data/lib/flexi_admin/components/helpers/url_helper.rb +8 -0
- data/lib/flexi_admin/components/helpers/value_formatter.rb +32 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.html.slim +2 -0
- data/lib/flexi_admin/components/nav/floating_toc_component.rb +6 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.html.slim +30 -0
- data/lib/flexi_admin/components/resource/autocomplete_component.rb +83 -0
- data/lib/flexi_admin/components/resource/button_select_component.html.slim +13 -0
- data/lib/flexi_admin/components/resource/button_select_component.rb +19 -0
- data/lib/flexi_admin/components/resource/form_component.rb +18 -0
- data/lib/flexi_admin/components/resource/form_element_component.html.slim +3 -0
- data/lib/flexi_admin/components/resource/form_element_component.rb +31 -0
- data/lib/flexi_admin/components/resource/form_mixin.rb +287 -0
- data/lib/flexi_admin/components/resource/link_action_component.html.slim +8 -0
- data/lib/flexi_admin/components/resource/link_action_component.rb +16 -0
- data/lib/flexi_admin/components/resource/show_page_component.rb +21 -0
- data/lib/flexi_admin/components/resource/view_component.html.slim +26 -0
- data/lib/flexi_admin/components/resource/view_component.rb +22 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.html.slim +7 -0
- data/lib/flexi_admin/components/resources/bulk_action/button_component.rb +29 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.html.slim +32 -0
- data/lib/flexi_admin/components/resources/bulk_action/modal_component.rb +54 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.html.slim +18 -0
- data/lib/flexi_admin/components/resources/grid_view/card_component.rb +65 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.html.slim +10 -0
- data/lib/flexi_admin/components/resources/grid_view/grid_component.rb +16 -0
- data/lib/flexi_admin/components/resources/grid_view_component.rb +89 -0
- data/lib/flexi_admin/components/resources/index_page_component.html.slim +13 -0
- data/lib/flexi_admin/components/resources/index_page_component.rb +19 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.html.slim +2 -0
- data/lib/flexi_admin/components/resources/list_view/cell_component.rb +26 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.html.slim +17 -0
- data/lib/flexi_admin/components/resources/list_view/table_component.rb +21 -0
- data/lib/flexi_admin/components/resources/list_view_component.rb +80 -0
- data/lib/flexi_admin/components/resources/pagination_component.html.slim +42 -0
- data/lib/flexi_admin/components/resources/pagination_component.rb +64 -0
- data/lib/flexi_admin/components/resources/resources_component.rb +34 -0
- data/lib/flexi_admin/components/resources/switch_view_component.html.slim +16 -0
- data/lib/flexi_admin/components/resources/switch_view_component.rb +45 -0
- data/lib/flexi_admin/components/resources/view_component.html.slim +12 -0
- data/lib/flexi_admin/components/resources/view_component.rb +15 -0
- data/lib/flexi_admin/components/shared/alert_component.html.slim +2 -0
- data/lib/flexi_admin/components/shared/alert_component.rb +11 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.html.slim +15 -0
- data/lib/flexi_admin/components/shared/autocomplete/results_component.rb +50 -0
- data/lib/flexi_admin/components/shared/autocomplete.rb +6 -0
- data/lib/flexi_admin/components/shared/datalist_component.html.slim +24 -0
- data/lib/flexi_admin/components/shared/datalist_component.rb +20 -0
- data/lib/flexi_admin/components/shared/link_component.html.slim +3 -0
- data/lib/flexi_admin/components/shared/link_component.rb +15 -0
- data/lib/flexi_admin/components/shared/medium_component.html.slim +7 -0
- data/lib/flexi_admin/components/shared/medium_component.rb +51 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.html.slim +9 -0
- data/lib/flexi_admin/components/shared/table/header_item_component.rb +78 -0
- data/lib/flexi_admin/components/shared/trix_component.html.slim +22 -0
- data/lib/flexi_admin/components/shared/trix_component.rb +21 -0
- data/lib/flexi_admin/components.rb +87 -0
- data/lib/flexi_admin/config.rb +24 -0
- data/lib/flexi_admin/controllers/modals_controller.rb +13 -0
- data/lib/flexi_admin/controllers/resources_controller.rb +240 -0
- data/lib/flexi_admin/controllers.rb +9 -0
- data/lib/flexi_admin/engine.rb +34 -0
- data/lib/flexi_admin/helpers/application_helper.rb +4 -0
- data/lib/flexi_admin/helpers.rb +8 -0
- data/lib/flexi_admin/javascript/controllers/application.js +9 -0
- data/lib/flexi_admin/javascript/controllers/autocomplete_controller.js +142 -0
- data/lib/flexi_admin/javascript/controllers/bulk_action_controller.js +158 -0
- data/lib/flexi_admin/javascript/controllers/button_select_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/datalist_controller.js +104 -0
- data/lib/flexi_admin/javascript/controllers/floating_toc_controller.js +39 -0
- data/lib/flexi_admin/javascript/controllers/form_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/form_validation_controller.js +86 -0
- data/lib/flexi_admin/javascript/controllers/index.js +44 -0
- data/lib/flexi_admin/javascript/controllers/pagination_controller.js +13 -0
- data/lib/flexi_admin/javascript/controllers/sorting_controller.js +17 -0
- data/lib/flexi_admin/javascript/controllers/switch_view_controller.js +15 -0
- data/lib/flexi_admin/javascript/controllers/toast_controller.js +18 -0
- data/lib/flexi_admin/javascript/controllers/trix_controller.js +32 -0
- data/lib/flexi_admin/javascript/controllers/uploads_controller.js +164 -0
- data/lib/flexi_admin/javascript/flexi_admin.js +4 -0
- data/lib/flexi_admin/javascript/utils.js +26 -0
- data/lib/flexi_admin/models/concerns/application_resource.rb +25 -0
- data/lib/flexi_admin/models/concerns/parentable.rb +17 -0
- data/lib/flexi_admin/models/context_params.rb +127 -0
- data/lib/flexi_admin/models/resources/context.rb +59 -0
- data/lib/flexi_admin/models/struct.rb +29 -0
- data/lib/flexi_admin/models/toast.rb +23 -0
- data/lib/flexi_admin/models.rb +20 -0
- data/lib/flexi_admin/prompts/codegen-system-prompt.md +50 -0
- data/lib/flexi_admin/railtie.rb +78 -0
- data/lib/flexi_admin/routes.rb +15 -0
- data/lib/flexi_admin/services/code_gen/code_export.rb +22 -0
- data/lib/flexi_admin/services/code_gen/gemini.rb +104 -0
- data/lib/flexi_admin/services/code_gen/gpt.rb +68 -0
- data/lib/flexi_admin/services/code_gen/runner.rb +210 -0
- data/lib/flexi_admin/services/code_gen.rb +14 -0
- data/lib/flexi_admin/services/create_resource.rb +32 -0
- data/lib/flexi_admin/services/update_resource.rb +30 -0
- data/lib/flexi_admin/services.rb +10 -0
- data/lib/flexi_admin/version.rb +10 -0
- data/lib/flexi_admin/views/shared/_redirect.slim +2 -0
- data/lib/flexi_admin/views/shared/_reload.slim +2 -0
- data/lib/flexi_admin/views/shared/_toasts.slim +15 -0
- data/lib/flexi_admin/views/shared/not_authorized.slim +11 -0
- data/lib/flexi_admin.rb +58 -0
- data/lib/tasks/flexi_admin.rake +49 -0
- data/lib/tasks/semantic.rake +57 -0
- metadata +333 -0
@@ -0,0 +1,142 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { markValid } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="autocomplete"
|
5
|
+
export default class extends Controller {
|
6
|
+
static targets = [
|
7
|
+
"input",
|
8
|
+
"list",
|
9
|
+
"clearIcon",
|
10
|
+
"loadingIcon",
|
11
|
+
"resourceId",
|
12
|
+
"isDisabled",
|
13
|
+
];
|
14
|
+
|
15
|
+
connect() {
|
16
|
+
this._disableInput(this.inputTarget.dataset.autocompleteIsDisabled);
|
17
|
+
this.timeout = null;
|
18
|
+
this.blurTimeout = null;
|
19
|
+
if (this.inputTarget.value && !this.inputTarget.disabled) {
|
20
|
+
this._clearIcon("show");
|
21
|
+
} else {
|
22
|
+
this._clearIcon("hide");
|
23
|
+
}
|
24
|
+
this._loadingIcon("hide");
|
25
|
+
}
|
26
|
+
|
27
|
+
disconnect() {
|
28
|
+
clearTimeout(this.timeout);
|
29
|
+
clearTimeout(this.blurTimeout);
|
30
|
+
this.hideResults();
|
31
|
+
}
|
32
|
+
|
33
|
+
keyup(event) {
|
34
|
+
if (this.inputTarget.value.length > 0) {
|
35
|
+
this.listTarget.classList.remove("d-none");
|
36
|
+
this._clearIcon("show");
|
37
|
+
markValid(event);
|
38
|
+
} else {
|
39
|
+
this.hideResults();
|
40
|
+
this._clearIcon("hide");
|
41
|
+
return;
|
42
|
+
}
|
43
|
+
|
44
|
+
clearTimeout(this.timeout);
|
45
|
+
|
46
|
+
this.timeout = setTimeout(() => {
|
47
|
+
this._search(this.inputTarget.value);
|
48
|
+
}, 200);
|
49
|
+
}
|
50
|
+
|
51
|
+
hideResults() {
|
52
|
+
this.listTarget.classList.add("d-none");
|
53
|
+
}
|
54
|
+
|
55
|
+
onFocusOut(event) {
|
56
|
+
// Delay hiding results to allow for click events on results
|
57
|
+
this.blurTimeout = setTimeout(() => {
|
58
|
+
this.hideResults();
|
59
|
+
}, 200);
|
60
|
+
}
|
61
|
+
|
62
|
+
preventBlur(event) {
|
63
|
+
// Prevent the blur event when clicking on a result
|
64
|
+
event.preventDefault();
|
65
|
+
clearTimeout(this.blurTimeout);
|
66
|
+
}
|
67
|
+
|
68
|
+
select(event) {
|
69
|
+
this.resourceIdTarget.value =
|
70
|
+
event.currentTarget.dataset.autocompleteResourceIdValue;
|
71
|
+
this.inputTarget.value = event.currentTarget.innerText;
|
72
|
+
this.inputTarget.dispatchEvent(new Event("input"));
|
73
|
+
clearTimeout(this.blurTimeout);
|
74
|
+
this.hideResults();
|
75
|
+
}
|
76
|
+
|
77
|
+
inputValue(event) {
|
78
|
+
this.inputTarget.value = event.currentTarget.innerText;
|
79
|
+
this.inputTarget.dispatchEvent(new Event("input"));
|
80
|
+
this.hideResults();
|
81
|
+
}
|
82
|
+
|
83
|
+
clear() {
|
84
|
+
this.inputTarget.value = "";
|
85
|
+
this.resourceIdTarget.value = "";
|
86
|
+
this.inputTarget.dispatchEvent(new Event("input"));
|
87
|
+
this.hideResults();
|
88
|
+
this._clearIcon("hide");
|
89
|
+
this.inputTarget.focus();
|
90
|
+
}
|
91
|
+
|
92
|
+
_loadingIcon(string) {
|
93
|
+
if (string === "show") {
|
94
|
+
this.loadingIconTarget.classList.remove("d-none");
|
95
|
+
} else {
|
96
|
+
this.loadingIconTarget.classList.add("d-none");
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
_clearIcon(string) {
|
101
|
+
if (string === "show") {
|
102
|
+
this.clearIconTarget.classList.remove("d-none");
|
103
|
+
} else {
|
104
|
+
this.clearIconTarget.classList.add("d-none");
|
105
|
+
}
|
106
|
+
}
|
107
|
+
|
108
|
+
_disableInput(string) {
|
109
|
+
if (string === "true") {
|
110
|
+
this.inputTarget.disabled = true;
|
111
|
+
} else {
|
112
|
+
this.inputTarget.disabled = false;
|
113
|
+
}
|
114
|
+
}
|
115
|
+
|
116
|
+
async _search(string) {
|
117
|
+
const path = this.inputTarget.dataset.autocompleteSearchPath;
|
118
|
+
const url = new URL(path, window.location.origin);
|
119
|
+
url.searchParams.set("q", string);
|
120
|
+
|
121
|
+
try {
|
122
|
+
this.loadingIconTarget.classList.remove("d-none"); // Show loading icon
|
123
|
+
const response = await fetch(url.toString(), {
|
124
|
+
headers: {
|
125
|
+
Accept: "text/html",
|
126
|
+
},
|
127
|
+
});
|
128
|
+
|
129
|
+
if (response.ok) {
|
130
|
+
const html = await response.text();
|
131
|
+
this._clearIcon("show");
|
132
|
+
this.listTarget.innerHTML = html; // Set the results as inner HTML
|
133
|
+
} else {
|
134
|
+
console.error("Error fetching search results:", response.statusText);
|
135
|
+
}
|
136
|
+
} catch (error) {
|
137
|
+
console.error("Network error:", error);
|
138
|
+
} finally {
|
139
|
+
this.loadingIconTarget.classList.add("d-none"); // Hide loading icon
|
140
|
+
}
|
141
|
+
}
|
142
|
+
}
|
@@ -0,0 +1,158 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { fetchTurboContent } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="bulk-action"
|
5
|
+
export default class extends Controller {
|
6
|
+
static values = {
|
7
|
+
scope: String,
|
8
|
+
};
|
9
|
+
|
10
|
+
connect() {
|
11
|
+
this.selectedIds = [];
|
12
|
+
|
13
|
+
document.addEventListener("bulk-action-modal-opened", (event) => {
|
14
|
+
this._modalOpened(event);
|
15
|
+
});
|
16
|
+
}
|
17
|
+
|
18
|
+
disconnect() {
|
19
|
+
document.removeEventListener("bulk-action-modal-opened", this._modalOpened);
|
20
|
+
}
|
21
|
+
|
22
|
+
async requestModal(event) {
|
23
|
+
const url = await event.target.dataset.urlWithId;
|
24
|
+
fetchTurboContent(event, url);
|
25
|
+
}
|
26
|
+
|
27
|
+
submitForm(event) {
|
28
|
+
event.preventDefault();
|
29
|
+
|
30
|
+
const modal = this._withModal();
|
31
|
+
const form = modal.querySelector("form");
|
32
|
+
form.requestSubmit();
|
33
|
+
}
|
34
|
+
|
35
|
+
toggle(event) {
|
36
|
+
const id = event.target.value;
|
37
|
+
|
38
|
+
if (event.target.checked) {
|
39
|
+
// Add ID to the array if the checkbox is checked
|
40
|
+
this.selectedIds.push(id);
|
41
|
+
} else {
|
42
|
+
// Remove ID from the array if the checkbox is unchecked
|
43
|
+
this.selectedIds = this.selectedIds.filter(
|
44
|
+
(selectedId) => selectedId !== id
|
45
|
+
);
|
46
|
+
}
|
47
|
+
|
48
|
+
if (this.selectedIds.length > 0) {
|
49
|
+
this._enableActions();
|
50
|
+
} else {
|
51
|
+
this._disableActions();
|
52
|
+
}
|
53
|
+
|
54
|
+
this._persist();
|
55
|
+
// console.log(`${this.scopeValue} select one`, this.selectedIds.length);
|
56
|
+
}
|
57
|
+
|
58
|
+
toggleAll(event) {
|
59
|
+
if (event.target.checked) {
|
60
|
+
this._selectAll();
|
61
|
+
} else {
|
62
|
+
this._unselectAll();
|
63
|
+
}
|
64
|
+
}
|
65
|
+
|
66
|
+
_modalOpened(event) {
|
67
|
+
if (event.detail.scope !== this.scopeValue) {
|
68
|
+
return;
|
69
|
+
}
|
70
|
+
|
71
|
+
const modal = this._withModal();
|
72
|
+
|
73
|
+
this._populateCountElements(modal);
|
74
|
+
this._populateIds(modal);
|
75
|
+
this._addProcessor(modal, event.detail.modalId);
|
76
|
+
}
|
77
|
+
|
78
|
+
_populateCountElements(modal) {
|
79
|
+
const countElements = modal.querySelectorAll("span.count");
|
80
|
+
countElements.forEach((countElement) => {
|
81
|
+
countElement.textContent = this.selectedIds.length;
|
82
|
+
});
|
83
|
+
}
|
84
|
+
|
85
|
+
_addProcessor(modal, processor) {
|
86
|
+
const form = modal.querySelector("form");
|
87
|
+
const hiddenInput = document.createElement("input");
|
88
|
+
hiddenInput.type = "hidden";
|
89
|
+
hiddenInput.name = "processor";
|
90
|
+
hiddenInput.value = processor;
|
91
|
+
form.appendChild(hiddenInput);
|
92
|
+
}
|
93
|
+
|
94
|
+
_populateIds(modal) {
|
95
|
+
const form = modal.querySelector("form");
|
96
|
+
const hiddenInput = document.createElement("input");
|
97
|
+
hiddenInput.type = "hidden";
|
98
|
+
hiddenInput.name = "ids";
|
99
|
+
hiddenInput.value = JSON.stringify(this.selectedIds);
|
100
|
+
form.appendChild(hiddenInput);
|
101
|
+
}
|
102
|
+
|
103
|
+
_withModal() {
|
104
|
+
return document.querySelector(`#modalx_${this.scopeValue}`);
|
105
|
+
}
|
106
|
+
|
107
|
+
_selectAll() {
|
108
|
+
// find all checkboxes with the name of the actionScope
|
109
|
+
const checkboxes = document.querySelectorAll(
|
110
|
+
`.bulk-action-checkbox > input[name="${this.scopeValue}"]`
|
111
|
+
);
|
112
|
+
|
113
|
+
this.selectedIds = Array.from(checkboxes).map((checkbox) => checkbox.value);
|
114
|
+
|
115
|
+
Array.from(checkboxes).forEach((checkbox) => {
|
116
|
+
checkbox.checked = true;
|
117
|
+
});
|
118
|
+
|
119
|
+
this._persist();
|
120
|
+
this._enableActions();
|
121
|
+
// console.log(`${this.scopeValue} select all`, this.selectedIds.length);
|
122
|
+
}
|
123
|
+
|
124
|
+
_unselectAll() {
|
125
|
+
this.selectedIds = [];
|
126
|
+
const checkboxes = document.querySelectorAll(
|
127
|
+
`.bulk-action-checkbox > input[name="${this.scopeValue}"]`
|
128
|
+
);
|
129
|
+
Array.from(checkboxes).forEach((checkbox) => {
|
130
|
+
checkbox.checked = false;
|
131
|
+
});
|
132
|
+
|
133
|
+
this._persist();
|
134
|
+
this._disableActions();
|
135
|
+
// console.log(`${this.scopeValue} unselect all`, this.selectedIds.length);
|
136
|
+
}
|
137
|
+
|
138
|
+
_persist() {
|
139
|
+
this.element.dataset.ids = JSON.stringify(this.selectedIds);
|
140
|
+
// console.log("persist", this.element.dataset.ids);
|
141
|
+
}
|
142
|
+
|
143
|
+
_enableActions() {
|
144
|
+
document
|
145
|
+
.querySelectorAll(".dropdown-item.bulk-action.selection-dependent")
|
146
|
+
.forEach((item) => {
|
147
|
+
item.classList.remove("disabled");
|
148
|
+
});
|
149
|
+
}
|
150
|
+
|
151
|
+
_disableActions() {
|
152
|
+
document
|
153
|
+
.querySelectorAll(".dropdown-item.bulk-action.selection-dependent")
|
154
|
+
.forEach((item) => {
|
155
|
+
item.classList.add("disabled");
|
156
|
+
});
|
157
|
+
}
|
158
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="button-select"
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = ["button", "input"];
|
6
|
+
static values = { disabled: Boolean };
|
7
|
+
|
8
|
+
connect() {
|
9
|
+
this._updateSelectedButton();
|
10
|
+
}
|
11
|
+
|
12
|
+
select(event) {
|
13
|
+
if (this.disabledValue) {
|
14
|
+
return;
|
15
|
+
}
|
16
|
+
|
17
|
+
event.preventDefault();
|
18
|
+
const selectedValue = event.currentTarget.dataset.value;
|
19
|
+
this.inputTarget.value = selectedValue;
|
20
|
+
this._updateSelectedButton();
|
21
|
+
}
|
22
|
+
|
23
|
+
_updateSelectedButton() {
|
24
|
+
this.buttonTargets.forEach((button) => {
|
25
|
+
button.classList.toggle(
|
26
|
+
"selected",
|
27
|
+
button.dataset.value === this.inputTarget.value
|
28
|
+
);
|
29
|
+
button.classList.toggle("disabled", this.disabledValue);
|
30
|
+
});
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,104 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="autocomplete"
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = ["input", "datalist", "clearIcon", "loadingIcon"];
|
6
|
+
|
7
|
+
static values = {
|
8
|
+
searchPath: String,
|
9
|
+
isDisabled: Boolean,
|
10
|
+
resourceId: String,
|
11
|
+
};
|
12
|
+
|
13
|
+
connect() {
|
14
|
+
this._disableInput(this.isDisabledValue);
|
15
|
+
this.timeout = null;
|
16
|
+
if (this.inputTarget.value && !this.inputTarget.disabled) {
|
17
|
+
this._clearIcon("show");
|
18
|
+
} else {
|
19
|
+
this._clearIcon("hide");
|
20
|
+
}
|
21
|
+
this._loadingIcon("hide");
|
22
|
+
}
|
23
|
+
|
24
|
+
disconnect() {
|
25
|
+
clearTimeout(this.timeout);
|
26
|
+
while (this.datalistTarget.firstChild) {
|
27
|
+
this.datalistTarget.removeChild(this.datalistTarget.firstChild);
|
28
|
+
}
|
29
|
+
}
|
30
|
+
|
31
|
+
keyup() {
|
32
|
+
if (this.inputTarget.value.length > 0) {
|
33
|
+
this._clearIcon("show");
|
34
|
+
} else {
|
35
|
+
this._clearIcon("hide");
|
36
|
+
return;
|
37
|
+
}
|
38
|
+
|
39
|
+
clearTimeout(this.timeout);
|
40
|
+
|
41
|
+
this.timeout = setTimeout(() => {
|
42
|
+
this._search(this.inputTarget.value);
|
43
|
+
}, 200);
|
44
|
+
}
|
45
|
+
|
46
|
+
clear() {
|
47
|
+
this.inputTarget.value = "";
|
48
|
+
this.inputTarget.dispatchEvent(new Event("input"));
|
49
|
+
this._clearIcon("hide");
|
50
|
+
this.inputTarget.focus();
|
51
|
+
}
|
52
|
+
|
53
|
+
_loadingIcon(string) {
|
54
|
+
if (string === "show") {
|
55
|
+
this.loadingIconTarget.classList.remove("d-none");
|
56
|
+
} else {
|
57
|
+
this.loadingIconTarget.classList.add("d-none");
|
58
|
+
}
|
59
|
+
}
|
60
|
+
|
61
|
+
_clearIcon(string) {
|
62
|
+
if (string === "show") {
|
63
|
+
this.clearIconTarget.classList.remove("d-none");
|
64
|
+
} else {
|
65
|
+
this.clearIconTarget.classList.add("d-none");
|
66
|
+
}
|
67
|
+
}
|
68
|
+
|
69
|
+
_disableInput(string) {
|
70
|
+
if (string === "true") {
|
71
|
+
this.inputTarget.disabled = true;
|
72
|
+
} else {
|
73
|
+
this.inputTarget.disabled = false;
|
74
|
+
}
|
75
|
+
}
|
76
|
+
|
77
|
+
async _search(string) {
|
78
|
+
const path = this.searchPathValue;
|
79
|
+
const url = new URL(path, window.location.origin);
|
80
|
+
url.searchParams.set("q", string);
|
81
|
+
|
82
|
+
try {
|
83
|
+
this.loadingIconTarget.classList.remove("d-none"); // Show loading icon
|
84
|
+
const response = await fetch(url.toString(), {
|
85
|
+
headers: {
|
86
|
+
Accept: "text/html",
|
87
|
+
},
|
88
|
+
});
|
89
|
+
|
90
|
+
if (response.ok) {
|
91
|
+
const html = await response.text();
|
92
|
+
this._clearIcon("show");
|
93
|
+
this.datalistTarget.innerHTML = html; // Set the results as inner HTML
|
94
|
+
this.inputTarget.dispatchEvent(new Event("input"));
|
95
|
+
} else {
|
96
|
+
console.error("Error fetching search results:", response.statusText);
|
97
|
+
}
|
98
|
+
} catch (error) {
|
99
|
+
console.error("Network error:", error);
|
100
|
+
} finally {
|
101
|
+
this.loadingIconTarget.classList.add("d-none"); // Hide loading icon
|
102
|
+
}
|
103
|
+
}
|
104
|
+
}
|
@@ -0,0 +1,39 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="floating-toc"
|
4
|
+
export default class extends Controller {
|
5
|
+
static targets = ["toc"];
|
6
|
+
|
7
|
+
connect() {
|
8
|
+
this._buildToc();
|
9
|
+
}
|
10
|
+
|
11
|
+
_buildToc() {
|
12
|
+
// Find the TOC target element
|
13
|
+
const tocTarget = this.tocTarget;
|
14
|
+
if (!tocTarget) return;
|
15
|
+
|
16
|
+
// Find all elements with the .toc class
|
17
|
+
const tocChapters = document.querySelectorAll(".toc");
|
18
|
+
|
19
|
+
// Create a list item for each chapter
|
20
|
+
tocChapters.forEach((chapter) => {
|
21
|
+
const title = chapter.innerHTML;
|
22
|
+
const id = chapter.id;
|
23
|
+
|
24
|
+
// Create the list item and link
|
25
|
+
const listItem = document.createElement("li");
|
26
|
+
listItem.classList.add("nav-item");
|
27
|
+
|
28
|
+
const link = document.createElement("a");
|
29
|
+
link.classList.add("nav-link");
|
30
|
+
link.href = `#${id}`;
|
31
|
+
link.textContent = title;
|
32
|
+
link.setAttribute("data-turbo", "false");
|
33
|
+
|
34
|
+
// Append the link to the list item, and the list item to the TOC target
|
35
|
+
listItem.appendChild(link);
|
36
|
+
tocTarget.appendChild(listItem);
|
37
|
+
});
|
38
|
+
}
|
39
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { fetchTurboContent } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="form"
|
5
|
+
export default class extends Controller {
|
6
|
+
static values = {
|
7
|
+
resourcePath: String,
|
8
|
+
};
|
9
|
+
|
10
|
+
enable(event) {
|
11
|
+
fetchTurboContent(event, this.resourcePathValue);
|
12
|
+
}
|
13
|
+
|
14
|
+
disable(event) {
|
15
|
+
fetchTurboContent(event, this.resourcePathValue);
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,86 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
export default class extends Controller {
|
4
|
+
connect() {
|
5
|
+
this.setCustomValidationMessages();
|
6
|
+
this._unhideValidationMessages();
|
7
|
+
}
|
8
|
+
|
9
|
+
disconnect() {
|
10
|
+
this.removeCustomValidationMessages();
|
11
|
+
}
|
12
|
+
|
13
|
+
setCustomValidationMessages() {
|
14
|
+
this.getInputFields().forEach((field) => {
|
15
|
+
field.addEventListener("invalid", this.handleInvalid);
|
16
|
+
});
|
17
|
+
}
|
18
|
+
|
19
|
+
removeCustomValidationMessages() {
|
20
|
+
this.getInputFields().forEach((field) => {
|
21
|
+
field.removeEventListener("invalid", this.handleInvalid);
|
22
|
+
});
|
23
|
+
}
|
24
|
+
|
25
|
+
getInputFields() {
|
26
|
+
return Array.from(
|
27
|
+
this.element.querySelectorAll(
|
28
|
+
'input:not([type="hidden"]), select, textarea'
|
29
|
+
)
|
30
|
+
);
|
31
|
+
}
|
32
|
+
|
33
|
+
handleInvalid = (event) => {
|
34
|
+
const field = event.target;
|
35
|
+
if (this.isFieldValid(field)) {
|
36
|
+
field.setCustomValidity("");
|
37
|
+
return;
|
38
|
+
}
|
39
|
+
|
40
|
+
const type = this._isCustomType(field)
|
41
|
+
? field.dataset.fieldType
|
42
|
+
: field.type;
|
43
|
+
let message = "Toto je povinné pole.";
|
44
|
+
|
45
|
+
switch (type) {
|
46
|
+
case "text":
|
47
|
+
message = "Toto je povinné pole.";
|
48
|
+
break;
|
49
|
+
case "autocomplete":
|
50
|
+
message = "Najděte a vyberte si položku ze seznamu.";
|
51
|
+
break;
|
52
|
+
case "email":
|
53
|
+
message = "Zadejte platnou emailovou adresu.";
|
54
|
+
break;
|
55
|
+
case "tel":
|
56
|
+
message = "Zadejte platné telefonní číslo.";
|
57
|
+
break;
|
58
|
+
// Add more cases for other field types as needed
|
59
|
+
}
|
60
|
+
|
61
|
+
field.setCustomValidity(message);
|
62
|
+
};
|
63
|
+
|
64
|
+
isFieldValid(field) {
|
65
|
+
return (
|
66
|
+
!field.validity.badInput &&
|
67
|
+
!field.validity.valueMissing &&
|
68
|
+
!field.validity.typeMismatch &&
|
69
|
+
!field.validity.patternMismatch &&
|
70
|
+
!field.validity.tooShort &&
|
71
|
+
!field.validity.tooLong &&
|
72
|
+
!field.validity.rangeUnderflow &&
|
73
|
+
!field.validity.rangeOverflow
|
74
|
+
);
|
75
|
+
}
|
76
|
+
|
77
|
+
_isCustomType(field) {
|
78
|
+
return field.dataset.fieldType !== undefined;
|
79
|
+
}
|
80
|
+
|
81
|
+
_unhideValidationMessages() {
|
82
|
+
this.element.querySelectorAll(".invalid-feedback").forEach((el) => {
|
83
|
+
el.classList.add("d-table-cell");
|
84
|
+
});
|
85
|
+
}
|
86
|
+
}
|
@@ -0,0 +1,44 @@
|
|
1
|
+
// This file is auto-generated by ./bin/rails stimulus:manifest:update
|
2
|
+
// Run that command whenever you add a new controller or create them with
|
3
|
+
// ./bin/rails generate stimulus controllerName
|
4
|
+
|
5
|
+
import { application } from "./application";
|
6
|
+
|
7
|
+
import AutocompleteController from "./autocomplete_controller";
|
8
|
+
application.register("autocomplete", AutocompleteController);
|
9
|
+
|
10
|
+
import BulkActionController from "./bulk_action_controller";
|
11
|
+
application.register("bulk-action", BulkActionController);
|
12
|
+
|
13
|
+
import ButtonSelectController from "./button_select_controller";
|
14
|
+
application.register("button-select", ButtonSelectController);
|
15
|
+
|
16
|
+
import DatalistController from "./datalist_controller";
|
17
|
+
application.register("datalist", DatalistController);
|
18
|
+
|
19
|
+
import FormController from "./form_controller";
|
20
|
+
application.register("form", FormController);
|
21
|
+
|
22
|
+
import FormValidationController from "./form_validation_controller";
|
23
|
+
application.register("form-validation", FormValidationController);
|
24
|
+
|
25
|
+
import PaginationController from "./pagination_controller";
|
26
|
+
application.register("pagination", PaginationController);
|
27
|
+
|
28
|
+
import SwitchViewController from "./switch_view_controller";
|
29
|
+
application.register("switch-view", SwitchViewController);
|
30
|
+
|
31
|
+
import ToastController from "./toast_controller";
|
32
|
+
application.register("toast", ToastController);
|
33
|
+
|
34
|
+
import TrixController from "./trix_controller";
|
35
|
+
application.register("trix", TrixController);
|
36
|
+
|
37
|
+
import UploadsController from "./uploads_controller";
|
38
|
+
application.register("uploads", UploadsController);
|
39
|
+
|
40
|
+
import SortingController from "./sorting_controller";
|
41
|
+
application.register("sorting", SortingController);
|
42
|
+
|
43
|
+
import FloatingTocController from "./floating_toc_controller";
|
44
|
+
application.register("floating-toc", FloatingTocController);
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { fetchTurboContent } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="pagination"
|
5
|
+
export default class extends Controller {
|
6
|
+
connect() {}
|
7
|
+
|
8
|
+
paginate(event) {
|
9
|
+
const path = event.target.dataset.resourcePath;
|
10
|
+
|
11
|
+
fetchTurboContent(event, path);
|
12
|
+
}
|
13
|
+
}
|
@@ -0,0 +1,17 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { fetchTurboContent } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="sorting"
|
5
|
+
export default class extends Controller {
|
6
|
+
static values = {
|
7
|
+
sortPath: String,
|
8
|
+
};
|
9
|
+
|
10
|
+
// connect() {}
|
11
|
+
|
12
|
+
sort(event) {
|
13
|
+
event.preventDefault();
|
14
|
+
|
15
|
+
fetchTurboContent(event, this.sortPathValue);
|
16
|
+
}
|
17
|
+
}
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
import { fetchTurboContent } from "../utils";
|
3
|
+
|
4
|
+
// Connects to data-controller="switch-view"
|
5
|
+
export default class extends Controller {
|
6
|
+
static values = {
|
7
|
+
resourcePath: String,
|
8
|
+
};
|
9
|
+
|
10
|
+
connect() {}
|
11
|
+
|
12
|
+
switch(event) {
|
13
|
+
fetchTurboContent(event, this.resourcePathValue);
|
14
|
+
}
|
15
|
+
}
|
@@ -0,0 +1,18 @@
|
|
1
|
+
import { Controller } from "@hotwired/stimulus";
|
2
|
+
|
3
|
+
// Connects to data-controller="toast"
|
4
|
+
export default class extends Controller {
|
5
|
+
connect() {
|
6
|
+
//Set a delay to hide the toast message after 5 seconds (5000 milliseconds)
|
7
|
+
setTimeout(() => {
|
8
|
+
this.element.classList.add("slide-out");
|
9
|
+
this.element.addEventListener(
|
10
|
+
"transitionend",
|
11
|
+
() => {
|
12
|
+
this.element.style.display = "none";
|
13
|
+
},
|
14
|
+
{ once: true }
|
15
|
+
);
|
16
|
+
}, 5000);
|
17
|
+
}
|
18
|
+
}
|