Skip to content

Commit e9638a6

Browse files
authored
Merge pull request #54 from zopefoundation/codemonkey440/rendered_sql_clipboard_copy_button
Add "Copy to clipboard" button to the ZMI `Test` tab
2 parents 81d89fe + 6d9ee0c commit e9638a6

File tree

2 files changed

+60
-23
lines changed

2 files changed

+60
-23
lines changed

CHANGES.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,10 @@ Changelog
44
5.1 (unreleased)
55
----------------
66

7+
- Add "Copy to clipboard" button to the ZMI `Test` tab.
8+
The button copies the rendered SQL output to the user's clipboard.
9+
(`#53 <https://github.com/zopefoundation/Products.ZSQLMethods/issues/53>`_)
10+
711
- Move package metadata from setup.py to pyproject.toml.
812

913

src/Shared/DC/ZRDB/dtml/test.dtml

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,14 @@
44
<dtml-var manage_tabs>
55
</dtml-with>
66

7+
<style>
8+
button#copyToClipboard {
9+
position: absolute;
10+
right: 1rem;
11+
z-index: 10;
12+
}
13+
</style>
14+
715
<main class="container-fluid">
816

917
<dtml-let num_rows="REQUEST.get('num_rows') or 20">
@@ -25,12 +33,13 @@
2533
</p>
2634
<dtml-in args mapping>
2735
<div class="form-group row">
28-
<label for="&dtml-name;"
29-
class="form-label col-sm-3 col-md-2">&dtml-name;</label>
30-
31-
<dtml-let typ="type or REQUEST.get('%s_type' % name, 'string')">
32-
<div class="col-sm-3 col-md-2">
33-
<select name="&dtml-name;_type" class="form-control">
36+
<div class="input-group col">
37+
<label for="&dtml-name;"
38+
class="form-control col-sm-3 col-md-2 input-group-text bg-light">
39+
<code>&dtml-name;</code>
40+
</label>
41+
<dtml-let typ="type or REQUEST.get('%s_type' % name, 'string')">
42+
<select name="&dtml-name;_type" class="form-control col-sm-3 col-md-2">
3443
<option <dtml-if "typ == 'float'">selected</dtml-if>>
3544
float
3645
</option>
@@ -44,14 +53,11 @@
4453
tokens
4554
</option>
4655
</select>
47-
</div>
48-
</dtml-let>
49-
50-
<div class="col-sm-6 col-md-7">
51-
<input type="text" class="form-control" size="40"
52-
name="&dtml-name;"
53-
id="&dtml-name;"
54-
value="<dtml-var "REQUEST.get(name, default)">"/>
56+
</dtml-let>
57+
<input type="text" class="form-control"
58+
name="&dtml-name;"
59+
id="&dtml-name;"
60+
value="<dtml-var "REQUEST.get(name, default)">"/>
5561
</div>
5662
</div>
5763
</dtml-in>
@@ -62,10 +68,12 @@
6268
</dtml-let>
6369

6470
<div class="form-group row">
65-
<label for="num_rows"
66-
class="form-label col-sm-3 col-md-2">Rows per page</label>
67-
<div class="col-sm-3 col-md-2">
68-
<select name="num_rows" class="form-control">
71+
<div class="input-group col">
72+
<label for="num_rows"
73+
class="form-control col-sm-3 col-md-2 input-group-text bg-light text-muted">
74+
Rows per page
75+
</label>
76+
<select name="num_rows" class="form-control col-sm-3 col-md-2">
6977
<dtml-in "[10, 20, 50, 100, 500, 1000]">
7078
<option <dtml-if "_.int(num_rows)==_['sequence-item']">selected</dtml-if>>
7179
<dtml-var sequence-item>
@@ -92,7 +100,11 @@
92100
The final query sent to the database may contain additional
93101
elements inserted automatically, such as a <em>LIMIT</em> clause.
94102
</p>
95-
<pre class="form-control code col-sm-12 bg-dark text-white small border-0"
103+
<button type="button" class="btn btn-secondary mt-0"
104+
id="copyToClipboard" title="Copy to Clipboard">
105+
<i class="fas fa-copy"></i>
106+
</button>
107+
<pre class="form-control code col-sm-12 bg-dark text-white small border-dark"
96108
name="template:text" data-contenttype="sql"
97109
><dtml-var "this().manage_zmi_test(REQUEST, src__=1)" html_quote></pre>
98110

@@ -192,11 +204,32 @@
192204
</dtml-try>
193205

194206
<script>
195-
$(function() {
196-
editor.setOptions({
197-
'readOnly': true,
207+
$(function() {
208+
try {
209+
editor.setOptions({
210+
'readOnly': true,
211+
});
212+
} catch (err) {
213+
// Ignore
214+
}
215+
$('#copyToClipboard').on('click', function(e) {
216+
const $icon = $(e.currentTarget).find('i');
217+
const tempInput = document.createElement('textarea');
218+
tempInput.value = document.querySelector('pre[name="template:text"]').innerText;
219+
document.body.appendChild(tempInput);
220+
tempInput.select();
221+
try {
222+
document.execCommand('copy');
223+
$icon.removeClass('fa-copy').addClass('fa-check');
224+
setTimeout(function() {
225+
$icon.removeClass('fa-check').addClass('fa-copy');
226+
}, 2000);
227+
} catch (err) {
228+
alert('Failed to copy text: ' + err);
229+
}
230+
document.body.removeChild(tempInput);
231+
});
198232
});
199-
});
200233
</script>
201234

202235
<dtml-except>

0 commit comments

Comments
 (0)