mirror of
https://codeberg.org/icewind/ptouch-api.git
synced 2026-06-03 19:04:08 +02:00
element helper
This commit is contained in:
parent
20060fefe0
commit
0c4bbbe3e4
1 changed files with 134 additions and 75 deletions
203
web/label.js
203
web/label.js
|
|
@ -27,70 +27,122 @@ const nextElementId = () => {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @typedef ElementSpec
|
||||||
|
* @type {object}
|
||||||
|
* @property {string} tag
|
||||||
|
* @property {Object.<string, string>} props
|
||||||
|
* @property {Object.<string, string>} attributes
|
||||||
|
* @property {Object.<string, any>} data
|
||||||
|
* @property {Object.<string, Function>} events
|
||||||
|
* @property {string[]} clases
|
||||||
|
* @property {(ElementSpec|string)[]} children
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* @param {string|ElementSpec} spec
|
||||||
|
* @returns {HTMLElement|Text}
|
||||||
|
*/
|
||||||
|
const el = (spec) => {
|
||||||
|
if (typeof spec === "string") {
|
||||||
|
return document.createTextNode(spec);
|
||||||
|
}
|
||||||
|
let element = document.createElement(spec.tag);
|
||||||
|
for (const [key, value] of Object.entries(spec.props || {})) {
|
||||||
|
element[key] = value;
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(spec.attributes || {})) {
|
||||||
|
element.setAttribute(key, value);
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(spec.data || {})) {
|
||||||
|
element.dataset[key] = value;
|
||||||
|
}
|
||||||
|
for (const [key, value] of Object.entries(spec.events || {})) {
|
||||||
|
element.addEventListener(key, value);
|
||||||
|
}
|
||||||
|
for (const c of spec.classes || []) {
|
||||||
|
element.classList.add(c);
|
||||||
|
}
|
||||||
|
for (const child of spec.children || []) {
|
||||||
|
element.appendChild(el(child));
|
||||||
|
}
|
||||||
|
return element;
|
||||||
|
}
|
||||||
|
|
||||||
const addElementControls = (row) => {
|
const addElementControls = (row) => {
|
||||||
{
|
row.appendChild(el({
|
||||||
let sizeCol = document.createElement('td');
|
tag: 'td',
|
||||||
sizeCol.classList.add('size');
|
classes: ['size'],
|
||||||
let sizeInput = document.createElement('input');
|
children: ['Size', {
|
||||||
sizeInput.addEventListener('input', render);
|
tag: 'input',
|
||||||
sizeInput.type = "number";
|
events: {input: render},
|
||||||
sizeInput.value = defaultFontSize.toString();
|
props: {
|
||||||
sizeCol.appendChild(document.createTextNode("Size"))
|
type: 'number',
|
||||||
sizeCol.appendChild(sizeInput);
|
value: defaultFontSize.toString(),
|
||||||
row.appendChild(sizeCol);
|
|
||||||
}
|
}
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
|
||||||
{
|
row.appendChild(el({
|
||||||
let posCol = document.createElement('td');
|
tag: 'td',
|
||||||
posCol.classList.add('pos');
|
classes: ['pos'],
|
||||||
let posInputX = document.createElement('input');
|
children: ['Position', {
|
||||||
posInputX.addEventListener('input', render);
|
tag: 'input',
|
||||||
posInputX.type = "number";
|
events: {input: render},
|
||||||
posInputX.value = "0";
|
classes: ['pos_x'],
|
||||||
posInputX.classList.add('pos_x');
|
props: {
|
||||||
let posInputY = document.createElement('input');
|
type: 'number',
|
||||||
posInputY.addEventListener('input', render);
|
value: "0",
|
||||||
posInputY.type = "number";
|
|
||||||
posInputY.value = "0";
|
|
||||||
posInputY.classList.add('pos_y');
|
|
||||||
posCol.appendChild(document.createTextNode("Position"))
|
|
||||||
posCol.appendChild(posInputX);
|
|
||||||
posCol.appendChild(posInputY);
|
|
||||||
row.appendChild(posCol);
|
|
||||||
}
|
}
|
||||||
|
}, {
|
||||||
|
tag: 'input',
|
||||||
|
events: {input: render},
|
||||||
|
classes: ['pos_y'],
|
||||||
|
props: {
|
||||||
|
type: 'number',
|
||||||
|
value: "0",
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}));
|
||||||
|
|
||||||
{
|
row.appendChild(el({
|
||||||
let removeCol = document.createElement('td');
|
tag: 'td',
|
||||||
removeCol.classList.add('delete');
|
classes: ['delete'],
|
||||||
let removeInput = document.createElement('input');
|
children: [{
|
||||||
removeInput.type = "button";
|
tag: 'input',
|
||||||
removeInput.value = "×";
|
events: {click: removeElement},
|
||||||
removeInput.addEventListener('click', removeElement);
|
props: {
|
||||||
removeCol.appendChild(removeInput);
|
type: 'button',
|
||||||
row.appendChild(removeCol);
|
value: 'x',
|
||||||
}
|
}
|
||||||
|
}]
|
||||||
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
const addTextElement = () => {
|
const addTextElement = () => {
|
||||||
let id = nextElementId();
|
let id = nextElementId();
|
||||||
let row = document.createElement('tr');
|
let row = el({
|
||||||
row.dataset.elementId = id;
|
tag: 'tr',
|
||||||
row.dataset.type = 'text';
|
data: {elementId: id, type: 'text'},
|
||||||
|
children: [{
|
||||||
|
tag: 'td',
|
||||||
let textCol = document.createElement('td');
|
classes: ['text'],
|
||||||
textCol.classList.add('text');
|
props: {colSpan: 2},
|
||||||
textCol.colSpan = 2;
|
children: [{
|
||||||
let textInput = document.createElement('input');
|
tag: 'input',
|
||||||
textInput.type = "text";
|
events: {input: render},
|
||||||
textInput.addEventListener('input', render);
|
props: {
|
||||||
textCol.appendChild(textInput);
|
type: 'text',
|
||||||
row.appendChild(textCol);
|
focus: 'focused',
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
addElementControls(row);
|
addElementControls(row);
|
||||||
elementsTableBody.appendChild(row);
|
elementsTableBody.appendChild(row);
|
||||||
|
|
||||||
textInput.focus();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
const loadImage = (event) => {
|
const loadImage = (event) => {
|
||||||
|
|
@ -107,29 +159,36 @@ const loadImage = (event) => {
|
||||||
|
|
||||||
const addImageElement = () => {
|
const addImageElement = () => {
|
||||||
let id = nextElementId();
|
let id = nextElementId();
|
||||||
let row = document.createElement('tr');
|
|
||||||
row.dataset.elementId = id;
|
|
||||||
row.dataset.type = 'image';
|
|
||||||
|
|
||||||
|
|
||||||
let imageCol = document.createElement('td');
|
|
||||||
imageCol.classList.add('image');
|
|
||||||
let imageInput = document.createElement('input');
|
|
||||||
imageInput.type = 'file';
|
|
||||||
let imageId = `image-input-${id}`;
|
let imageId = `image-input-${id}`;
|
||||||
imageInput.id = imageId;
|
let row = el({
|
||||||
imageInput.addEventListener('change', loadImage);
|
tag: 'tr',
|
||||||
let imageLabel = document.createElement('label');
|
data: {elementId: id, type: 'image'},
|
||||||
imageLabel.appendChild(document.createTextNode("Browse..."));
|
children: [{
|
||||||
imageLabel.setAttribute('for', imageId);
|
tag: 'td',
|
||||||
let thumbCol = document.createElement('td');
|
classes: ['image'],
|
||||||
thumbCol.classList.add('preview');
|
children: [{
|
||||||
let imageThumb = document.createElement('img');
|
tag: 'input',
|
||||||
imageCol.appendChild(imageLabel);
|
events: {change: loadImage},
|
||||||
imageCol.appendChild(imageInput);
|
props: {
|
||||||
thumbCol.appendChild(imageThumb);
|
id: imageId,
|
||||||
row.appendChild(imageCol);
|
type: 'file',
|
||||||
row.appendChild(thumbCol);
|
focus: 'focused',
|
||||||
|
}
|
||||||
|
},{
|
||||||
|
tag: 'label',
|
||||||
|
events: {change: loadImage},
|
||||||
|
children: "Browse...",
|
||||||
|
attributes: {
|
||||||
|
for: imageId,
|
||||||
|
}
|
||||||
|
}]
|
||||||
|
}, {
|
||||||
|
tag: 'td',
|
||||||
|
classes: ['preview'],
|
||||||
|
children: [{tag: 'img'}]
|
||||||
|
}]
|
||||||
|
});
|
||||||
|
|
||||||
addElementControls(row);
|
addElementControls(row);
|
||||||
elementsTableBody.appendChild(row);
|
elementsTableBody.appendChild(row);
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue