headmin 0.5.1 → 0.5.4
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 +4 -4
- data/CHANGELOG.md +2 -2
- data/Gemfile +14 -0
- data/Gemfile.lock +79 -2
- data/app/assets/javascripts/headmin/controllers/media_controller.js +237 -0
- data/app/assets/javascripts/headmin/controllers/media_modal_controller.js +110 -0
- data/app/assets/javascripts/headmin/controllers/remote_modal_controller.js +9 -0
- data/app/assets/javascripts/headmin/controllers/textarea_controller.js +34 -0
- data/app/assets/javascripts/headmin/index.js +8 -0
- data/app/assets/javascripts/headmin.js +294 -0
- data/app/assets/stylesheets/headmin/forms/file.scss +40 -5
- data/app/assets/stylesheets/headmin/forms/media.scss +10 -0
- data/app/assets/stylesheets/headmin/forms.scss +1 -0
- data/app/assets/stylesheets/headmin/layout/sidebar.scss +0 -1
- data/app/assets/stylesheets/headmin/media/index.scss +9 -0
- data/app/assets/stylesheets/headmin/media.scss +1 -0
- data/app/assets/stylesheets/headmin/overrides/redactorx.scss +1 -1
- data/app/assets/stylesheets/headmin/table.scss +8 -0
- data/app/assets/stylesheets/headmin/vendor/{tom-select-bootstrap.css → tom-select-bootstrap.scss} +0 -1
- data/app/assets/stylesheets/headmin.css +61 -8
- data/app/assets/stylesheets/headmin.scss +1 -0
- data/app/controllers/headmin/media_controller.rb +52 -0
- data/app/controllers/headmin_controller.rb +2 -0
- data/app/helpers/headmin/form_helper.rb +2 -2
- data/app/models/concerns/headmin/field.rb +2 -2
- data/app/models/concerns/headmin/fieldable.rb +19 -10
- data/app/models/concerns/headmin/form/hintable.rb +6 -1
- data/app/models/headmin/filter/association.rb +86 -0
- data/app/models/headmin/filter/association_view.rb +74 -0
- data/app/models/headmin/filter/base.rb +5 -2
- data/app/models/headmin/filter/boolean_view.rb +1 -0
- data/app/models/headmin/filter/date.rb +49 -1
- data/app/models/headmin/filter/date_view.rb +1 -0
- data/app/models/headmin/filter/flatpickr_view.rb +1 -0
- data/app/models/headmin/filter/number_view.rb +1 -0
- data/app/models/headmin/filter/operator_view.rb +3 -1
- data/app/models/headmin/filter/options_view.rb +1 -0
- data/app/models/headmin/filter/text_view.rb +1 -0
- data/app/models/headmin/form/association_view.rb +102 -0
- data/app/models/headmin/form/blocks_view.rb +4 -1
- data/app/models/headmin/form/file_view.rb +0 -8
- data/app/models/headmin/form/flatpickr_view.rb +2 -1
- data/app/models/headmin/form/media_item_view.rb +39 -0
- data/app/models/headmin/form/media_view.rb +137 -0
- data/app/models/headmin/form/select_view.rb +2 -1
- data/app/models/headmin/form/textarea_view.rb +6 -1
- data/app/models/headmin/thumbnail_view.rb +40 -19
- data/app/models/view_model.rb +4 -0
- data/app/views/examples/admin.html.erb +8 -8
- data/app/views/examples/auth.html.erb +2 -2
- data/app/views/headmin/_breadcrumbs.html.erb +2 -2
- data/app/views/headmin/_dropdown.html.erb +1 -1
- data/app/views/headmin/_filters.html.erb +12 -7
- data/app/views/headmin/_pagination.html.erb +2 -2
- data/app/views/headmin/_popup.html.erb +4 -4
- data/app/views/headmin/_table.html.erb +1 -1
- data/app/views/headmin/_thumbnail.html.erb +33 -9
- data/app/views/headmin/dropdown/_button.html.erb +2 -2
- data/app/views/headmin/dropdown/_item.html.erb +2 -2
- data/app/views/headmin/dropdown/_list.html.erb +3 -3
- data/app/views/headmin/dropdown/_locale.html.erb +5 -5
- data/app/views/headmin/filters/_association.html.erb +24 -0
- data/app/views/headmin/filters/_options.html.erb +1 -1
- data/app/views/headmin/filters/filter/_button.html.erb +2 -2
- data/app/views/headmin/filters/filter/_null_select.html.erb +2 -2
- data/app/views/headmin/forms/_association.html.erb +30 -0
- data/app/views/headmin/forms/_errors.html.erb +1 -1
- data/app/views/headmin/forms/_file.html.erb +10 -11
- data/app/views/headmin/forms/_hint.html.erb +6 -1
- data/app/views/headmin/forms/_media.html.erb +60 -0
- data/app/views/headmin/forms/_repeater.html.erb +18 -16
- data/app/views/headmin/forms/_textarea.html.erb +1 -1
- data/app/views/headmin/forms/_wrapper.html.erb +0 -1
- data/app/views/headmin/forms/fields/_list.html.erb +6 -4
- data/app/views/headmin/forms/media/_item.html.erb +38 -0
- data/app/views/headmin/forms/media/_validation.html.erb +10 -0
- data/app/views/headmin/forms/repeater/_row.html.erb +17 -15
- data/app/views/headmin/heading/_title.html.erb +2 -2
- data/app/views/headmin/layout/_main.html.erb +2 -0
- data/app/views/headmin/layout/_remote_modal.html.erb +1 -0
- data/app/views/headmin/layout/_sidebar.html.erb +1 -1
- data/app/views/headmin/media/_item.html.erb +16 -0
- data/app/views/headmin/media/_media_item_modal.html.erb +51 -0
- data/app/views/headmin/media/_modal.html.erb +35 -0
- data/app/views/headmin/media/create.turbo_stream.erb +5 -0
- data/app/views/headmin/media/index.html.erb +3 -0
- data/app/views/headmin/media/show.html.erb +9 -0
- data/app/views/headmin/media/update.turbo_stream.erb +3 -0
- data/app/views/headmin/nav/_dropdown.html.erb +7 -7
- data/app/views/headmin/nav/_item.html.erb +5 -5
- data/app/views/headmin/nav/item/_locale.html.erb +6 -6
- data/app/views/headmin/pagination/_per_page.html.erb +7 -7
- data/app/views/headmin/pagination/kaminari/_first_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_gap.html.erb +1 -1
- data/app/views/headmin/pagination/kaminari/_last_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_next_page.html.erb +3 -3
- data/app/views/headmin/pagination/kaminari/_page.html.erb +2 -2
- data/app/views/headmin/pagination/kaminari/_paginator.html.erb +1 -1
- data/app/views/headmin/pagination/kaminari/_prev_page.html.erb +2 -2
- data/app/views/headmin/table/_actions.html.erb +9 -9
- data/app/views/headmin/table/_body.html.erb +1 -1
- data/app/views/headmin/table/actions/_action.html.erb +4 -4
- data/app/views/headmin/table/actions/_export.html.erb +1 -1
- data/app/views/headmin/table/body/_association.html.erb +17 -3
- data/app/views/headmin/table/body/_boolean.erb +4 -4
- data/app/views/headmin/table/body/_date.html.erb +2 -2
- data/app/views/headmin/table/body/_image.html.erb +18 -0
- data/app/views/headmin/table/body/_string.html.erb +1 -1
- data/app/views/headmin/table/head/_cell.html.erb +1 -1
- data/app/views/headmin/table/head/cell/_asc.html.erb +2 -2
- data/app/views/headmin/table/head/cell/_default.html.erb +1 -1
- data/app/views/headmin/table/head/cell/_desc.html.erb +1 -1
- data/app/views/headmin/views/devise/confirmations/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/passwords/_edit.html.erb +1 -1
- data/app/views/headmin/views/devise/passwords/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/registrations/_edit.html.erb +5 -5
- data/app/views/headmin/views/devise/registrations/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/sessions/_new.html.erb +1 -1
- data/app/views/headmin/views/devise/shared/_links.html.erb +14 -20
- data/app/views/headmin/views/devise/unlocks/_new.html.erb +1 -1
- data/config/locales/activerecord/en.yml +1 -0
- data/config/locales/activerecord/nl.yml +1 -0
- data/config/locales/devise/nl.yml +1 -1
- data/config/locales/headmin/filters/en.yml +3 -1
- data/config/locales/headmin/filters/nl.yml +2 -0
- data/config/locales/headmin/forms/en.yml +8 -0
- data/config/locales/headmin/forms/nl.yml +8 -0
- data/config/locales/headmin/media/en.yml +23 -0
- data/config/locales/headmin/media/nl.yml +23 -0
- data/config/locales/headmin/table/en.yml +2 -0
- data/config/locales/headmin/table/nl.yml +2 -0
- data/config/routes.rb +10 -0
- data/lib/generators/templates/views/layouts/auth.html.erb +2 -2
- data/lib/headmin/version.rb +1 -1
- data/package.json +1 -1
- metadata +34 -3
@@ -10093,6 +10093,260 @@ var hello_controller_default = class extends Controller {
|
|
10093
10093
|
}
|
10094
10094
|
};
|
10095
10095
|
|
10096
|
+
// app/assets/javascripts/headmin/controllers/media_controller.js
|
10097
|
+
var media_controller_default = class extends Controller {
|
10098
|
+
static get targets() {
|
10099
|
+
return ["item", "template", "thumbnails", "modalButton", "placeholder", "validationInput", "count", "editButton"];
|
10100
|
+
}
|
10101
|
+
connect() {
|
10102
|
+
document.addEventListener("mediaSelectionSubmitted", (event) => {
|
10103
|
+
if (event.detail.name === this.element.dataset.name) {
|
10104
|
+
this.selectItems(event.detail.items);
|
10105
|
+
}
|
10106
|
+
});
|
10107
|
+
if (this.hasSorting()) {
|
10108
|
+
this.initSortable();
|
10109
|
+
}
|
10110
|
+
this.validate();
|
10111
|
+
}
|
10112
|
+
destroy(event) {
|
10113
|
+
const item = event.currentTarget.closest("[data-media-target='item']");
|
10114
|
+
this.destroyItem(item);
|
10115
|
+
}
|
10116
|
+
syncIds() {
|
10117
|
+
const ids = this.activeIds();
|
10118
|
+
this.modalButtonTargets.forEach((button) => {
|
10119
|
+
const url = new URL(button.getAttribute("href"));
|
10120
|
+
url.searchParams.delete("ids[]");
|
10121
|
+
ids.forEach((id) => {
|
10122
|
+
url.searchParams.append("ids[]", id);
|
10123
|
+
});
|
10124
|
+
button.setAttribute("href", url.toString());
|
10125
|
+
});
|
10126
|
+
}
|
10127
|
+
initSortable() {
|
10128
|
+
sortable_esm_default.create(this.thumbnailsTarget, {
|
10129
|
+
handle: ".media-drag-sort-handle",
|
10130
|
+
onEnd: (event) => {
|
10131
|
+
this.resetPositions();
|
10132
|
+
}
|
10133
|
+
});
|
10134
|
+
}
|
10135
|
+
hasSorting() {
|
10136
|
+
return this.element.dataset.sort === "true";
|
10137
|
+
}
|
10138
|
+
destroyItem(item) {
|
10139
|
+
this.removeItem(item);
|
10140
|
+
this.postProcess();
|
10141
|
+
}
|
10142
|
+
selectItems(items) {
|
10143
|
+
this.removeAllItems();
|
10144
|
+
this.addItems(items);
|
10145
|
+
this.postProcess();
|
10146
|
+
}
|
10147
|
+
postProcess() {
|
10148
|
+
this.resetPositions();
|
10149
|
+
this.syncIds();
|
10150
|
+
this.togglePlaceholder();
|
10151
|
+
this.validate();
|
10152
|
+
}
|
10153
|
+
validate() {
|
10154
|
+
this.clearValidation();
|
10155
|
+
if (this.element.dataset.required === "0")
|
10156
|
+
return;
|
10157
|
+
this.validateMinimum();
|
10158
|
+
this.validateMaximum();
|
10159
|
+
}
|
10160
|
+
clearValidation() {
|
10161
|
+
this.validationInputTarget.setCustomValidity("");
|
10162
|
+
}
|
10163
|
+
validateMinimum() {
|
10164
|
+
const count = this.activeItems().length;
|
10165
|
+
if (count < this.minActiveItems()) {
|
10166
|
+
this.validationInputTarget.setCustomValidity(this.validationInputTarget.dataset.minMessage);
|
10167
|
+
}
|
10168
|
+
}
|
10169
|
+
validateMaximum() {
|
10170
|
+
const count = this.activeItems().length;
|
10171
|
+
if (count > this.maxActiveItems()) {
|
10172
|
+
this.validationInputTarget.setCustomValidity(this.validationInputTarget.dataset.maxMessage);
|
10173
|
+
}
|
10174
|
+
}
|
10175
|
+
minActiveItems() {
|
10176
|
+
return parseInt(this.element.dataset.min, 10) || 0;
|
10177
|
+
}
|
10178
|
+
maxActiveItems() {
|
10179
|
+
return parseInt(this.element.dataset.max, 10) || Infinity;
|
10180
|
+
}
|
10181
|
+
resetPositions() {
|
10182
|
+
this.activeItems().forEach((item, index2) => {
|
10183
|
+
const positionInput = item.querySelector("input[name*='position']");
|
10184
|
+
if (positionInput) {
|
10185
|
+
positionInput.value = index2;
|
10186
|
+
}
|
10187
|
+
});
|
10188
|
+
}
|
10189
|
+
addItems(items) {
|
10190
|
+
items.forEach((item) => this.addItem(item));
|
10191
|
+
}
|
10192
|
+
addItem(item) {
|
10193
|
+
const currentItem = this.itemByBlobId(item.blobId);
|
10194
|
+
if (currentItem) {
|
10195
|
+
this.enableItem(currentItem);
|
10196
|
+
} else {
|
10197
|
+
this.createItem(item);
|
10198
|
+
}
|
10199
|
+
}
|
10200
|
+
togglePlaceholder() {
|
10201
|
+
if (this.activeItems().length > 0) {
|
10202
|
+
this.hidePlaceholder();
|
10203
|
+
} else {
|
10204
|
+
this.showPlaceholder();
|
10205
|
+
}
|
10206
|
+
}
|
10207
|
+
showPlaceholder() {
|
10208
|
+
this.placeholderTarget.classList.remove("d-none");
|
10209
|
+
}
|
10210
|
+
hidePlaceholder() {
|
10211
|
+
this.placeholderTarget.classList.add("d-none");
|
10212
|
+
}
|
10213
|
+
enableItem(item) {
|
10214
|
+
item.querySelector("input[name*='_destroy']").value = false;
|
10215
|
+
item.classList.remove("d-none");
|
10216
|
+
}
|
10217
|
+
createItem(item) {
|
10218
|
+
const template = this.templateTarget;
|
10219
|
+
const html = this.randomizeIds(template);
|
10220
|
+
this.thumbnailsTarget.insertAdjacentHTML("beforeend", html);
|
10221
|
+
const newItem = this.itemTargets.pop();
|
10222
|
+
newItem.querySelector('input[name*="[blob_id]"]').value = item.blobId;
|
10223
|
+
newItem.querySelector('input[name*="[_destroy]"]').value = false;
|
10224
|
+
const editButton = newItem.querySelector('[data-media-target="editButton"]');
|
10225
|
+
editButton.setAttribute("href", editButton.getAttribute("href").replace("$1", item.blobId));
|
10226
|
+
const oldThumbnail = newItem.querySelector(".h-thumbnail");
|
10227
|
+
const newThumbnail = item.thumbnail.cloneNode(true);
|
10228
|
+
oldThumbnail.parentNode.replaceChild(newThumbnail, oldThumbnail);
|
10229
|
+
}
|
10230
|
+
randomizeIds(template) {
|
10231
|
+
const regex = new RegExp(template.dataset.templateIdRegex, "g");
|
10232
|
+
const randomNumber = Math.floor(1e8 + Math.random() * 9e8);
|
10233
|
+
return template.innerHTML.replace(regex, randomNumber);
|
10234
|
+
}
|
10235
|
+
removeAllItems() {
|
10236
|
+
this.removeItems(this.itemTargets);
|
10237
|
+
}
|
10238
|
+
removeItems(items) {
|
10239
|
+
items.forEach((item) => {
|
10240
|
+
this.removeItem(item);
|
10241
|
+
});
|
10242
|
+
}
|
10243
|
+
removeItem(item) {
|
10244
|
+
item.querySelector("input[name*='_destroy']").value = 1;
|
10245
|
+
item.classList.add("d-none");
|
10246
|
+
this.resetPositions();
|
10247
|
+
this.syncIds();
|
10248
|
+
this.togglePlaceholder();
|
10249
|
+
}
|
10250
|
+
itemByBlobId(blobId) {
|
10251
|
+
return this.itemTargets.find((item) => {
|
10252
|
+
return item.querySelector("input[name*='blob_id']").value === blobId;
|
10253
|
+
});
|
10254
|
+
}
|
10255
|
+
activeItems() {
|
10256
|
+
return this.itemTargets.filter((item) => {
|
10257
|
+
return item.querySelector("input[name$='[_destroy]']").value === "false";
|
10258
|
+
});
|
10259
|
+
}
|
10260
|
+
activeIds() {
|
10261
|
+
return this.activeItems().map((item) => {
|
10262
|
+
return item.querySelector("input[name$='[blob_id]']").value;
|
10263
|
+
});
|
10264
|
+
}
|
10265
|
+
};
|
10266
|
+
|
10267
|
+
// app/assets/javascripts/headmin/controllers/media_modal_controller.js
|
10268
|
+
var media_modal_controller_default = class extends Controller {
|
10269
|
+
static get targets() {
|
10270
|
+
return ["idCheckbox", "item", "form", "selectButton", "placeholder", "count"];
|
10271
|
+
}
|
10272
|
+
connect() {
|
10273
|
+
this.validate();
|
10274
|
+
this.updateCount();
|
10275
|
+
}
|
10276
|
+
select() {
|
10277
|
+
this.dispatchSelectionEvent();
|
10278
|
+
}
|
10279
|
+
submitForm() {
|
10280
|
+
this.hidePlaceholder();
|
10281
|
+
this.triggerFormSubmission();
|
10282
|
+
}
|
10283
|
+
inputChange() {
|
10284
|
+
this.handleInputChange();
|
10285
|
+
this.updateCount();
|
10286
|
+
}
|
10287
|
+
hidePlaceholder() {
|
10288
|
+
this.placeholderTarget.classList.add("d-none");
|
10289
|
+
}
|
10290
|
+
handleInputChange() {
|
10291
|
+
this.validate();
|
10292
|
+
}
|
10293
|
+
dispatchSelectionEvent() {
|
10294
|
+
document.dispatchEvent(new CustomEvent("mediaSelectionSubmitted", {
|
10295
|
+
detail: {
|
10296
|
+
name: this.element.dataset.name,
|
10297
|
+
items: this.renderItemsForEvent(this.selectedItems())
|
10298
|
+
}
|
10299
|
+
}));
|
10300
|
+
}
|
10301
|
+
triggerFormSubmission() {
|
10302
|
+
this.formTarget.requestSubmit();
|
10303
|
+
}
|
10304
|
+
renderItemsForEvent(items) {
|
10305
|
+
return items.map((item) => this.renderItemForEvent(item));
|
10306
|
+
}
|
10307
|
+
renderItemForEvent(item) {
|
10308
|
+
return {
|
10309
|
+
blobId: item.querySelector('input[type="checkbox"]').value,
|
10310
|
+
thumbnail: item.querySelector(".h-thumbnail")
|
10311
|
+
};
|
10312
|
+
}
|
10313
|
+
selectedItems() {
|
10314
|
+
return this.itemTargets.filter((item) => {
|
10315
|
+
const checkbox = item.querySelector('input[type="checkbox"]');
|
10316
|
+
return checkbox.checked;
|
10317
|
+
});
|
10318
|
+
}
|
10319
|
+
selectedItemsCount() {
|
10320
|
+
return this.selectedItems().length;
|
10321
|
+
}
|
10322
|
+
minSelectedItems() {
|
10323
|
+
return parseInt(this.element.dataset.min, 10) || 0;
|
10324
|
+
}
|
10325
|
+
maxSelectedItems() {
|
10326
|
+
return parseInt(this.element.dataset.max, 10) || Infinity;
|
10327
|
+
}
|
10328
|
+
validate() {
|
10329
|
+
if (this.isValid()) {
|
10330
|
+
this.enableSelectButton();
|
10331
|
+
} else {
|
10332
|
+
this.disableSelectButton();
|
10333
|
+
}
|
10334
|
+
}
|
10335
|
+
enableSelectButton() {
|
10336
|
+
this.selectButtonTarget.removeAttribute("disabled");
|
10337
|
+
}
|
10338
|
+
disableSelectButton() {
|
10339
|
+
this.selectButtonTarget.setAttribute("disabled", "");
|
10340
|
+
}
|
10341
|
+
isValid() {
|
10342
|
+
const count = this.selectedItemsCount();
|
10343
|
+
return count >= this.minSelectedItems() && count <= this.maxSelectedItems();
|
10344
|
+
}
|
10345
|
+
updateCount() {
|
10346
|
+
this.countTarget.innerHTML = this.idCheckboxTargets.filter((checkbox) => checkbox.checked).length;
|
10347
|
+
}
|
10348
|
+
};
|
10349
|
+
|
10096
10350
|
// node_modules/@popperjs/core/lib/index.js
|
10097
10351
|
var lib_exports = {};
|
10098
10352
|
__export(lib_exports, {
|
@@ -15236,6 +15490,14 @@ var redactorx_controller_default = class extends Controller {
|
|
15236
15490
|
}
|
15237
15491
|
};
|
15238
15492
|
|
15493
|
+
// app/assets/javascripts/headmin/controllers/remote_modal_controller.js
|
15494
|
+
var remote_modal_controller_default = class extends Controller {
|
15495
|
+
connect() {
|
15496
|
+
this.modal = new Modal(this.element);
|
15497
|
+
this.modal.show();
|
15498
|
+
}
|
15499
|
+
};
|
15500
|
+
|
15239
15501
|
// app/assets/javascripts/headmin/controllers/repeater_controller.js
|
15240
15502
|
var repeater_controller_default = class extends Controller {
|
15241
15503
|
static get values() {
|
@@ -15580,6 +15842,34 @@ var table_controller_default = class extends Controller {
|
|
15580
15842
|
}
|
15581
15843
|
};
|
15582
15844
|
|
15845
|
+
// app/assets/javascripts/headmin/controllers/textarea_controller.js
|
15846
|
+
var textarea_controller_default = class extends Controller {
|
15847
|
+
static get targets() {
|
15848
|
+
return ["textarea", "count"];
|
15849
|
+
}
|
15850
|
+
connect() {
|
15851
|
+
this.update();
|
15852
|
+
}
|
15853
|
+
update() {
|
15854
|
+
this.resize();
|
15855
|
+
this.updateCount();
|
15856
|
+
}
|
15857
|
+
resize() {
|
15858
|
+
this.textareaTarget.style.height = "auto";
|
15859
|
+
this.textareaTarget.setAttribute("style", "height:" + this.textareaTarget.scrollHeight + "px;overflow-y:hidden;");
|
15860
|
+
}
|
15861
|
+
updateCount() {
|
15862
|
+
if (this.textareaTarget.getAttribute("maxlength")) {
|
15863
|
+
this.updateCountLength();
|
15864
|
+
}
|
15865
|
+
}
|
15866
|
+
updateCountLength() {
|
15867
|
+
const currentLength = this.textareaTarget.value.length;
|
15868
|
+
const maximumLength = this.textareaTarget.getAttribute("maxlength");
|
15869
|
+
this.countTarget.textContent = `${currentLength}/${maximumLength}`;
|
15870
|
+
}
|
15871
|
+
};
|
15872
|
+
|
15583
15873
|
// app/assets/javascripts/headmin/index.js
|
15584
15874
|
var Headmin = class {
|
15585
15875
|
static start() {
|
@@ -15594,13 +15884,17 @@ var Headmin = class {
|
|
15594
15884
|
Stimulus.register("filters", filters_controller_default);
|
15595
15885
|
Stimulus.register("flatpickr", flatpickr_controller_default);
|
15596
15886
|
Stimulus.register("hello", hello_controller_default);
|
15887
|
+
Stimulus.register("media", media_controller_default);
|
15888
|
+
Stimulus.register("media-modal", media_modal_controller_default);
|
15597
15889
|
Stimulus.register("notification", notification_controller_default);
|
15598
15890
|
Stimulus.register("popup", popup_controller_default);
|
15599
15891
|
Stimulus.register("redactorx", redactorx_controller_default);
|
15892
|
+
Stimulus.register("remote-modal", remote_modal_controller_default);
|
15600
15893
|
Stimulus.register("repeater", repeater_controller_default);
|
15601
15894
|
Stimulus.register("select", select_controller_default);
|
15602
15895
|
Stimulus.register("table", table_controller_default);
|
15603
15896
|
Stimulus.register("table-actions", table_actions_controller_default);
|
15897
|
+
Stimulus.register("textarea", textarea_controller_default);
|
15604
15898
|
}
|
15605
15899
|
};
|
15606
15900
|
export {
|
@@ -17,26 +17,41 @@
|
|
17
17
|
display: flex;
|
18
18
|
flex-wrap: wrap;
|
19
19
|
gap: map-get($spacers, 2);
|
20
|
+
|
21
|
+
a, a:link, a:hover {
|
22
|
+
color: inherit;
|
23
|
+
text-decoration: inherit;
|
24
|
+
}
|
20
25
|
}
|
21
26
|
|
22
27
|
.h-form-file-thumbnail {
|
23
28
|
position: relative;
|
24
29
|
pointer-events: initial !important;
|
25
30
|
display: flex;
|
31
|
+
|
32
|
+
&:hover {
|
33
|
+
.h-form-file-thumbnail-actions {
|
34
|
+
display: block;
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
|
39
|
+
.h-form-file-thumbnail-actions {
|
40
|
+
display: none;
|
26
41
|
}
|
27
42
|
|
28
43
|
.h-form-file-thumbnail-remove {
|
29
44
|
position: absolute;
|
30
|
-
top:
|
31
|
-
right:
|
45
|
+
top: 5px;
|
46
|
+
right: 5px;
|
32
47
|
background: $danger;
|
33
|
-
width:
|
34
|
-
height:
|
48
|
+
width: 25px;
|
49
|
+
height: 25px;
|
35
50
|
display: flex;
|
36
51
|
align-items: center;
|
37
52
|
justify-content: center;
|
38
53
|
color: white;
|
39
|
-
border-radius: $border-radius;
|
54
|
+
border-radius: $border-radius-pill;
|
40
55
|
z-index: 3;
|
41
56
|
cursor: pointer;
|
42
57
|
|
@@ -44,3 +59,23 @@
|
|
44
59
|
background: tint-color($danger, $btn-hover-bg-tint-amount)
|
45
60
|
}
|
46
61
|
}
|
62
|
+
|
63
|
+
.h-form-file-thumbnail-edit {
|
64
|
+
position: absolute;
|
65
|
+
top: 5px;
|
66
|
+
right: 35px;
|
67
|
+
background-color: rgba(0, 0, 0, 0.7);
|
68
|
+
width: 25px;
|
69
|
+
height: 25px;
|
70
|
+
display: flex;
|
71
|
+
align-items: center;
|
72
|
+
justify-content: center;
|
73
|
+
border-radius: $border-radius-pill;
|
74
|
+
z-index: 3;
|
75
|
+
cursor: pointer;
|
76
|
+
color: white !important;
|
77
|
+
|
78
|
+
&:hover {
|
79
|
+
background-color: rgba(0, 0, 0, 1);
|
80
|
+
}
|
81
|
+
}
|
@@ -0,0 +1 @@
|
|
1
|
+
@import "media/index";
|
@@ -10180,7 +10180,6 @@ fieldset:disabled .btn {
|
|
10180
10180
|
.ts-wrapper.form-select {
|
10181
10181
|
padding: 0;
|
10182
10182
|
height: auto;
|
10183
|
-
box-shadow: none;
|
10184
10183
|
}
|
10185
10184
|
.ts-wrapper.form-select .ts-control,
|
10186
10185
|
.ts-wrapper.form-select.single.input-active .ts-control {
|
@@ -12944,7 +12943,10 @@ span.flatpickr-weekday {
|
|
12944
12943
|
padding: 0.375rem 0.75rem !important;
|
12945
12944
|
position: relative;
|
12946
12945
|
}
|
12947
|
-
.rx-content p
|
12946
|
+
.rx-content p,
|
12947
|
+
.rx-content ul li,
|
12948
|
+
.rx-content ol li,
|
12949
|
+
.rx-content td {
|
12948
12950
|
font-size: 0.9rem;
|
12949
12951
|
line-height: 1.5;
|
12950
12952
|
color: #212529;
|
@@ -13019,29 +13021,69 @@ span.flatpickr-weekday {
|
|
13019
13021
|
flex-wrap: wrap;
|
13020
13022
|
gap: 0.5rem;
|
13021
13023
|
}
|
13024
|
+
.h-form-file-thumbnails a,
|
13025
|
+
.h-form-file-thumbnails a:link,
|
13026
|
+
.h-form-file-thumbnails a:hover {
|
13027
|
+
color: inherit;
|
13028
|
+
text-decoration: inherit;
|
13029
|
+
}
|
13022
13030
|
.h-form-file-thumbnail {
|
13023
13031
|
position: relative;
|
13024
13032
|
pointer-events: initial !important;
|
13025
13033
|
display: flex;
|
13026
13034
|
}
|
13035
|
+
.h-form-file-thumbnail:hover .h-form-file-thumbnail-actions {
|
13036
|
+
display: block;
|
13037
|
+
}
|
13038
|
+
.h-form-file-thumbnail-actions {
|
13039
|
+
display: none;
|
13040
|
+
}
|
13027
13041
|
.h-form-file-thumbnail-remove {
|
13028
13042
|
position: absolute;
|
13029
|
-
top:
|
13030
|
-
right:
|
13043
|
+
top: 5px;
|
13044
|
+
right: 5px;
|
13031
13045
|
background: #dc3545;
|
13032
|
-
width:
|
13033
|
-
height:
|
13046
|
+
width: 25px;
|
13047
|
+
height: 25px;
|
13034
13048
|
display: flex;
|
13035
13049
|
align-items: center;
|
13036
13050
|
justify-content: center;
|
13037
13051
|
color: white;
|
13038
|
-
border-radius:
|
13052
|
+
border-radius: 50rem;
|
13039
13053
|
z-index: 3;
|
13040
13054
|
cursor: pointer;
|
13041
13055
|
}
|
13042
13056
|
.h-form-file-thumbnail-remove:hover {
|
13043
13057
|
background: #e15361;
|
13044
13058
|
}
|
13059
|
+
.h-form-file-thumbnail-edit {
|
13060
|
+
position: absolute;
|
13061
|
+
top: 5px;
|
13062
|
+
right: 35px;
|
13063
|
+
background-color: rgba(0, 0, 0, 0.7);
|
13064
|
+
width: 25px;
|
13065
|
+
height: 25px;
|
13066
|
+
display: flex;
|
13067
|
+
align-items: center;
|
13068
|
+
justify-content: center;
|
13069
|
+
border-radius: 50rem;
|
13070
|
+
z-index: 3;
|
13071
|
+
cursor: pointer;
|
13072
|
+
color: white !important;
|
13073
|
+
}
|
13074
|
+
.h-form-file-thumbnail-edit:hover {
|
13075
|
+
background-color: black;
|
13076
|
+
}
|
13077
|
+
.h-form-media-validation {
|
13078
|
+
opacity: 0;
|
13079
|
+
width: 100px;
|
13080
|
+
height: 0;
|
13081
|
+
padding: 0;
|
13082
|
+
margin: 0;
|
13083
|
+
position: absolute;
|
13084
|
+
bottom: 0;
|
13085
|
+
left: 0;
|
13086
|
+
}
|
13045
13087
|
.repeater {
|
13046
13088
|
position: relative;
|
13047
13089
|
}
|
@@ -13138,7 +13180,6 @@ mark,
|
|
13138
13180
|
.nav-brand svg,
|
13139
13181
|
.nav-brand img {
|
13140
13182
|
max-width: 100%;
|
13141
|
-
height: 30px;
|
13142
13183
|
}
|
13143
13184
|
.nav-brand svg {
|
13144
13185
|
fill: #ffffff;
|
@@ -13204,6 +13245,12 @@ body.empty {
|
|
13204
13245
|
width: 300px;
|
13205
13246
|
max-width: 100%;
|
13206
13247
|
}
|
13248
|
+
.h-table-cell-image {
|
13249
|
+
padding: 0.4rem 1rem !important;
|
13250
|
+
}
|
13251
|
+
.h-table-cell-image img {
|
13252
|
+
border-radius: 3px;
|
13253
|
+
}
|
13207
13254
|
.h-table-cell-color {
|
13208
13255
|
width: 22px;
|
13209
13256
|
height: 22px;
|
@@ -13390,6 +13437,12 @@ body.empty {
|
|
13390
13437
|
z-index: 9;
|
13391
13438
|
display: none;
|
13392
13439
|
}
|
13440
|
+
.media-modal .h-thumbnail {
|
13441
|
+
cursor: pointer;
|
13442
|
+
}
|
13443
|
+
.media-modal input[type=checkbox]:checked + label .h-thumbnail {
|
13444
|
+
background-color: #0d6efd;
|
13445
|
+
}
|
13393
13446
|
.h-popup {
|
13394
13447
|
padding: 10px;
|
13395
13448
|
background: #ffffff;
|
@@ -0,0 +1,52 @@
|
|
1
|
+
class Headmin::MediaController < HeadminController
|
2
|
+
layout false
|
3
|
+
|
4
|
+
def index
|
5
|
+
@blobs =
|
6
|
+
ActiveStorage::Blob
|
7
|
+
.left_outer_joins(:attachments)
|
8
|
+
.where.not(active_storage_attachments: {record_type: "ActiveStorage::VariantRecord"}) # Not a variant
|
9
|
+
.or(ActiveStorage::Blob.where(active_storage_attachments: {id: nil})) # Or an orphan
|
10
|
+
.order(created_at: :desc)
|
11
|
+
.group(:id)
|
12
|
+
.all
|
13
|
+
end
|
14
|
+
|
15
|
+
def create
|
16
|
+
blobs = []
|
17
|
+
media_params[:files].reject { |c| c.blank? }.each do |file|
|
18
|
+
blobs << ActiveStorage::Blob.create_and_upload!(io: file, filename: file.original_filename)
|
19
|
+
end
|
20
|
+
|
21
|
+
respond_to do |format|
|
22
|
+
format.turbo_stream {
|
23
|
+
@blobs = blobs
|
24
|
+
}
|
25
|
+
format.html { redirect_to root_path }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def show
|
30
|
+
@blob = ActiveStorage::Blob.find(params[:id])
|
31
|
+
end
|
32
|
+
|
33
|
+
def update
|
34
|
+
@blob = ActiveStorage::Blob.find(params[:id])
|
35
|
+
media_item_params[:filename] = media_item_params[:filename] + "." + @blob.filename.to_s.rpartition(".").last
|
36
|
+
if @blob.update(media_item_params)
|
37
|
+
flash.now[:notice] = t("admin.flash.updated", name: @blob.filename)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
def media_params
|
44
|
+
params.permit(
|
45
|
+
files: []
|
46
|
+
)
|
47
|
+
end
|
48
|
+
|
49
|
+
def media_item_params
|
50
|
+
params.require(:blob).permit!
|
51
|
+
end
|
52
|
+
end
|
@@ -16,8 +16,8 @@ module Headmin
|
|
16
16
|
# https://example.com/products?amount=1&type[]=food&type[]=beverage
|
17
17
|
#
|
18
18
|
# <%= form.hidden_input :amount, value: 1 %>
|
19
|
-
# <%= form.hidden_input :
|
20
|
-
# <%= form.hidden_input :
|
19
|
+
# <%= form.hidden_input :"type[]", value: "food" %>
|
20
|
+
# <%= form.hidden_input :"type[]", value: "beverage" %>
|
21
21
|
def query_parameter_fields(form)
|
22
22
|
test = request.query_parameters.map do |name, value|
|
23
23
|
if value.is_a?(Array)
|
@@ -4,7 +4,7 @@ module Headmin
|
|
4
4
|
|
5
5
|
included do
|
6
6
|
# Configuration
|
7
|
-
has_closure_tree
|
7
|
+
has_closure_tree order: "position", numeric_order: true
|
8
8
|
|
9
9
|
# Associations
|
10
10
|
belongs_to :fieldable, polymorphic: true, optional: true, touch: true
|
@@ -13,7 +13,7 @@ module Headmin
|
|
13
13
|
accepts_nested_attributes_for :fields, allow_destroy: true
|
14
14
|
|
15
15
|
# field_type: :files, :file
|
16
|
-
has_many_attached :files
|
16
|
+
has_many_attached :files, dependent: :detach
|
17
17
|
accepts_nested_attributes_for :files_attachments, allow_destroy: true
|
18
18
|
end
|
19
19
|
end
|