(core) Form kanban tasks

Summary:
- Open all links in a new tab
- Excluding not filled columns (to fix trigger formulas)
- Fixed Ref/RefList submission
- Removing redundant type definitions for Box
- Adding header menu item
- Default empty values in select control

Test Plan: Updated

Reviewers: georgegevoian

Reviewed By: georgegevoian

Differential Revision: https://phab.getgrist.com/D4166
This commit is contained in:
Jarosław Sadziński
2024-01-23 21:52:57 +01:00
parent 007c4492dc
commit 95c0441d84
22 changed files with 363 additions and 124 deletions

19
static/forms/README.md Normal file
View File

@@ -0,0 +1,19 @@
## grist-form-submit.js
File is taken from https://github.com/gristlabs/grist-form-submit. But it is modified to work with
forms, especially for:
- Ref and RefList columns, as by default it sends numbers as strings (FormData issue), and Grist
doesn't know how to convert them back to numbers.
- Empty strings are not sent at all - otherwise Grist won't be able to fire trigger formulas
correctly and provide default values for columns.
- By default it requires a redirect URL, now it is optional.
## purify.min.js
File taken from https://www.npmjs.com/package/dompurify. It is used to sanitize HTML. It wasn't
modified at all.
## form.html
This is handlebars template filled by DocApi.ts

View File

@@ -9,6 +9,15 @@
</style>
<script src="forms/grist-form-submit.js"></script>
<script src="forms/purify.min.js"></script>
<script>
// Make all links open in a new tab.
DOMPurify.addHook('uponSanitizeAttribute', (node) => {
if (!('target' in node)) { return; }
node.setAttribute('target', '_blank');
// Make sure that this is set explicitly, as it's often set by the browser.
node.setAttribute('rel', 'noopener');
});
</script>
<link rel="stylesheet" href="forms/form.css">
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
@@ -43,7 +52,7 @@
document.querySelector('.grist-form input[type="submit"]').addEventListener('click', function(event) {
// When submit is pressed make sure that all choice lists that are required
// have at least one option selected
const choiceLists = document.querySelectorAll('.grist-choice-list.required:not(:has(input:checked))');
const choiceLists = document.querySelectorAll('.grist-checkbox-list.required:not(:has(input:checked))');
Array.from(choiceLists).forEach(function(choiceList) {
// If the form has at least one checkbox make it required
const firstCheckbox = choiceList.querySelector('input[type="checkbox"]');
@@ -51,7 +60,7 @@
});
// All other required choice lists with at least one option selected are no longer required
const choiceListsRequired = document.querySelectorAll('.grist-choice-list.required:has(input:checked)');
const choiceListsRequired = document.querySelectorAll('.grist-checkbox-list.required:has(input:checked)');
Array.from(choiceListsRequired).forEach(function(choiceList) {
// If the form has at least one checkbox make it required
const firstCheckbox = choiceList.querySelector('input[type="checkbox"]');

View File

@@ -69,7 +69,19 @@ class TypedFormData {
this._formData = formData ?? new FormData(formElement);
this._formElement = formElement;
}
keys() { return this._formData.keys(); }
keys() {
const keys = Array.from(this._formData.keys());
// Don't return keys for scalar values which just return empty string.
// Otherwise Grist won't fire trigger formulas.
return keys.filter(key => {
// If there are multiple values, return this key as it is.
if (this._formData.getAll(key).length !== 1) { return true; }
// If the value is empty string or null, don't return the key.
const value = this._formData.get(key);
return value !== '' && value !== null;
});
}
type(key) {
return this._formElement?.querySelector(`[name="${key}"]`)?.getAttribute('data-grist-type');
}

View File

@@ -80,6 +80,7 @@
--icon-FunctionResult: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTQsMiBMMTIsMiBDMTMuMTA0NTY5NSwyIDE0LDIuODk1NDMwNSAxNCw0IEwxNCwxMiBDMTQsMTMuMTA0NTY5NSAxMy4xMDQ1Njk1LDE0IDEyLDE0IEw0LDE0IEMyLjg5NTQzMDUsMTQgMiwxMy4xMDQ1Njk1IDIsMTIgTDIsNCBDMiwyLjg5NTQzMDUgMi44OTU0MzA1LDIgNCwyIFogTTQuNSw2IEM0LjIyMzg1NzYzLDYgNCw2LjIyMzg1NzYzIDQsNi41IEM0LDYuNzc2MTQyMzcgNC4yMjM4NTc2Myw3IDQuNSw3IEwxMS41LDcgQzExLjc3NjE0MjQsNyAxMiw2Ljc3NjE0MjM3IDEyLDYuNSBDMTIsNi4yMjM4NTc2MyAxMS43NzYxNDI0LDYgMTEuNSw2IEw0LjUsNiBaIE00LjUsOSBDNC4yMjM4NTc2Myw5IDQsOS4yMjM4NTc2MyA0LDkuNSBDNCw5Ljc3NjE0MjM3IDQuMjIzODU3NjMsMTAgNC41LDEwIEwxMS41LDEwIEMxMS43NzYxNDI0LDEwIDEyLDkuNzc2MTQyMzcgMTIsOS41IEMxMiw5LjIyMzg1NzYzIDExLjc3NjE0MjQsOSAxMS41LDkgTDQuNSw5IFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
--icon-GreenArrow: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iOTQiIGhlaWdodD0iMTIiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTk0IDZMODQgMC4yMjY0OTdWMTEuNzczNUw5NCA2Wk0wIDdINC43VjVIMFY3Wk0xNC4xIDdIMjMuNVY1SDE0LjFWN1pNMzIuOSA3SDQyLjNWNUgzMi45VjdaTTUxLjcgN0g2MS4xVjVINTEuN1Y3Wk03MC41IDdINzkuOVY1SDcwLjVWN1oiIGZpbGw9IiMxNkIzNzgiLz48L3N2Zz4=');
--icon-Grow: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTEuNSAxLjVMNi41IDYuNU05LjUgOS41TDE0LjUgMTQuNU03LjUgMS41SDEuNVY3LjVNMTQuNSA4LjVWMTQuNUg4LjUiIHN0cm9rZT0iIzkyOTI5OSIgc3Ryb2tlLW1pdGVybGltaXQ9IjEwIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiLz48L3N2Zz4=');
--icon-Headband: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzEwNjFfNzU4NSkiPjxwYXRoIGQ9Ik0xNCAxNkw4IDExTDIgMTZWMEgxNFYxNloiIGZpbGw9IiMwMDAiLz48L2c+PGRlZnM+PGNsaXBQYXRoIGlkPSJjbGlwMF8xMDYxXzc1ODUiPjxwYXRoIGZpbGw9IiNmZmYiIGQ9Ik0wIDBIMTZWMTZIMHoiLz48L2NsaXBQYXRoPjwvZGVmcz48L3N2Zz4=');
--icon-Heart: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTciIGhlaWdodD0iMTciIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgY2xpcC1wYXRoPSJ1cmwoI2NsaXAwXzg0Nl8xNTQxOSkiPjxwYXRoIGQ9Ik03LjY4NTY0IDE1Ljk5OUM2Ljg4NTY0IDE1LjI5OSAwLjI4NTY0NSA5Ljc5OTAxIDAuMjg1NjQ1IDUuNTk5MDFDMC4yODU2NDUgMi44OTkwMSAyLjQ4NTY0IDAuNzk5MDExIDUuMDg1NjQgMC43OTkwMTFDNi4yODU2NCAwLjc5OTAxMSA3LjM4NTY0IDEuMjk5MDEgOC4yODU2NCAxLjk5OTAxQzkuMTg1NjQgMS4xOTkwMSAxMC4yODU2IDAuNzk5MDExIDExLjQ4NTYgMC43OTkwMTFDMTQuMTg1NiAwLjc5OTAxMSAxNi4yODU2IDIuOTk5MDEgMTYuMjg1NiA1LjU5OTAxQzE2LjI4NTYgOS43OTkwMSA5LjY4NTY1IDE1LjI5OSA4Ljg4NTY0IDE1Ljg5OUM4LjU4NTY0IDE2LjI5OSA3Ljk4NTY0IDE2LjI5OSA3LjY4NTY0IDE1Ljk5OVpNNS4wODU2NCAyLjc5OTAxQzMuNTg1NjQgMi43OTkwMSAyLjI4NTY0IDQuMDk5MDEgMi4yODU2NCA1LjU5OTAxQzIuMjg1NjQgNy43OTkwMSA1Ljc4NTY0IDExLjU5OSA4LjI4NTY0IDEzLjc5OUMxMC4zODU2IDExLjg5OSAxNC4yODU2IDcuOTk5MDEgMTQuMjg1NiA1LjU5OTAxQzE0LjI4NTYgMy45OTkwMSAxMi45ODU2IDIuNzk5MDEgMTEuNDg1NiAyLjc5OTAxQzEwLjU4NTYgMi43OTkwMSA5LjY4NTY0IDMuMjk5MDEgOS4xODU2NCA0LjA5OTAxQzguNzg1NjQgNC42OTkwMSA3Ljg4NTY0IDQuNjk5MDEgNy40ODU2NCA0LjA5OTAxQzYuODg1NjQgMy4yOTkwMSA2LjA4NTY0IDIuNzk5MDEgNS4wODU2NCAyLjc5OTAxWiIgZmlsbD0iIzE2QjM3OCIvPjwvZz48ZGVmcz48Y2xpcFBhdGggaWQ9ImNsaXAwXzg0Nl8xNTQxOSI+PHBhdGggZmlsbD0iI2ZmZiIgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLjI4NiAuNDk5KSIgZD0iTTAgMEgxNlYxNkgweiIvPjwvY2xpcFBhdGg+PC9kZWZzPjwvc3ZnPg==');
--icon-Help: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTIuNzA5MjY0NDMsMy40MTYzNzEyMSBDMS42NDQ0MDc2OSw0LjY0NDQzMjIyIDEsNi4yNDY5NjEzNyAxLDggQzEsOS43NTMwMzg2MyAxLjY0NDQwNzY5LDExLjM1NTU2NzggMi43MDkyNjQ0MywxMi41ODM2Mjg4IEw0Ljg0MDA3MTI5LDEwLjQ1MjgyMTkgQzQuMzEzNTQwOCw5Ljc3NTQ4MDA3IDQsOC45MjQzNTU3MyA0LDggQzQsNy4wNzU2NDQyNyA0LjMxMzU0MDgsNi4yMjQ1MTk5MyA0Ljg0MDA3MTI5LDUuNTQ3MTc4MDcgTDIuNzA5MjY0NDMsMy40MTYzNzEyMSBaIE0zLjQxNjM3MTIxLDIuNzA5MjY0NDMgTDUuNTQ3MTc4MDcsNC44NDAwNzEyOSBDNi4yMjQ1MTk5Myw0LjMxMzU0MDggNy4wNzU2NDQyNyw0IDgsNCBDOC45MjQzNTU3Myw0IDkuNzc1NDgwMDcsNC4zMTM1NDA4IDEwLjQ1MjgyMTksNC44NDAwNzEyOSBMMTIuNTgzNjI4OCwyLjcwOTI2NDQzIEMxMS4zNTU1Njc4LDEuNjQ0NDA3NjkgOS43NTMwMzg2MywxIDgsMSBDNi4yNDY5NjEzNywxIDQuNjQ0NDMyMjIsMS42NDQ0MDc2OSAzLjQxNjM3MTIxLDIuNzA5MjY0NDMgWiBNNS45MDE5ODczMSw1Ljg1NTYyMzc2IEM1Ljg5NDgyMDAxLDUuODYzNzgzMDcgNS44ODczNDIwNCw1Ljg3MTc2NDc0IDUuODc5NTUzMzksNS44Nzk1NTMzOSBDNS44NzE3NjQ3NCw1Ljg4NzM0MjA0IDUuODYzNzgzMDcsNS44OTQ4MjAwMSA1Ljg1NTYyMzc2LDUuOTAxOTg3MzEgQzUuMzI2Mjk1NSw2LjQ0MjkzOTMyIDUsNy4xODMzNjQ0NiA1LDggQzUsOC44MTY2MzU1NCA1LjMyNjI5NTUsOS41NTcwNjA2OCA1Ljg1NTYyMzc2LDEwLjA5ODAxMjcgQzUuODYzNzgzMDcsMTAuMTA1MTggNS44NzE3NjQ3NCwxMC4xMTI2NTggNS44Nzk1NTMzOSwxMC4xMjA0NDY2IEM1Ljg4NzM0MjA0LDEwLjEyODIzNTMgNS44OTQ4MjAwMSwxMC4xMzYyMTY5IDUuOTAxOTg3MzEsMTAuMTQ0Mzc2MiBDNi40NDI5MzkzMiwxMC42NzM3MDQ1IDcuMTgzMzY0NDYsMTEgOCwxMSBDOC44MTY2MzU1NCwxMSA5LjU1NzA2MDY4LDEwLjY3MzcwNDUgMTAuMDk4MDEyNywxMC4xNDQzNzYyIEMxMC4xMDUxOCwxMC4xMzYyMTY5IDEwLjExMjY1OCwxMC4xMjgyMzUzIDEwLjEyMDQ0NjYsMTAuMTIwNDQ2NiBDMTAuMTI4MjM1MywxMC4xMTI2NTggMTAuMTM2MjE2OSwxMC4xMDUxOCAxMC4xNDQzNzYyLDEwLjA5ODAxMjcgQzEwLjY3MzcwNDUsOS41NTcwNjA2OCAxMSw4LjgxNjYzNTU0IDExLDggQzExLDcuMTgzMzY0NDYgMTAuNjczNzA0NSw2LjQ0MjkzOTMyIDEwLjE0NDM3NjIsNS45MDE5ODczMSBDMTAuMTM2MjE2OSw1Ljg5NDgyMDAxIDEwLjEyODIzNTMsNS44ODczNDIwNCAxMC4xMjA0NDY2LDUuODc5NTUzMzkgQzEwLjExMjY1OCw1Ljg3MTc2NDc0IDEwLjEwNTE4LDUuODYzNzgzMDcgMTAuMDk4MDEyNyw1Ljg1NTYyMzc2IEM5LjU1NzA2MDY4LDUuMzI2Mjk1NSA4LjgxNjYzNTU0LDUgOCw1IEM3LjE4MzM2NDQ2LDUgNi40NDI5MzkzMiw1LjMyNjI5NTUgNS45MDE5ODczMSw1Ljg1NTYyMzc2IFogTTMuNDE2MzcxMjEsMTMuMjkwNzM1NiBDNC42NDQ0MzIyMiwxNC4zNTU1OTIzIDYuMjQ2OTYxMzcsMTUgOCwxNSBDOS43NTMwMzg2MywxNSAxMS4zNTU1Njc4LDE0LjM1NTU5MjMgMTIuNTgzNjI4OCwxMy4yOTA3MzU2IEwxMC40NTI4MjE5LDExLjE1OTkyODcgQzkuNzc1NDgwMDcsMTEuNjg2NDU5MiA4LjkyNDM1NTczLDEyIDgsMTIgQzcuMDc1NjQ0MjcsMTIgNi4yMjQ1MTk5MywxMS42ODY0NTkyIDUuNTQ3MTc4MDcsMTEuMTU5OTI4NyBMMy40MTYzNzEyMSwxMy4yOTA3MzU2IFogTTEzLjI5MDczNTYsMTIuNTgzNjI4OCBDMTQuMzU1NTkyMywxMS4zNTU1Njc4IDE1LDkuNzUzMDM4NjMgMTUsOCBDMTUsNi4yNDY5NjEzNyAxNC4zNTU1OTIzLDQuNjQ0NDMyMjIgMTMuMjkwNzM1NiwzLjQxNjM3MTIxIEwxMS4xNTk5Mjg3LDUuNTQ3MTc4MDcgQzExLjY4NjQ1OTIsNi4yMjQ1MTk5MyAxMiw3LjA3NTY0NDI3IDEyLDggQzEyLDguOTI0MzU1NzMgMTEuNjg2NDU5Miw5Ljc3NTQ4MDA3IDExLjE1OTkyODcsMTAuNDUyODIxOSBMMTMuMjkwNzM1NiwxMi41ODM2Mjg4IFogTTgsMTYgQzMuNTgxNzIyLDE2IDAsMTIuNDE4Mjc4IDAsOCBDMCwzLjU4MTcyMiAzLjU4MTcyMiwwIDgsMCBDMTIuNDE4Mjc4LDAgMTYsMy41ODE3MjIgMTYsOCBDMTYsMTIuNDE4Mjc4IDEyLjQxODI3OCwxNiA4LDE2IFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');
--icon-Home: url('data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTYiIGhlaWdodD0iMTYiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PHBhdGggZD0iTTgsMi4wODMwOTUxOSBMMS40NzE4MjUzMiw2IEw4LDkuOTE2OTA0ODEgTDE0LjUyODE3NDcsNiBMOCwyLjA4MzA5NTE5IFogTTguMjU3MjQ3ODgsMS4wNzEyNTM1NCBMMTUuNzU3MjQ3OSw1LjU3MTI1MzU0IEMxNi4wODA5MTc0LDUuNzY1NDU1MjMgMTYuMDgwOTE3NCw2LjIzNDU0NDc3IDE1Ljc1NzI0NzksNi40Mjg3NDY0NiBMOC4yNTcyNDc4OCwxMC45Mjg3NDY1IEM4LjA5ODkwNjY4LDExLjAyMzc1MTIgNy45MDEwOTMzMiwxMS4wMjM3NTEyIDcuNzQyNzUyMTIsMTAuOTI4NzQ2NSBMMC4yNDI3NTIxMjIsNi40Mjg3NDY0NiBDLTAuMDgwOTE3Mzc0MSw2LjIzNDU0NDc3IC0wLjA4MDkxNzM3NDEsNS43NjU0NTUyMyAwLjI0Mjc1MjEyMiw1LjU3MTI1MzU0IEw3Ljc0Mjc1MjEyLDEuMDcxMjUzNTQgQzcuOTAxMDkzMzIsMC45NzYyNDg4MjEgOC4wOTg5MDY2OCwwLjk3NjI0ODgyMSA4LjI1NzI0Nzg4LDEuMDcxMjUzNTQgWiBNMTQuNTI4MTc0NywxMCBMMTMuNzQyNzUyMSw5LjUyODc0NjQ2IEMxMy41MDU5NjIsOS4zODY2NzIzOCAxMy40MjkxNzk1LDkuMDc5NTQyMjYgMTMuNTcxMjUzNSw4Ljg0Mjc1MjEyIEMxMy43MTMzMjc2LDguNjA1OTYxOTkgMTQuMDIwNDU3Nyw4LjUyOTE3OTQ2IDE0LjI1NzI0NzksOC42NzEyNTM1NCBMMTUuNzU3MjQ3OSw5LjU3MTI1MzU0IEMxNi4wODA5MTc0LDkuNzY1NDU1MjMgMTYuMDgwOTE3NCwxMC4yMzQ1NDQ4IDE1Ljc1NzI0NzksMTAuNDI4NzQ2NSBMOC4yNTcyNDc4OCwxNC45Mjg3NDY1IEM4LjA5ODkwNjY4LDE1LjAyMzc1MTIgNy45MDEwOTMzMiwxNS4wMjM3NTEyIDcuNzQyNzUyMTIsMTQuOTI4NzQ2NSBMMC4yNDI3NTIxMjIsMTAuNDI4NzQ2NSBDLTAuMDgwOTE3Mzc0MSwxMC4yMzQ1NDQ4IC0wLjA4MDkxNzM3NDEsOS43NjU0NTUyMyAwLjI0Mjc1MjEyMiw5LjU3MTI1MzU0IEwxLjc0Mjc1MjEyLDguNjcxMjUzNTQgQzEuOTc5NTQyMjYsOC41MjkxNzk0NiAyLjI4NjY3MjM4LDguNjA1OTYxOTkgMi40Mjg3NDY0Niw4Ljg0Mjc1MjEyIEMyLjU3MDgyMDU0LDkuMDc5NTQyMjYgMi40OTQwMzgwMSw5LjM4NjY3MjM4IDIuMjU3MjQ3ODgsOS41Mjg3NDY0NiBMMS40NzE4MjUzMiwxMCBMOCwxMy45MTY5MDQ4IEwxNC41MjgxNzQ3LDEwIFoiIGZpbGw9IiMwMDAiIGZpbGwtcnVsZT0ibm9uemVybyIvPjwvc3ZnPg==');

View File

@@ -0,0 +1,10 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1061_7585)">
<path d="M14 16L8 11L2 16V0H14V16Z" fill="black"/>
</g>
<defs>
<clipPath id="clip0_1061_7585">
<rect width="16" height="16" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 300 B