summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorerdgeist <erdgeist@erdgeist.org>2026-07-19 22:19:22 +0200
committererdgeist <erdgeist@erdgeist.org>2026-07-19 22:19:22 +0200
commit08d02a8591ee8047cb708646092cd4bdb7492c33 (patch)
tree6b98f8e2d8f98f728394215da57bc9a08de56818
parent318c0ec9793beba1a6ac0e18168c774fce15dd37 (diff)
Add copy-url button to assets; unified the mechanism across views
-rw-r--r--app/views/assets/show.html.erb10
-rw-r--r--app/views/nodes/new.html.erb5
-rw-r--r--public/javascripts/admin_interface.js21
-rw-r--r--public/javascripts/admin_search.js6
4 files changed, 34 insertions, 8 deletions
diff --git a/app/views/assets/show.html.erb b/app/views/assets/show.html.erb
index 5717dd9..ff00883 100644
--- a/app/views/assets/show.html.erb
+++ b/app/views/assets/show.html.erb
@@ -20,7 +20,15 @@
20 <div class="node_content"><%= image_tag @asset.upload.url(:medium), style: "max-width: 300px; max-height: 300px;" %></div> 20 <div class="node_content"><%= image_tag @asset.upload.url(:medium), style: "max-width: 300px; max-height: 300px;" %></div>
21 21
22 <div class="node_description">Public Path</div> 22 <div class="node_description">Public Path</div>
23 <div class="node_content"><%= @asset.upload.url.sub(/\?\d+$/, "") %></div> 23 <div class="node_content">
24 <% public_path = @asset.upload.url.sub(/\?\d+$/, "") %>
25 <%= link_to public_path, public_path, target: "_blank", rel: "noopener" %>
26 <button type="button" class="action_button copy_button"
27 data-copy-url="<%= request.base_url + public_path %>">
28 <%= icon("copy", library: "tabler", "aria-hidden": true) %>
29 <span class="copy_button_label">Copy URL</span>
30 </button>
31 </div>
24 32
25 <div class="node_description">Content Type</div> 33 <div class="node_description">Content Type</div>
26 <div class="node_content"><%= @asset.upload.content_type %></div> 34 <div class="node_content"><%= @asset.upload.content_type %></div>
diff --git a/app/views/nodes/new.html.erb b/app/views/nodes/new.html.erb
index 890d46e..805fbc9 100644
--- a/app/views/nodes/new.html.erb
+++ b/app/views/nodes/new.html.erb
@@ -41,7 +41,10 @@
41 <div class="node_description">Resulting path</div> 41 <div class="node_description">Resulting path</div>
42 <div class="node_content"> 42 <div class="node_content">
43 <span id="resulting_path">—</span> 43 <span id="resulting_path">—</span>
44 <button type="button" id="copy_resulting_path" class="unselected">copy</button> 44 <button type="button" id="copy_resulting_path" class="unselected copy_button" data-copy-target="#resulting_path">
45 <span class="copy_button_label">copy</span>
46 </button>
47
45 <span class="field_hint">This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it).</span> 48 <span class="field_hint">This preview updates as you type. The final path can still be changed afterward by editing the title (for the last segment) or moving the node to a different parent (for everything before it).</span>
46 </div> 49 </div>
47 50
diff --git a/public/javascripts/admin_interface.js b/public/javascripts/admin_interface.js
index b7bdc10..e9f96c2 100644
--- a/public/javascripts/admin_interface.js
+++ b/public/javascripts/admin_interface.js
@@ -86,6 +86,27 @@ $(document).ready(function () {
86 if (meta) request.setRequestHeader("X-CSRF-Token", meta.content); 86 if (meta) request.setRequestHeader("X-CSRF-Token", meta.content);
87 }); 87 });
88 88
89 document.addEventListener('click', function (event) {
90 var button = event.target.closest('.copy_button');
91 if (!button) return;
92
93 var text = button.dataset.copyUrl;
94 if (text === undefined && button.dataset.copyTarget) {
95 var target = document.querySelector(button.dataset.copyTarget);
96 text = target ? target.textContent : undefined;
97 }
98
99 if (!text || text === '—' || !navigator.clipboard) return;
100
101 navigator.clipboard.writeText(text).then(function () {
102 var label = button.querySelector('.copy_button_label');
103 if (!label) return;
104 var original = label.textContent;
105 label.textContent = 'Copied!';
106 setTimeout(function () { label.textContent = original; }, 1500);
107 });
108 });
109
89}); 110});
90 111
91 112
diff --git a/public/javascripts/admin_search.js b/public/javascripts/admin_search.js
index b53c931..ad368cb 100644
--- a/public/javascripts/admin_search.js
+++ b/public/javascripts/admin_search.js
@@ -202,12 +202,6 @@ parent_search = {
202 $("#title").bind("input", function() { 202 $("#title").bind("input", function() {
203 parent_search.update_resulting_path(); 203 parent_search.update_resulting_path();
204 }); 204 });
205
206 $("#copy_resulting_path").bind("click", function() {
207 var path = $("#resulting_path").text();
208 if (path === "—" || !navigator.clipboard) return;
209 navigator.clipboard.writeText(path);
210 });
211 }, 205 },
212 206
213 update_resulting_path : function() { 207 update_resulting_path : function() {