Skip to content

Commit

Permalink
fix(lr-data-output): improve native form validation
Browse files Browse the repository at this point in the history
  • Loading branch information
nd0ut committed Oct 26, 2023
1 parent e54d8fa commit e7368b1
Show file tree
Hide file tree
Showing 2 changed files with 107 additions and 30 deletions.
91 changes: 61 additions & 30 deletions blocks/DataOutput/DataOutput.js
Original file line number Diff line number Diff line change
@@ -1,17 +1,27 @@
// @ts-check
import { UploaderBlock } from '../../abstract/UploaderBlock.js';
import { uploadFileGroup } from '@uploadcare/upload-client';
import { applyStyles } from '@symbiotejs/symbiote';

/** @typedef {import('@uploadcare/upload-client').UploadcareFile[]} FileList} */
/**
* @typedef {| import('../../types/exported.js').OutputFileEntry[]
* | {
* groupData: import('@uploadcare/upload-client').GroupInfo;
* files: import('../../types/exported.js').OutputFileEntry[];
* }} Output}
*/

export class DataOutput extends UploaderBlock {
processInnerHtml = true;
requireCtxName = true;

init$ = {
...this.init$,
output: null,
filesData: null,
};
constructor() {
super();
this.init$ = {
...this.init$,
output: null,
};
}

get dict() {
return DataOutput.dict;
Expand All @@ -28,22 +38,24 @@ export class DataOutput extends UploaderBlock {
this._dynamicInputsContainer = document.createElement('div');
this.appendChild(this._dynamicInputsContainer);

if (this.hasAttribute(this.dict.INPUT_REQUIRED)) {
let input = document.createElement('input');
input.type = 'text';
input.name = '__UPLOADCARE_VALIDATION_INPUT__';
input.required = true;
this.appendChild(input);
this._validationInputElement = input;
}
let input = document.createElement('input');
input.type = 'text';
input.name = '__UPLOADCARE_VALIDATION_INPUT__';
input.required = this.hasAttribute(this.dict.INPUT_REQUIRED);
input.tabIndex = -1;
applyStyles(input, {
opacity: 0,
height: 0,
width: 0,
});
this.appendChild(input);
this._validationInputElement = input;
}

this.sub(
'output',
/** @param {Output} data */
(data) => {
if (!data) {
return;
}
if (this.hasAttribute(this.dict.FIRE_EVENT_ATTR)) {
this.dispatchEvent(
new CustomEvent(this.dict.EVENT_NAME, {
Expand All @@ -58,18 +70,32 @@ export class DataOutput extends UploaderBlock {
);
}

if (this.hasAttribute(this.dict.FORM_INPUT_ATTR)) {
if (this.hasAttribute(this.dict.FORM_INPUT_ATTR) && this._dynamicInputsContainer) {
this._dynamicInputsContainer.innerHTML = '';
let values = data.groupData ? [data.groupData.cdnUrl] : data.map((file) => file.cdnUrl);
/** @type {string[]} */
let values;
if (Array.isArray(data)) {
values = data.map((file) => /** @type {string} */ (file.cdnUrl));
} else if (data?.groupData) {
values = [data.groupData.cdnUrl];
} else {
values = [];
}
for (let value of values) {
let input = document.createElement('input');
input.type = 'hidden';
input.name = this.getAttribute(this.dict.INPUT_NAME_ATTR) || this.ctxName;
input.value = value;
input.value = value ?? '';
this._dynamicInputsContainer.appendChild(input);
}
if (this.hasAttribute(this.dict.INPUT_REQUIRED)) {
if (this._validationInputElement) {
this._validationInputElement.value = values.length ? '__VALUE__' : '';
const msg = this.$['*message'];
if (msg?.isError) {
this._validationInputElement.setCustomValidity(`${msg.caption}. ${msg.text}`);
} else {
this._validationInputElement.setCustomValidity('');
}
}
}

Expand All @@ -82,21 +108,26 @@ export class DataOutput extends UploaderBlock {

this.sub(
this.dict.SRC_CTX_KEY,
async (/** @type {FileList} */ data) => {
if (!data) {
async (/** @type {import('../../types/exported.js').OutputFileEntry[]} */ data) => {
if (!data || !data.length) {
this.$.output = null;
this.$.filesData = null;
return;
}
this.$.filesData = data;
if (this.cfg.groupOutput || this.hasAttribute(this.dict.GROUP_ATTR)) {
const allUploaded = data.every((item) => item.isUploaded);
if (allUploaded && (this.cfg.groupOutput || this.hasAttribute(this.dict.GROUP_ATTR))) {
let uuidList = data.map((fileDesc) => {
return fileDesc.uuid;
return fileDesc.uuid + (fileDesc.cdnUrlModifiers ? `/${fileDesc.cdnUrlModifiers}` : '');
});
const validationOk = data.every((item) => item.isValid);
if (!validationOk) {
this.$.output = {
groupData: undefined,
files: data,
};
return;
}
const uploadClientOptions = await this.getUploadClientOptions();
let resp = await uploadFileGroup(uuidList, {
...uploadClientOptions,
});
const resp = await uploadFileGroup(uuidList, uploadClientOptions);
this.$.output = {
groupData: resp,
files: data,
Expand Down
46 changes: 46 additions & 0 deletions blocks/test/form.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<!DOCTYPE html>
<base href="../../" />

<head>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<script
async=""
src="https://cdn.skypack.dev/-/[email protected]/dist=es2020,mode=raw,min/dist/es-module-shims.js"
></script>
<script type="importmap">
{
"imports": {
"@symbiotejs/symbiote": "./node_modules/@symbiotejs/symbiote/build/symbiote.js",
"@uploadcare/upload-client": "./node_modules/@uploadcare/upload-client/dist/esm/index.browser.mjs"
}
}
</script>
<script type="module">
import * as LR from './index.js';
LR.registerBlocks(LR);

const form = document.querySelector('form');
form.addEventListener('submit', (e) => {
e.preventDefault();
console.log('SUBMIT', e.target);
});
</script>
</head>

<lr-config ctx-name="my-uploader" pubkey="demopublickey" multiple multiple-min="2" multiple-max="3"></lr-config>

<form>
<lr-file-uploader-regular style="position: relative; display: inline-block;" ctx-name="my-uploader" css-src="./blocks/themes/lr-basic/index.css">
<lr-data-output
style="position: absolute; bottom: 0px; left: 50%"
ctx-name="my-uploader"
use-console
use-input
input-required
use-group
></lr-data-output>
</lr-file-uploader-regular>
<br />
<br />
<button type="submit">Submit</button>
</form>

0 comments on commit e7368b1

Please sign in to comment.