Implement fields having multiple items in creator
This commit is contained in:
parent
8730b7c199
commit
dbde3a5834
@ -10,6 +10,7 @@ export class Field {
|
|||||||
categoryName = null;
|
categoryName = null;
|
||||||
isHidden = false;
|
isHidden = false;
|
||||||
isDisabled = false;
|
isDisabled = false;
|
||||||
|
allowMultiple = false;
|
||||||
|
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
this.key = key;
|
this.key = key;
|
||||||
@ -55,4 +56,9 @@ export class Field {
|
|||||||
this.isDisabled = true;
|
this.isDisabled = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
multiple() {
|
||||||
|
this.allowMultiple = true;
|
||||||
|
return this;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,29 +1,66 @@
|
|||||||
|
import { FieldInputItem } from "./FieldInputItem.js";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents the actual input element on the creator tool
|
* Represents the actual input element on the creator tool
|
||||||
* A field may have multiple inputs if it allows multiple values
|
* May contain multiple items if the field allows multiple values
|
||||||
*/
|
*/
|
||||||
export class FieldInput {
|
export class FieldInput {
|
||||||
constructor(field, parentElem) {
|
constructor(field, parentElem) {
|
||||||
this.field = field;
|
this.field = field;
|
||||||
this.id = "field-" + field.key;
|
this.id = "field-" + field.key;
|
||||||
|
this.items = [];
|
||||||
|
this.parent = parentElem;
|
||||||
|
|
||||||
if (!field.isHidden)
|
this.appendHtml(parentElem);
|
||||||
parentElem.innerHTML += `
|
|
||||||
<label for="${field.key}">${field.displayName}</label>
|
|
||||||
<p class="description">${field.description ?? ""}</p>
|
|
||||||
${field.getInputHtml(this.id)}
|
|
||||||
`;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
isValid() {
|
appendHtml(parent) {
|
||||||
return this.field.isValidInput(this.id);
|
const fieldContainer = document.createElement("div");
|
||||||
|
fieldContainer.className = "field-container";
|
||||||
|
|
||||||
|
const item = new FieldInputItem(this, fieldContainer);
|
||||||
|
|
||||||
|
if (!this.field.isHidden) {
|
||||||
|
parent.insertAdjacentHTML("beforeend", `
|
||||||
|
<label for="${this.field.key}">${this.field.displayName}</label>
|
||||||
|
<p class="description">${this.field.description ?? ""}</p>
|
||||||
|
`);
|
||||||
|
|
||||||
|
parent.appendChild(fieldContainer);
|
||||||
|
|
||||||
|
if (this.field.allowMultiple && this.items.length === 0) {
|
||||||
|
const addBtn = document.createElement("button");
|
||||||
|
addBtn.className = "text-button";
|
||||||
|
addBtn.type = "button";
|
||||||
|
addBtn.innerText = "+ Add";
|
||||||
|
addBtn.onclick = () => this.addItem(fieldContainer);
|
||||||
|
parent.appendChild(addBtn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this.items.push(item);
|
||||||
|
this.updateItems();
|
||||||
}
|
}
|
||||||
|
|
||||||
getValue() {
|
updateItems() {
|
||||||
return this.field.getInputValue(this.id);
|
for (const item of this.items) item.update();
|
||||||
}
|
}
|
||||||
|
|
||||||
toString() {
|
addItem(parent) {
|
||||||
return this.field.inputToString(this.id);
|
const item = new FieldInputItem(this, parent);
|
||||||
|
this.items.push(item);
|
||||||
|
|
||||||
|
this.updateItems();
|
||||||
|
}
|
||||||
|
|
||||||
|
removeItem(id) {
|
||||||
|
const i = this.items.findIndex(item => item.id === id);
|
||||||
|
|
||||||
|
this.items[i].remove();
|
||||||
|
this.items.splice(i, 1);
|
||||||
|
|
||||||
|
this.updateItems();
|
||||||
|
|
||||||
|
this.parent.closest("form").onchange();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
60
assets/scripts/FieldInputItem.js
Normal file
60
assets/scripts/FieldInputItem.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
export class FieldInputItem {
|
||||||
|
container = null;
|
||||||
|
removeBtn = null;
|
||||||
|
|
||||||
|
constructor(input, parentElem) {
|
||||||
|
this.input = input;
|
||||||
|
this.field = input.field;
|
||||||
|
this.id = input.id + (input.field.allowMultiple ? "-" + Math.random().toString().slice(2, 5) : "");
|
||||||
|
|
||||||
|
this.appendHtml(parentElem);
|
||||||
|
}
|
||||||
|
|
||||||
|
appendHtml(parent) {
|
||||||
|
const container = document.createElement("div");
|
||||||
|
container.style.display = "flex";
|
||||||
|
container.style.gap = "0.5rem";
|
||||||
|
|
||||||
|
if (this.field.allowMultiple) {
|
||||||
|
const wrapper = document.createElement("div");
|
||||||
|
wrapper.innerHTML = this.field.getInputHtml(this.id);
|
||||||
|
container.appendChild(wrapper);
|
||||||
|
|
||||||
|
const removeBtn = document.createElement("button");
|
||||||
|
removeBtn.type = "button";
|
||||||
|
removeBtn.className = "text-button";
|
||||||
|
removeBtn.innerHTML = "× Remove";
|
||||||
|
removeBtn.onclick = () => this.input.removeItem(this.id);
|
||||||
|
container.appendChild(removeBtn);
|
||||||
|
|
||||||
|
this.removeBtn = removeBtn;
|
||||||
|
} else {
|
||||||
|
container.innerHTML = this.field.getInputHtml(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
parent.appendChild(container);
|
||||||
|
this.container = container;
|
||||||
|
}
|
||||||
|
|
||||||
|
update() {
|
||||||
|
if (this.removeBtn) {
|
||||||
|
this.removeBtn.style.display = this.input.items.length > 1 ? "inline-block" : "none";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
remove() {
|
||||||
|
this.container.remove();
|
||||||
|
}
|
||||||
|
|
||||||
|
isValid() {
|
||||||
|
return this.field.isValidInput(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
getValue() {
|
||||||
|
return this.field.getInputValue(this.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
toString() {
|
||||||
|
return this.field.inputToString(this.id);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -86,10 +86,10 @@ export class SpfRecord {
|
|||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createFromFieldInputs(fieldInputs) {
|
static createFromFieldInputItems(items) {
|
||||||
const tokens = fieldInputs
|
const tokens = items
|
||||||
.filter(input => !input.field.isDisabled && input.isValid())
|
.filter(item => !item.field.isDisabled && item.isValid())
|
||||||
.map(input => input.toString());
|
.map(item => item.toString());
|
||||||
|
|
||||||
const text = tokens.join(" ");
|
const text = tokens.join(" ");
|
||||||
|
|
||||||
|
|||||||
@ -8,10 +8,10 @@ export class TagListRecord {
|
|||||||
this.text = text;
|
this.text = text;
|
||||||
}
|
}
|
||||||
|
|
||||||
static createFromFieldInputs(fieldInputs) {
|
static createFromFieldInputItems(items) {
|
||||||
const tokens = fieldInputs
|
const tokens = items
|
||||||
.filter(input => !input.field.isDisabled && input.isValid())
|
.filter(item => !item.field.isDisabled && item.isValid())
|
||||||
.filter(input => !input.field.defaultValue || input.getValue() !== input.field.defaultValue)
|
.filter(item => !item.field.defaultValue || item.getValue() !== item.field.defaultValue)
|
||||||
.map(input => input.toString());
|
.map(input => input.toString());
|
||||||
|
|
||||||
const text = tokens.join("; ");
|
const text = tokens.join("; ");
|
||||||
|
|||||||
@ -5,7 +5,6 @@ export class Term extends Field {
|
|||||||
separator = null;
|
separator = null;
|
||||||
isRequired = false;
|
isRequired = false;
|
||||||
position = null;
|
position = null;
|
||||||
allowMultiple = false;
|
|
||||||
valueRequirement = ValueRequirement.REQUIRED;
|
valueRequirement = ValueRequirement.REQUIRED;
|
||||||
|
|
||||||
constructor(key) {
|
constructor(key) {
|
||||||
@ -52,11 +51,6 @@ export class Term extends Field {
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
multiple() {
|
|
||||||
this.allowMultiple = true;
|
|
||||||
return this;
|
|
||||||
}
|
|
||||||
|
|
||||||
value(requirement) {
|
value(requirement) {
|
||||||
this.valueRequirement = requirement;
|
this.valueRequirement = requirement;
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@ -36,7 +36,12 @@ document.getElementById("form").onchange = generate;
|
|||||||
generate();
|
generate();
|
||||||
|
|
||||||
function generate() {
|
function generate() {
|
||||||
const record = Record.createFromFieldInputs(inputs);
|
const items = [];
|
||||||
|
for (const input of inputs) {
|
||||||
|
items.push(...input.items);
|
||||||
|
}
|
||||||
|
|
||||||
|
const record = Record.createFromFieldInputItems(items);
|
||||||
|
|
||||||
document.getElementById("record").value = record.text;
|
document.getElementById("record").value = record.text;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -164,3 +164,23 @@ summary {
|
|||||||
summary:hover {
|
summary:hover {
|
||||||
color: black;
|
color: black;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.field-container {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: start;
|
||||||
|
gap: 0.5rem;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-button {
|
||||||
|
background: none;
|
||||||
|
border: none;
|
||||||
|
cursor: pointer;
|
||||||
|
color: #757575;
|
||||||
|
transition: color 200ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
.text-button:hover {
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user