2 * Abstract implementation of the JavaScript component of a form field handling a list of packages.
4 * @author Matthias Schmidt
5 * @copyright 2001-2021 WoltLab GmbH
6 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
7 * @module WoltLabSuite/Core/Acp/Form/Builder/Field/Devtools/Project/AbstractPackageList
10 define(["require", "exports", "tslib", "../../../../../../Core", "../../../../../../Language", "../../../../../../Dom/Traverse", "../../../../../../Dom/Change/Listener", "../../../../../../Dom/Util"], function (require, exports, tslib_1, Core, Language, DomTraverse, Listener_1, Util_1) {
12 Core = tslib_1.__importStar(Core);
13 Language = tslib_1.__importStar(Language);
14 DomTraverse = tslib_1.__importStar(DomTraverse);
15 Listener_1 = tslib_1.__importDefault(Listener_1);
16 Util_1 = tslib_1.__importDefault(Util_1);
17 class AbstractPackageList {
18 constructor(formFieldId, existingPackages) {
19 this.formFieldId = formFieldId;
20 this.packageList = document.getElementById(`${this.formFieldId}_packageList`);
21 if (this.packageList === null) {
22 throw new Error(`Cannot find package list for packages field with id '${this.formFieldId}'.`);
24 this.packageIdentifier = document.getElementById(`${this.formFieldId}_packageIdentifier`);
25 if (this.packageIdentifier === null) {
26 throw new Error(`Cannot find package identifier form field for packages field with id '${this.formFieldId}'.`);
28 this.packageIdentifier.addEventListener("keypress", (ev) => this.keyPress(ev));
29 this.addButton = document.getElementById(`${this.formFieldId}_addButton`);
30 if (this.addButton === null) {
31 throw new Error(`Cannot find add button for packages field with id '${this.formFieldId}'.`);
33 this.addButton.addEventListener("click", (ev) => this.addPackage(ev));
34 this.form = this.packageList.closest("form");
35 if (this.form === null) {
36 throw new Error(`Cannot find form element for packages field with id '${this.formFieldId}'.`);
38 this.form.addEventListener("submit", () => this.submit());
39 existingPackages.forEach((data) => this.addPackageByData(data));
42 * Adds a package to the package list as a consequence of the given event.
44 * If the package data is invalid, an error message is shown and no package is added.
47 event.preventDefault();
48 event.stopPropagation();
50 if (!this.validateInput()) {
53 this.addPackageByData(this.getInputData());
56 this.packageIdentifier.focus();
59 * Adds a package to the package list using the given package data.
61 addPackageByData(packageData) {
62 // add package to list
63 const listItem = document.createElement("li");
64 this.populateListItem(listItem, packageData);
66 const deleteButton = document.createElement("span");
67 deleteButton.className = "icon icon16 fa-times pointer jsTooltip";
68 deleteButton.title = Language.get("wcf.global.button.delete");
69 deleteButton.addEventListener("click", (ev) => this.removePackage(ev));
70 listItem.insertAdjacentElement("afterbegin", deleteButton);
71 this.packageList.appendChild(listItem);
72 Listener_1.default.trigger();
75 * Creates the hidden fields when the form is submitted.
77 createSubmitFields(listElement, index) {
78 const packageIdentifier = document.createElement("input");
79 packageIdentifier.type = "hidden";
80 packageIdentifier.name = `${this.formFieldId}[${index}][packageIdentifier]`;
81 packageIdentifier.value = listElement.dataset.packageIdentifier;
82 this.form.appendChild(packageIdentifier);
85 * Empties the input fields.
88 this.packageIdentifier.value = "";
91 * Returns the current data of the input fields to add a new package.
95 packageIdentifier: this.packageIdentifier.value,
99 * Adds a package to the package list after pressing ENTER in a text field.
102 if (event.key === "Enter") {
103 this.addPackage(event);
107 * Adds all necessary package-relavant data to the given list item.
109 populateListItem(listItem, packageData) {
110 listItem.dataset.packageIdentifier = packageData.packageIdentifier;
113 * Removes a package by clicking on its delete button.
115 removePackage(event) {
116 event.currentTarget.closest("li").remove();
117 // remove field errors if the last package has been deleted
118 Util_1.default.innerError(this.packageList, "");
121 * Adds all necessary (hidden) form fields to the form when submitting the form.
124 DomTraverse.childrenByTag(this.packageList, "LI").forEach((listItem, index) => this.createSubmitFields(listItem, index));
127 * Returns `true` if the currently entered package data is valid. Otherwise `false` is returned and relevant error
128 * messages are shown.
131 return this.validatePackageIdentifier();
134 * Returns `true` if the currently entered package identifier is valid. Otherwise `false` is returned and an error
137 validatePackageIdentifier() {
138 const packageIdentifier = this.packageIdentifier.value;
139 if (packageIdentifier === "") {
140 Util_1.default.innerError(this.packageIdentifier, Language.get("wcf.global.form.error.empty"));
143 if (packageIdentifier.length < 3) {
144 Util_1.default.innerError(this.packageIdentifier, Language.get("wcf.acp.devtools.project.packageIdentifier.error.minimumLength"));
147 else if (packageIdentifier.length > 191) {
148 Util_1.default.innerError(this.packageIdentifier, Language.get("wcf.acp.devtools.project.packageIdentifier.error.maximumLength"));
151 if (!AbstractPackageList.packageIdentifierRegExp.test(packageIdentifier)) {
152 Util_1.default.innerError(this.packageIdentifier, Language.get("wcf.acp.devtools.project.packageIdentifier.error.format"));
155 // check if package has already been added
156 const duplicate = DomTraverse.childrenByTag(this.packageList, "LI").some((listItem) => listItem.dataset.packageIdentifier === packageIdentifier);
158 Util_1.default.innerError(this.packageIdentifier, Language.get("wcf.acp.devtools.project.packageIdentifier.error.duplicate"));
161 // remove outdated errors
162 Util_1.default.innerError(this.packageIdentifier, "");
166 * Returns `true` if the given version is valid. Otherwise `false` is returned and an error message is shown.
168 validateVersion(versionElement) {
169 const version = versionElement.value;
170 // see `wcf\data\package\Package::isValidVersion()`
171 // the version is no a required attribute
172 if (version !== "") {
173 if (version.length > 255) {
174 Util_1.default.innerError(versionElement, Language.get("wcf.acp.devtools.project.packageVersion.error.maximumLength"));
177 if (!AbstractPackageList.versionRegExp.test(version)) {
178 Util_1.default.innerError(versionElement, Language.get("wcf.acp.devtools.project.packageVersion.error.format"));
182 // remove outdated errors
183 Util_1.default.innerError(versionElement, "");
187 // see `wcf\data\package\Package::isValidPackageName()`
188 AbstractPackageList.packageIdentifierRegExp = new RegExp(/^[a-zA-Z0-9_-]+\.[a-zA-Z0-9_-]+(\.[a-zA-Z0-9_-]+)+$/);
189 // see `wcf\data\package\Package::isValidVersion()`
190 AbstractPackageList.versionRegExp = new RegExp(/^([0-9]+).([0-9]+)\.([0-9]+)( (a|alpha|b|beta|d|dev|rc|pl) ([0-9]+))?$/i);
191 Core.enableLegacyInheritance(AbstractPackageList);
192 return AbstractPackageList;