mirror of
https://github.com/simonw/datasette.git
synced 2026-05-27 20:36:17 +02:00
Support multi-line parameters on /db/-/execute-write
Refs https://github.com/simonw/datasette/issues/2742#issuecomment-4536317049 Each paramater input now has an expand/collapse button toggle to turn into a textarea. If you paste text that includes at least one newline it toggles automatically.
This commit is contained in:
parent
1bce34a338
commit
66bbbbc947
2 changed files with 94 additions and 1 deletions
|
|
@ -74,6 +74,25 @@
|
|||
color: #b00020;
|
||||
font-weight: 700;
|
||||
}
|
||||
form.sql .execute-write-parameter-row textarea[data-parameter-control] {
|
||||
border: 1px solid #ccc;
|
||||
border-radius: 3px;
|
||||
box-sizing: content-box;
|
||||
display: inline-block;
|
||||
font-family: Helvetica, sans-serif;
|
||||
font-size: 1em;
|
||||
min-height: 7rem;
|
||||
padding: 9px 4px;
|
||||
vertical-align: top;
|
||||
width: 60%;
|
||||
}
|
||||
form.sql.core button.execute-write-parameter-toggle[type=button] {
|
||||
font-size: 0.72rem;
|
||||
height: 1.8rem;
|
||||
line-height: 1;
|
||||
margin-left: 0.35rem;
|
||||
padding: 0.25rem 0.45rem;
|
||||
}
|
||||
</style>
|
||||
{% endblock %}
|
||||
|
||||
|
|
@ -118,7 +137,7 @@
|
|||
{% if parameter_names %}
|
||||
<h2>Parameters</h2>
|
||||
{% for parameter in parameter_names %}
|
||||
<p><label for="qp{{ loop.index }}">{{ parameter }}</label> <input type="text" id="qp{{ loop.index }}" name="{{ parameter }}" value="{{ parameter_values.get(parameter, "") }}"></p>
|
||||
<p class="execute-write-parameter-row"><label for="qp{{ loop.index }}">{{ parameter }}</label> <input type="text" id="qp{{ loop.index }}" name="{{ parameter }}" value="{{ parameter_values.get(parameter, "") }}" data-parameter-control> <button type="button" class="execute-write-parameter-toggle" data-parameter-toggle aria-controls="qp{{ loop.index }}" aria-expanded="false">Expand</button></p>
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
|
||||
|
|
@ -164,6 +183,79 @@ if (executeWriteSqlInput && !executeWriteSqlInput.value) {
|
|||
|
||||
{% include "_codemirror_foot.html" %}
|
||||
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
function replaceParameterControl(control, button, expand, value, selectionStart) {
|
||||
const replacement = document.createElement(expand ? "textarea" : "input");
|
||||
replacement.id = control.id;
|
||||
replacement.name = control.name;
|
||||
replacement.value = value === undefined ? control.value : value;
|
||||
replacement.setAttribute("data-parameter-control", "");
|
||||
if (expand) {
|
||||
replacement.rows = 5;
|
||||
button.textContent = "Collapse";
|
||||
button.setAttribute("aria-expanded", "true");
|
||||
} else {
|
||||
replacement.type = "text";
|
||||
button.textContent = "Expand";
|
||||
button.setAttribute("aria-expanded", "false");
|
||||
}
|
||||
control.replaceWith(replacement);
|
||||
replacement.focus();
|
||||
if (selectionStart !== undefined && replacement.setSelectionRange) {
|
||||
replacement.setSelectionRange(selectionStart, selectionStart);
|
||||
}
|
||||
}
|
||||
|
||||
document.querySelectorAll("[data-parameter-toggle]").forEach((button) => {
|
||||
button.addEventListener("click", () => {
|
||||
const control = document.getElementById(button.getAttribute("aria-controls"));
|
||||
if (!control) {
|
||||
return;
|
||||
}
|
||||
const expanded = control.tagName.toLowerCase() === "textarea";
|
||||
replaceParameterControl(control, button, !expanded);
|
||||
});
|
||||
});
|
||||
|
||||
document
|
||||
.querySelector("form.sql.core")
|
||||
.addEventListener("paste", (event) => {
|
||||
const control = event.target;
|
||||
if (
|
||||
!(control instanceof HTMLInputElement) ||
|
||||
!control.matches("[data-parameter-control]")
|
||||
) {
|
||||
return;
|
||||
}
|
||||
const pasted = event.clipboardData ? event.clipboardData.getData("text") : "";
|
||||
if (!/[\r\n]/.test(pasted)) {
|
||||
return;
|
||||
}
|
||||
const button = document.querySelector(
|
||||
`[data-parameter-toggle][aria-controls="${control.id}"]`
|
||||
);
|
||||
if (!button) {
|
||||
return;
|
||||
}
|
||||
event.preventDefault();
|
||||
const selectionStart = control.selectionStart ?? control.value.length;
|
||||
const selectionEnd = control.selectionEnd ?? selectionStart;
|
||||
const value =
|
||||
control.value.slice(0, selectionStart) +
|
||||
pasted +
|
||||
control.value.slice(selectionEnd);
|
||||
replaceParameterControl(
|
||||
control,
|
||||
button,
|
||||
true,
|
||||
value,
|
||||
selectionStart + pasted.length
|
||||
);
|
||||
});
|
||||
});
|
||||
</script>
|
||||
|
||||
{% if write_template_tables %}
|
||||
<script>
|
||||
window.addEventListener("DOMContentLoaded", () => {
|
||||
|
|
|
|||
|
|
@ -719,6 +719,7 @@ async def test_execute_write_get_prepopulates_without_executing():
|
|||
assert 'data-sql-template="insert"' in response.text
|
||||
assert 'data-sql-template="update"' in response.text
|
||||
assert 'data-sql-template="delete"' in response.text
|
||||
assert 'addEventListener("paste"' in response.text
|
||||
assert '<table class="execute-write-analysis">' in response.text
|
||||
assert '<th scope="col">Required permission</th>' in response.text
|
||||
assert "<td><code>insert</code></td>" in response.text
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue