diff options
| author | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 04:54:33 +0200 |
|---|---|---|
| committer | erdgeist <erdgeist@erdgeist.org> | 2026-07-13 04:54:33 +0200 |
| commit | 8baac265059b70da0148487458ee4077b15f155e (patch) | |
| tree | b97b07a76bec2fef602fa01c1739a89a412d812f /public/javascripts | |
| parent | b138f40a6493f7c4341fba196c48440e795babb9 (diff) | |
Asset picker: attach/detach/reorder UI, read-only view, autosave fix
Replaces nodes#edit's old Images section -- a hidden panel dumping
every image asset in the system unfiltered (#image_browser) plus a
raw drag-and-drop box (#image_box) -- with a small search-and-click
picker built on the endpoint from the last two commits. Attaching
posts immediately and appends the new thumbnail via a cloned
<template> -- icons only render correctly through the Rails helper
server-side, so the template holds real, pre-rendered markup for JS
to clone rather than duplicating raw SVG in a JS string. Reordering is
jQuery UI sortable on the small attached list only, with a dedicated
drag handle rather than the whole thumbnail.
Two bugs caught while click-testing, fixed here rather than shipped
and patched after: the search panel never closed after attaching an
image, since the success handler re-triggered focus to keep it open
for attaching several in a row -- which meant it just re-populated
itself forever instead of signaling "done." Fixed to close explicitly;
a click-outside-closes handler was added alongside it, matching the
affordance the top-bar search already has.
A real, independent, pre-existing data bug surfaced during the same
testing: Node#autosave!'s first-time-creation branch never carried
related assets forward from whatever page was previously current --
attach an image, let autosave fire once, and it silently landed on a
fresh, assetless Page row. Long-dormant, not introduced by this work,
just finally exercised by something that made it visible. Fixed inside
the `unless self.autosave` guard specifically -- running this on every
call, not just creation, would overwrite anything attached directly to
an existing autosave in between, a worse bug than the one being fixed.
nodes#show gains a read-only Images section, rendered only when a page
actually has attached images, so an attachment can be confirmed
present without entering the edit/lock cycle -- useful on its own, and
specifically useful the next time an asset bug needs investigating.
Its thumbnail CSS is shared with the edit view's picker via a class
(.thumbnail_list) rather than duplicated under a second name.
Diffstat (limited to 'public/javascripts')
| -rw-r--r-- | public/javascripts/admin_interface.js | 4 | ||||
| -rw-r--r-- | public/javascripts/related_assets.js | 80 |
2 files changed, 84 insertions, 0 deletions
diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js index 3f6a0a9..619933d 100644 --- a/public/javascripts/admin_interface.js +++ b/public/javascripts/admin_interface.js | |||
| @@ -59,6 +59,10 @@ $(document).ready(function () { | |||
| 59 | event_search.initialize_search(); | 59 | event_search.initialize_search(); |
| 60 | } | 60 | } |
| 61 | 61 | ||
| 62 | if ($("#related_asset_search_term").length != 0) { | ||
| 63 | related_assets.initialize(); | ||
| 64 | } | ||
| 65 | |||
| 62 | if ($("#rrule_builder").length != 0) { | 66 | if ($("#rrule_builder").length != 0) { |
| 63 | rrule_builder.initialize(); | 67 | rrule_builder.initialize(); |
| 64 | } | 68 | } |
diff --git a/public/javascripts/related_assets.js b/public/javascripts/related_assets.js new file mode 100644 index 0000000..2955cbf --- /dev/null +++ b/public/javascripts/related_assets.js | |||
| @@ -0,0 +1,80 @@ | |||
| 1 | related_assets = { | ||
| 2 | initialize: function() { | ||
| 3 | var container = $("#related_assets"); | ||
| 4 | var searchUrl = container.data("search-url"); | ||
| 5 | var createUrl = container.data("create-url"); | ||
| 6 | var list = $("#related_asset_list"); | ||
| 7 | |||
| 8 | initSearchPicker({ | ||
| 9 | inputSelector: "#related_asset_search_term", | ||
| 10 | resultsSelector: "#related_asset_search_results", | ||
| 11 | url: searchUrl, | ||
| 12 | loadOnFocus: true, | ||
| 13 | renderResults: function(data, results) { | ||
| 14 | var found = false; | ||
| 15 | data.forEach(function(asset) { | ||
| 16 | var item = $( | ||
| 17 | "<a href='#' class='related_asset_result'>" + | ||
| 18 | "<img src='" + asset.thumb_url + "' alt=''>" + | ||
| 19 | "<span>" + asset.name + "</span>" + | ||
| 20 | "</a>" | ||
| 21 | ); | ||
| 22 | item.bind("click", function() { | ||
| 23 | related_assets.attach(asset.id, createUrl, list); | ||
| 24 | return false; | ||
| 25 | }); | ||
| 26 | results.append(item); | ||
| 27 | found = true; | ||
| 28 | }); | ||
| 29 | return found; | ||
| 30 | } | ||
| 31 | }); | ||
| 32 | |||
| 33 | $(document).on("click", function(e) { | ||
| 34 | if (!$(e.target).closest("#related_assets").length) { | ||
| 35 | $("#related_asset_search_results").slideUp().empty(); | ||
| 36 | } | ||
| 37 | }); | ||
| 38 | |||
| 39 | list.sortable({ | ||
| 40 | handle: ".related_asset_handle", | ||
| 41 | update: function(event, ui) { | ||
| 42 | var newPosition = ui.item.index() + 1; // acts_as_list is 1-based; jQuery UI's index() is 0-based | ||
| 43 | $.ajax({ | ||
| 44 | type: "PATCH", | ||
| 45 | url: ui.item.data("url"), | ||
| 46 | data: "position=" + newPosition | ||
| 47 | }); | ||
| 48 | } | ||
| 49 | }); | ||
| 50 | |||
| 51 | list.on("click", ".related_asset_remove", function() { | ||
| 52 | var item = $(this).closest("li"); | ||
| 53 | $.ajax({ | ||
| 54 | type: "DELETE", | ||
| 55 | url: item.data("url"), | ||
| 56 | success: function() { | ||
| 57 | item.remove(); | ||
| 58 | } | ||
| 59 | }); | ||
| 60 | }); | ||
| 61 | }, | ||
| 62 | |||
| 63 | attach: function(assetId, createUrl, list) { | ||
| 64 | $.ajax({ | ||
| 65 | type: "POST", | ||
| 66 | url: createUrl, | ||
| 67 | data: "asset_id=" + assetId, | ||
| 68 | dataType: "json", | ||
| 69 | success: function(related) { | ||
| 70 | var item = $($("#related_asset_template").html().trim()); | ||
| 71 | item.attr("data-url", related.url); | ||
| 72 | item.find("img").attr("src", related.thumb_url); | ||
| 73 | list.append(item); | ||
| 74 | list.sortable("refresh"); | ||
| 75 | $("#related_asset_search_term").val(""); | ||
| 76 | $("#related_asset_search_results").slideUp().empty(); | ||
| 77 | } | ||
| 78 | }); | ||
| 79 | } | ||
| 80 | }; | ||
