diff --git a/html/media/addedit_form.html b/html/media/addedit_form.html
index f7b89163..3062dd83 100644
--- a/html/media/addedit_form.html
+++ b/html/media/addedit_form.html
@@ -47,7 +47,7 @@
diff --git a/js/media/addedit.js b/js/media/addedit.js
index ed781a08..9f777824 100644
--- a/js/media/addedit.js
+++ b/js/media/addedit.js
@@ -124,6 +124,7 @@ OB.Media.mediaAddeditForm = function (id, title, editing) {
}
// fill country list
+ /*
for (var i in OB.Settings.countries) {
$form
.find(".country_field")
@@ -135,6 +136,7 @@ OB.Media.mediaAddeditForm = function (id, title, editing) {
"",
);
}
+ */
// tie together genre list with category list on change
$form.find(".category_field").change(function () {
@@ -156,12 +158,10 @@ OB.Media.mediaAddeditForm = function (id, title, editing) {
.setAttribute("data-id3-field", metadata.settings.id3_key);
}
- // set select field options
- if (metadata.type == "select" && metadata.settings && metadata.settings.options) {
- metadata.settings.options.forEach(function (option) {
- let selectField = metadataField.querySelector(".metadata_name_field");
- selectField.innerHTML = selectField.innerHTML + "
";
- });
+ // settings
+ let selectField = metadataField.querySelector(".metadata_name_field");
+ if (metadata.settings) {
+ selectField.settings = metadata.settings;
}
// change field name and description values
@@ -189,12 +189,6 @@ OB.Media.mediaAddeditForm = function (id, title, editing) {
"#media_addedit_" + id + " .metadata_" + metadata.name + "_field",
).suggestions = metadata.settings.suggestions;
}
-
- // set options
- if (metadata.type == "select" && metadata?.settings?.options) {
- document.querySelector("#media_addedit_" + id + " .metadata_" + metadata.name + "_field").options =
- metadata.settings.options;
- }
}
});
@@ -452,8 +446,9 @@ OB.Media.save = function () {
.val();
// media and playlist metadata fields return arrays, but will be a single item, so convert:
- if (Array.isArray(metaItem) && (metadata.type == "media" || metadata.type == "playlist")) {
- metaItem = metaItem[0];
+ if (metadata.type == "media" || metadata.type == "playlist") {
+ if (!metaItem || !metaItem.length) metaItem = null;
+ else metaItem = metaItem[0];
}
item["metadata_" + metadata.name] = metaItem;
diff --git a/js/media/details.js b/js/media/details.js
index 80f7c752..60185941 100644
--- a/js/media/details.js
+++ b/js/media/details.js
@@ -99,26 +99,19 @@ OB.Media.detailsPage = function (id) {
labelElem.textContent = metadata.description;
metaElem.appendChild(labelElem);
- switch (metadata.type) {
- case "media":
- case "playlist":
- const mediaPlaylistElem = document.createElement("ob-field-" + metadata.type);
- mediaPlaylistElem.setAttribute("value", value);
- mediaPlaylistElem.dataset.single = true;
- metaElem.appendChild(mediaPlaylistElem);
- break;
- case "time":
- case "date":
- case "datetime":
- const dateTimeElem = document.createElement("ob-field-" + metadata.type);
- dateTimeElem.setAttribute("value", value);
- metaElem.appendChild(dateTimeElem);
- break;
- default:
- const spanElem = document.createElement("span");
- spanElem.textContent = value;
- metaElem.appendChild(spanElem);
- break;
+ // use custom html element if available
+ if (customElements.get("ob-field-" + metadata.type)) {
+ const fieldElem = document.createElement("ob-field-" + metadata.type);
+ fieldElem.value = value;
+ fieldElem.settings = metadata.settings;
+ metaElem.appendChild(fieldElem);
+ }
+
+ // fallback to span
+ else {
+ const spanElem = document.createElement("span");
+ spanElem.textContent = value;
+ metaElem.appendChild(spanElem);
}
document.querySelector("#media_details_metadata").appendChild(metaElem);
diff --git a/js/media/settings.js b/js/media/settings.js
index 23ecda42..db33180f 100644
--- a/js/media/settings.js
+++ b/js/media/settings.js
@@ -404,7 +404,7 @@ OB.Media.metadataAddEditTypeChange = function () {
// handle select field
var select_value = document.querySelector(".metadata_default_select").value;
- var select_options = document.querySelector("#metadata_select_options").value.split("\n");
+ var select_options = document.querySelector("#metadata_select_options").value?.split("\n");
document.querySelector(".metadata_default_select").options = select_options;
document.querySelector(".metadata_default_select").value = select_value;
diff --git a/package-lock.json b/package-lock.json
index f7430c24..10b0c302 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -11,8 +11,10 @@
"dayjs": "^1.11.11",
"easymde": "^2.18.0",
"htm": "^3.1.1",
+ "isomorphic-dompurify": "^2.13.0",
"jquery": "^3.6.1",
"jquery-migrate": "^3.4.0",
+ "marked": "^13.0.2",
"sass": "^1.69.5",
"video.js": "^8.10.0"
},
@@ -109,6 +111,14 @@
"@types/tern": "*"
}
},
+ "node_modules/@types/dompurify": {
+ "version": "3.0.5",
+ "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz",
+ "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==",
+ "dependencies": {
+ "@types/trusted-types": "*"
+ }
+ },
"node_modules/@types/eslint": {
"version": "8.56.10",
"resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.56.10.tgz",
@@ -162,6 +172,11 @@
"@types/estree": "*"
}
},
+ "node_modules/@types/trusted-types": {
+ "version": "2.0.7",
+ "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz",
+ "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw=="
+ },
"node_modules/@videojs/http-streaming": {
"version": "3.12.1",
"resolved": "https://registry.npmjs.org/@videojs/http-streaming/-/http-streaming-3.12.1.tgz",
@@ -464,6 +479,17 @@
"npm": ">=5"
}
},
+ "node_modules/agent-base": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.1.tgz",
+ "integrity": "sha512-H0TSyFNDMomMNJQBn8wFV5YC/2eJ+VXECwOadZJT554xP6cODZHPX3H9QMQECxvrgiSOP1pHjy1sMWQVYJOUOA==",
+ "dependencies": {
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
"node_modules/ajv": {
"version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@@ -501,6 +527,11 @@
"node": ">= 8"
}
},
+ "node_modules/asynckit": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
+ "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q=="
+ },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
@@ -657,6 +688,17 @@
"integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==",
"dev": true
},
+ "node_modules/combined-stream": {
+ "version": "1.0.8",
+ "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz",
+ "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==",
+ "dependencies": {
+ "delayed-stream": "~1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
"node_modules/commander": {
"version": "2.20.3",
"resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz",
@@ -698,16 +740,78 @@
"node": ">= 8"
}
},
+ "node_modules/cssstyle": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-4.0.1.tgz",
+ "integrity": "sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==",
+ "dependencies": {
+ "rrweb-cssom": "^0.6.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/cssstyle/node_modules/rrweb-cssom": {
+ "version": "0.6.0",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.6.0.tgz",
+ "integrity": "sha512-APM0Gt1KoXBz0iIkkdB/kfvGOwC4UuJFeG/c+yV7wSc7q96cG/kJ0HiYCnzivD9SB53cLV1MlHFNfOuPaadYSw=="
+ },
+ "node_modules/data-urls": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/data-urls/-/data-urls-5.0.0.tgz",
+ "integrity": "sha512-ZYP5VBHshaDAiVZxjbRVcFJpc+4xGgT0bK3vzy1HLN8jTO975HEbuYzZJcHoQEY5K1a0z8YayJkyVETa08eNTg==",
+ "dependencies": {
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/dayjs": {
"version": "1.11.11",
"resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.11.tgz",
"integrity": "sha512-okzr3f11N6WuqYtZSvm+F776mB41wRZMhKP+hc34YdW+KmtYYK9iqvHSwo2k9FEH3fhGXvOPV6yz2IcSrfRUDg=="
},
+ "node_modules/debug": {
+ "version": "4.3.5",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
+ "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
+ "dependencies": {
+ "ms": "2.1.2"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/decimal.js": {
+ "version": "10.4.3",
+ "resolved": "https://registry.npmjs.org/decimal.js/-/decimal.js-10.4.3.tgz",
+ "integrity": "sha512-VBBaLc1MgL5XpzgIP7ny5Z6Nx3UrRkIViUkPUdtl9aya5amy3De1gsUUSB1g3+3sExYNjCAsAznmukyxCb1GRA=="
+ },
+ "node_modules/delayed-stream": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
+ "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==",
+ "engines": {
+ "node": ">=0.4.0"
+ }
+ },
"node_modules/dom-walk": {
"version": "0.1.2",
"resolved": "https://registry.npmjs.org/dom-walk/-/dom-walk-0.1.2.tgz",
"integrity": "sha512-6QvTW9mrGeIegrFXdtQi9pk7O/nSK6lSdXW2eqUspN5LWD7UTji2Fqw5V2YLjBpHEoU9Xl/eUWNpDeZvoyOv2w=="
},
+ "node_modules/dompurify": {
+ "version": "3.1.6",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.1.6.tgz",
+ "integrity": "sha512-cTOAhc36AalkjtBpfG6O8JimdTMWNXjiePT2xQH/ppBGi/4uIpmj8eKyIkMJErXWARyINV/sB38yf8JCLF5pbQ=="
+ },
"node_modules/easymde": {
"version": "2.18.0",
"resolved": "https://registry.npmjs.org/easymde/-/easymde-2.18.0.tgz",
@@ -720,6 +824,17 @@
"marked": "^4.1.0"
}
},
+ "node_modules/easymde/node_modules/marked": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
+ "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "bin": {
+ "marked": "bin/marked.js"
+ },
+ "engines": {
+ "node": ">= 12"
+ }
+ },
"node_modules/electron-to-chromium": {
"version": "1.4.817",
"resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.817.tgz",
@@ -739,6 +854,17 @@
"node": ">=10.13.0"
}
},
+ "node_modules/entities": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz",
+ "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
+ "engines": {
+ "node": ">=0.12"
+ },
+ "funding": {
+ "url": "https://github.com/fb55/entities?sponsor=1"
+ }
+ },
"node_modules/envinfo": {
"version": "7.13.0",
"resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.13.0.tgz",
@@ -872,6 +998,19 @@
"flat": "cli.js"
}
},
+ "node_modules/form-data": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz",
+ "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==",
+ "dependencies": {
+ "asynckit": "^0.4.0",
+ "combined-stream": "^1.0.8",
+ "mime-types": "^2.1.12"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
@@ -952,6 +1091,52 @@
"resolved": "https://registry.npmjs.org/htm/-/htm-3.1.1.tgz",
"integrity": "sha512-983Vyg8NwUE7JkZ6NmOqpCZ+sh1bKv2iYTlUkzlWmA5JD2acKoxd4KVxbMmxX/85mtfdnDmTFoNKcg5DGAvxNQ=="
},
+ "node_modules/html-encoding-sniffer": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-4.0.0.tgz",
+ "integrity": "sha512-Y22oTqIU4uuPgEemfz7NDJz6OeKf12Lsu+QC+s3BVpda64lTiMYCyGwg5ki4vFxkMwQdeZDl2adZoqUgdFuTgQ==",
+ "dependencies": {
+ "whatwg-encoding": "^3.1.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/http-proxy-agent": {
+ "version": "7.0.2",
+ "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz",
+ "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==",
+ "dependencies": {
+ "agent-base": "^7.1.0",
+ "debug": "^4.3.4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/https-proxy-agent": {
+ "version": "7.0.5",
+ "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.5.tgz",
+ "integrity": "sha512-1e4Wqeblerz+tMKPIq2EMGiiWW1dIjZOksyHWSUm1rmuvw/how9hBHZ38lAGj5ID4Ik6EdkOw7NmWPy6LAwalw==",
+ "dependencies": {
+ "agent-base": "^7.0.2",
+ "debug": "4"
+ },
+ "engines": {
+ "node": ">= 14"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
"node_modules/immutable": {
"version": "4.3.6",
"resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.6.tgz",
@@ -1066,6 +1251,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/is-potential-custom-element-name": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.1.tgz",
+ "integrity": "sha512-bCYeRA2rVibKZd+s2625gGnGF/t7DSqDs4dP7CrLA1m7jKWz6pps0LpYLJN8Q64HtmPKJ1hrN3nzPNKFEKOUiQ=="
+ },
"node_modules/isarray": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
@@ -1087,6 +1277,19 @@
"node": ">=0.10.0"
}
},
+ "node_modules/isomorphic-dompurify": {
+ "version": "2.13.0",
+ "resolved": "https://registry.npmjs.org/isomorphic-dompurify/-/isomorphic-dompurify-2.13.0.tgz",
+ "integrity": "sha512-jVxFnyOiA3fKPkteQjfIogww9T/BIX1Basuwt5D50MB3Sqvki9yBNq96ICLHpbiDY79jc6RC555DeBbTCt6i6A==",
+ "dependencies": {
+ "@types/dompurify": "^3.0.5",
+ "dompurify": "^3.1.6",
+ "jsdom": "^24.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/jest-worker": {
"version": "27.5.1",
"resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz",
@@ -1114,6 +1317,45 @@
"jquery": ">=3 <4"
}
},
+ "node_modules/jsdom": {
+ "version": "24.1.1",
+ "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-24.1.1.tgz",
+ "integrity": "sha512-5O1wWV99Jhq4DV7rCLIoZ/UIhyQeDR7wHVyZAHAshbrvZsLs+Xzz7gtwnlJTJDjleiTKh54F4dXrX70vJQTyJQ==",
+ "dependencies": {
+ "cssstyle": "^4.0.1",
+ "data-urls": "^5.0.0",
+ "decimal.js": "^10.4.3",
+ "form-data": "^4.0.0",
+ "html-encoding-sniffer": "^4.0.0",
+ "http-proxy-agent": "^7.0.2",
+ "https-proxy-agent": "^7.0.5",
+ "is-potential-custom-element-name": "^1.0.1",
+ "nwsapi": "^2.2.12",
+ "parse5": "^7.1.2",
+ "rrweb-cssom": "^0.7.1",
+ "saxes": "^6.0.0",
+ "symbol-tree": "^3.2.4",
+ "tough-cookie": "^4.1.4",
+ "w3c-xmlserializer": "^5.0.0",
+ "webidl-conversions": "^7.0.0",
+ "whatwg-encoding": "^3.1.1",
+ "whatwg-mimetype": "^4.0.0",
+ "whatwg-url": "^14.0.0",
+ "ws": "^8.18.0",
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "peerDependencies": {
+ "canvas": "^2.11.2"
+ },
+ "peerDependenciesMeta": {
+ "canvas": {
+ "optional": true
+ }
+ }
+ },
"node_modules/json-parse-even-better-errors": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz",
@@ -1196,14 +1438,14 @@
}
},
"node_modules/marked": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/marked/-/marked-4.3.0.tgz",
- "integrity": "sha512-PRsaiG84bK+AMvxziE/lCFss8juXjNaWzVbN5tXAm4XjeaS9NAHhop+PjQxz2A9h8Q4M/xGmzP8vqNwy6JeK0A==",
+ "version": "13.0.2",
+ "resolved": "https://registry.npmjs.org/marked/-/marked-13.0.2.tgz",
+ "integrity": "sha512-J6CPjP8pS5sgrRqxVRvkCIkZ6MFdRIjDkwUwgJ9nL2fbmM6qGQeB2C16hi8Cc9BOzj6xXzy0jyi0iPIfnMHYzA==",
"bin": {
"marked": "bin/marked.js"
},
"engines": {
- "node": ">= 12"
+ "node": ">= 18"
}
},
"node_modules/merge-stream": {
@@ -1216,7 +1458,6 @@
"version": "1.52.0",
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
"integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==",
- "dev": true,
"engines": {
"node": ">= 0.6"
}
@@ -1225,7 +1466,6 @@
"version": "2.1.35",
"resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz",
"integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==",
- "dev": true,
"dependencies": {
"mime-db": "1.52.0"
},
@@ -1255,6 +1495,11 @@
"mpd-to-m3u8-json": "bin/parse.js"
}
},
+ "node_modules/ms": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
+ "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
+ },
"node_modules/mux.js": {
"version": "7.0.3",
"resolved": "https://registry.npmjs.org/mux.js/-/mux.js-7.0.3.tgz",
@@ -1291,6 +1536,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/nwsapi": {
+ "version": "2.2.12",
+ "resolved": "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.12.tgz",
+ "integrity": "sha512-qXDmcVlZV4XRtKFzddidpfVP4oMSGhga+xdMc25mv8kaLUHtgzCDhUxkrN8exkGdTlLNaXj7CV3GtON7zuGZ+w=="
+ },
"node_modules/os-shim": {
"version": "0.1.3",
"resolved": "https://registry.npmjs.org/os-shim/-/os-shim-0.1.3.tgz",
@@ -1336,6 +1586,17 @@
"node": ">=6"
}
},
+ "node_modules/parse5": {
+ "version": "7.1.2",
+ "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz",
+ "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==",
+ "dependencies": {
+ "entities": "^4.4.0"
+ },
+ "funding": {
+ "url": "https://github.com/inikulin/parse5?sponsor=1"
+ }
+ },
"node_modules/path-exists": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
@@ -1491,15 +1752,24 @@
"integrity": "sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==",
"dev": true
},
+ "node_modules/psl": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz",
+ "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag=="
+ },
"node_modules/punycode": {
"version": "2.3.1",
"resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz",
"integrity": "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==",
- "dev": true,
"engines": {
"node": ">=6"
}
},
+ "node_modules/querystringify": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
+ "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ=="
+ },
"node_modules/randombytes": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
@@ -1558,6 +1828,11 @@
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
"integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
},
+ "node_modules/requires-port": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz",
+ "integrity": "sha512-KigOCHcocU3XODJxsu8i/j8T9tzT4adHiecwORRQ0ZZFcp7ahwXuRU1m+yuO90C5ZUyGeGfocHDI14M3L3yDAQ=="
+ },
"node_modules/resolve": {
"version": "1.22.8",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
@@ -1596,6 +1871,11 @@
"node": ">=8"
}
},
+ "node_modules/rrweb-cssom": {
+ "version": "0.7.1",
+ "resolved": "https://registry.npmjs.org/rrweb-cssom/-/rrweb-cssom-0.7.1.tgz",
+ "integrity": "sha512-TrEMa7JGdVm0UThDJSx7ddw5nVm3UJS9o9CCIZ72B1vSyEZoziDqBYP3XIoi/12lKrJR8rE3jeFHMok2F/Mnsg=="
+ },
"node_modules/rust-result": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/rust-result/-/rust-result-1.0.0.tgz",
@@ -1632,6 +1912,11 @@
"rust-result": "^1.0.0"
}
},
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
"node_modules/sass": {
"version": "1.77.6",
"resolved": "https://registry.npmjs.org/sass/-/sass-1.77.6.tgz",
@@ -1648,6 +1933,17 @@
"node": ">=14.0.0"
}
},
+ "node_modules/saxes": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/saxes/-/saxes-6.0.0.tgz",
+ "integrity": "sha512-xAg7SOnEhrm5zI3puOOKyy1OMcMlIJZYNJY7xLBwSze0UjhPLnWfj2GF2EpT0jmzaJKIWKHLsaSSajf35bcYnA==",
+ "dependencies": {
+ "xmlchars": "^2.2.0"
+ },
+ "engines": {
+ "node": ">=v12.22.7"
+ }
+ },
"node_modules/schema-utils": {
"version": "3.3.0",
"resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz",
@@ -1788,6 +2084,11 @@
"url": "https://github.com/sponsors/ljharb"
}
},
+ "node_modules/symbol-tree": {
+ "version": "3.2.4",
+ "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz",
+ "integrity": "sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw=="
+ },
"node_modules/tapable": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz",
@@ -1860,6 +2161,31 @@
"node": ">=8.0"
}
},
+ "node_modules/tough-cookie": {
+ "version": "4.1.4",
+ "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.4.tgz",
+ "integrity": "sha512-Loo5UUvLD9ScZ6jh8beX1T6sO1w2/MpCRpEP7V280GKMVUQ0Jzar2U3UJPsrdbziLEMMhu3Ujnq//rhiFuIeag==",
+ "dependencies": {
+ "psl": "^1.1.33",
+ "punycode": "^2.1.1",
+ "universalify": "^0.2.0",
+ "url-parse": "^1.5.3"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-5.0.0.tgz",
+ "integrity": "sha512-tk2G5R2KRwBd+ZN0zaEXpmzdKyOYksXwywulIX95MBODjSzMIuQnQ3m8JxgbhnL1LeVo7lqQKsYa1O3Htl7K5g==",
+ "dependencies": {
+ "punycode": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/typedarray": {
"version": "0.0.6",
"resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz",
@@ -1877,6 +2203,14 @@
"integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
"dev": true
},
+ "node_modules/universalify": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz",
+ "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==",
+ "engines": {
+ "node": ">= 4.0.0"
+ }
+ },
"node_modules/update-browserslist-db": {
"version": "1.1.0",
"resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.0.tgz",
@@ -1916,6 +2250,15 @@
"punycode": "^2.1.0"
}
},
+ "node_modules/url-parse": {
+ "version": "1.5.10",
+ "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
+ "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==",
+ "dependencies": {
+ "querystringify": "^2.1.1",
+ "requires-port": "^1.0.0"
+ }
+ },
"node_modules/url-toolkit": {
"version": "2.2.5",
"resolved": "https://registry.npmjs.org/url-toolkit/-/url-toolkit-2.2.5.tgz",
@@ -1976,6 +2319,17 @@
"global": "^4.3.1"
}
},
+ "node_modules/w3c-xmlserializer": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-5.0.0.tgz",
+ "integrity": "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==",
+ "dependencies": {
+ "xml-name-validator": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/watchpack": {
"version": "2.4.1",
"resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.1.tgz",
@@ -1989,6 +2343,14 @@
"node": ">=10.13.0"
}
},
+ "node_modules/webidl-conversions": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz",
+ "integrity": "sha512-VwddBukDzu71offAQR975unBIGqfKZpM+8ZX6ySk8nYhVoo5CYaZyzt3YBvYtRtO+aoGlqxPg/B87NGVZ/fu6g==",
+ "engines": {
+ "node": ">=12"
+ }
+ },
"node_modules/webpack": {
"version": "5.92.1",
"resolved": "https://registry.npmjs.org/webpack/-/webpack-5.92.1.tgz",
@@ -2113,6 +2475,37 @@
"node": ">=10.13.0"
}
},
+ "node_modules/whatwg-encoding": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-3.1.1.tgz",
+ "integrity": "sha512-6qN4hJdMwfYBtE3YBTTHhoeuUrDBPZmbQaxWAqSALV/MeEnR5z1xd8UKud2RAkFoPkmB+hli1TZSnyi84xz1vQ==",
+ "dependencies": {
+ "iconv-lite": "0.6.3"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-mimetype": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-4.0.0.tgz",
+ "integrity": "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/whatwg-url": {
+ "version": "14.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.0.0.tgz",
+ "integrity": "sha512-1lfMEm2IEr7RIV+f4lUNPOqfFL+pO+Xw3fJSqmjX9AbXcXcYOkCe1P6+9VBZB6n94af16NfZf+sSk0JCBZC9aw==",
+ "dependencies": {
+ "tr46": "^5.0.0",
+ "webidl-conversions": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -2134,6 +2527,39 @@
"integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==",
"dev": true
},
+ "node_modules/ws": {
+ "version": "8.18.0",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz",
+ "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/xml-name-validator": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-5.0.0.tgz",
+ "integrity": "sha512-EvGK8EJ3DhaHfbRlETOWAS5pO9MZITeauHKJyb8wyajUfQUenkIg2MvLDTZ4T/TgIcm3HU0TFBgWWboAZ30UHg==",
+ "engines": {
+ "node": ">=18"
+ }
+ },
+ "node_modules/xmlchars": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz",
+ "integrity": "sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw=="
+ },
"node_modules/yallist": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
diff --git a/package.json b/package.json
index 7f53a25e..02507fae 100644
--- a/package.json
+++ b/package.json
@@ -5,8 +5,10 @@
"dayjs": "^1.11.11",
"easymde": "^2.18.0",
"htm": "^3.1.1",
+ "isomorphic-dompurify": "^2.13.0",
"jquery": "^3.6.1",
"jquery-migrate": "^3.4.0",
+ "marked": "^13.0.2",
"sass": "^1.69.5",
"video.js": "^8.10.0"
},
diff --git a/ui/base/element.js b/ui/base/element.js
index d59abdb5..3ba05522 100644
--- a/ui/base/element.js
+++ b/ui/base/element.js
@@ -106,4 +106,10 @@ export class OBElement extends HTMLElement {
return null; // Return null if no ancestor with the specified tag name is found
}
+
+ // add a listener if not already added
+ ensureListener(element, event, callback) {
+ element.removeEventListener(event, callback);
+ element.addEventListener(event, callback);
+ }
}
diff --git a/ui/base/field.js b/ui/base/field.js
index 27a1685c..23de3b57 100644
--- a/ui/base/field.js
+++ b/ui/base/field.js
@@ -2,24 +2,26 @@ import { html, render } from "../vendor.js";
import { OBElement } from "../base/element.js";
export class OBField extends OBElement {
+ _value;
+ _editable;
+ _settings;
+
async connectedCallback() {
if (this.connected) {
await this.connected();
}
- if (this.getAttribute("value")) {
- this.value = this.getAttribute("value");
+ if (this.getAttribute("value") && this._value === undefined) {
+ this._value = this.getAttribute("value");
}
- this.resolveInitialized();
- }
+ if (this.hasAttribute("data-edit") && this._editable === undefined) {
+ this._editable = true;
+ }
- renderView() {
- render(html` ${this.value} `, this.root);
- }
+ this.resolveInitialized();
- renderEdit() {
- render(html`
`, this.root);
+ this.renderComponent();
}
// Bind this to events inside the shadowroot to propagate them to outside
@@ -37,37 +39,42 @@ export class OBField extends OBElement {
}
get value() {
- if (this.root.querySelector("input")) {
- return this.root.querySelector("input").value;
- }
+ return this._value;
}
set value(value) {
- if (!this.root.querySelector("input")) {
- return;
- }
-
- this.root.querySelector("input").value = value;
- this.renderComponent();
+ this._value = value;
+ this.refresh();
}
get editable() {
- return this.hasAttribute("data-edit");
+ return this._editable;
}
- set editable(value) {
- if (value) {
- this.setAttribute("data-edit", "");
- } else {
- this.removeAttribute("data-edit");
- }
+ set editable(editable) {
+ this._editable = !!editable;
+ this.refresh();
+ }
- this.renderComponent();
+ get settings() {
+ return this._settings;
+ }
+
+ set settings(settings) {
+ this._settings = settings;
+ this.refresh();
}
async renderComponent() {
- const edit = this.hasAttribute("data-edit");
- if (edit) this.renderEdit();
- else this.renderView();
+ if (this._editable) await this.renderEdit();
+ else await this.renderView();
+ }
+
+ async renderView() {
+ render(html`
${this._value}
`, this.root);
+ }
+
+ async renderEdit() {
+ render(html`
`, this.root);
}
}
diff --git a/ui/fields/bool.js b/ui/fields/bool.js
index b1e0d9cf..076ed7d9 100644
--- a/ui/fields/bool.js
+++ b/ui/fields/bool.js
@@ -2,30 +2,17 @@ import { html, render } from "../vendor.js";
import { OBField } from "../base/field.js";
class OBFieldBool extends OBField {
- #init;
-
- async connectedCallback() {
- if (this.#init) {
- return;
- }
- this.#init = true;
-
- this.renderComponent().then(() => {
- if (this.hasAttribute("value")) {
- const value = this.getAttribute("value");
- if (value.toLowerCase() === "true" || value === "1") {
- this.root.querySelector("input").checked = true;
- }
- }
- });
+ renderView() {
+ const output = this._value ? "Yes" : "No";
+ render(html`${output}`, this.root);
}
renderEdit() {
- render(html`
`, this.root);
+ render(html`
`, this.root);
}
- renderView() {
- render(html`
`, this.root);
+ inputChange(event) {
+ this._value = event.target.checked;
}
scss() {
@@ -39,19 +26,6 @@ class OBFieldBool extends OBField {
}
`;
}
-
- get value() {
- if (this.root.querySelector("input")) {
- return this.root.querySelector("input").checked;
- } else {
- return false;
- }
- }
-
- set value(value) {
- this.root.querySelector("input").checked = value;
- this.renderComponent();
- }
}
customElements.define("ob-field-bool", OBFieldBool);
diff --git a/ui/fields/checkbox.js b/ui/fields/checkbox.js
index defd802a..96675ecc 100644
--- a/ui/fields/checkbox.js
+++ b/ui/fields/checkbox.js
@@ -1,6 +1,7 @@
import { html, render } from "../vendor.js";
import { OBField } from "../base/field.js";
+// TODO remove, use ob-field-boolean instead.
class OBFieldCheckbox extends OBField {
#init;
diff --git a/ui/fields/country.js b/ui/fields/country.js
index c7a6dcee..d8263556 100644
--- a/ui/fields/country.js
+++ b/ui/fields/country.js
@@ -2,8 +2,6 @@ import { html, render } from "../vendor.js";
import { OBField } from "../base/field.js";
class OBFieldCountry extends OBField {
- #init;
-
static countries = null;
async connected() {
@@ -17,42 +15,42 @@ class OBFieldCountry extends OBField {
OBFieldCountry.countries[country.country_id] = country.name;
}
}
-
- this.renderComponent().then(() => {});
}
renderEdit() {
- render(html`
`, this.root);
-
- const fieldSelect = this.root.querySelector("ob-field-select");
- fieldSelect.options = OBFieldCountry.countries;
- fieldSelect.refresh();
+ render(html`
`, this.root);
+ this.fieldSelect = this.root.querySelector("ob-field-select");
+ this.fieldSelect.options = OBFieldCountry.countries;
+ this.fieldSelect.value = this.value;
+
+ if (this.initValue) {
+ const temp = this.initValue;
+ this.initValue = false;
+ this.value = temp;
+ }
}
renderView() {
- render(html`
`, this.root);
-
- const fieldSelect = this.root.querySelector("ob-field-select");
- fieldSelect.options = OBFieldCountry.countries;
- fieldSelect.refresh();
+ render(html`${this.currentCountryName()}`, this.root);
}
- currentCountryName() {
+ async currentCountryName() {
+ await this.initialized;
return OBFieldCountry.countries[this.value];
}
get value() {
- const fieldSelect = this.root.querySelector("ob-field-select");
- if (fieldSelect) {
- return fieldSelect.value;
- }
+ return this.fieldSelect?.value;
}
set value(value) {
- const fieldSelect = this.root.querySelector("ob-field-select");
- if (fieldSelect) {
- fieldSelect.value = value;
+ if (this.fieldSelect) {
+ this.fieldSelect.value = value;
+ } else {
+ this.initValue = value;
}
+
+ this.refresh();
}
}
diff --git a/ui/fields/datetime.js b/ui/fields/datetime.js
index 16671700..baf5009f 100644
--- a/ui/fields/datetime.js
+++ b/ui/fields/datetime.js
@@ -2,40 +2,24 @@ import { html, render } from "../vendor.js";
import { OBField } from "../base/field.js";
class OBFieldDatetime extends OBField {
- #init;
-
- #valueObject;
- #valueString;
- #value;
- #setValue;
-
valueFormat = "YYYY-MM-DD HH:mm:ss";
valueStringFormat = "MMM D, YYYY h:mm A";
- async connected() {
- if (this.#init) {
- return;
- }
- this.#init = true;
-
- this.#valueObject = null;
- this.#valueString = "";
- this.#value = null;
-
- this.renderComponent().then(() => {});
+ renderView() {
+ render(html`
${this._valueString}
`, this.root);
}
renderEdit() {
render(
html`
-
+
`,
this.root,
);
}
- renderView() {
- render(html`
${this.#valueString}
`, this.root);
+ inputChange(event) {
+ this.value = event.target.value;
}
scss() {
@@ -56,30 +40,15 @@ class OBFieldDatetime extends OBField {
`;
}
- get value() {
- return this.#value;
- }
-
set value(value) {
- const inputElem = this.root.querySelector("#field");
- inputElem.value = value;
- inputElem.dispatchEvent(new Event("change"));
- }
-
- #updateValue(event) {
- const value = event.target.value;
const datetime = chrono.casual.parseDate(value);
- if (datetime) {
- this.#valueObject = datetime;
- this.#valueString = dayjs(datetime).format(this.valueStringFormat);
- this.#value = dayjs(datetime).format(this.valueFormat);
- } else {
- this.#valueObject = null;
- this.#valueString = "";
- this.#value = null;
- }
+ this._value = datetime ? dayjs(datetime).format(this.valueFormat) : "";
+ this._valueString = datetime ? dayjs(datetime).format(this.valueStringFormat) : "";
+ this.refresh();
+ }
- this.renderComponent();
+ get value() {
+ return this._value;
}
}
diff --git a/ui/fields/formatted.js b/ui/fields/formatted.js
index fe8285ee..793e8587 100644
--- a/ui/fields/formatted.js
+++ b/ui/fields/formatted.js
@@ -1,17 +1,26 @@
-import { html, render } from "../vendor.js";
+import { html, render, marked, dompurify } from "../vendor.js";
import { OBField } from "../base/field.js";
class OBFieldFormatted extends OBField {
#init;
#editorInstance;
- async connectedCallback() {
- if (this.#init) {
- return;
- }
- this.#init = true;
+ renderEdit() {
+ if (this.#editorInstance) {
+ // update value only
+ this.#editorInstance.value(this._value);
+ } else {
+ render(
+ html`
+
+
`,
+ this.root,
+ );
- this.renderComponent().then(() => {
this.#editorInstance = new EasyMDE({
element: this.root.querySelector("#edit"),
minHeight: "200px",
@@ -40,24 +49,15 @@ class OBFieldFormatted extends OBField {
}
},
});
- });
- }
- renderEdit() {
- render(
- html`
-
-
`,
- this.root,
- );
+ this.#editorInstance.codemirror.on("change", () => {
+ this._value = this.#editorInstance.value();
+ });
+ }
}
renderView() {
- render(html`
TODO
`, this.root);
+ this.root.innerHTML = `
${dompurify.sanitize(marked(this._value ?? ""))}
`;
}
scss() {
@@ -66,7 +66,6 @@ class OBFieldFormatted extends OBField {
display: inline-block;
position: relative;
z-index: 1000;
- color: #000;
max-width: 300px;
}
@@ -77,20 +76,15 @@ class OBFieldFormatted extends OBField {
.editor-toolbar {
background-color: #fff;
}
- `;
- }
- get value() {
- return this.root.querySelector("#edit").value;
- }
+ #view > *:first-child {
+ margin-top: 0;
+ }
- set value(value) {
- if (this.#editorInstance) {
- this.#editorInstance.value(value);
- } else {
- this.root.querySelector("#edit").value = value;
- }
- this.renderComponent();
+ #view > *:last-child {
+ margin-bottom: 0;
+ }
+ `;
}
}
diff --git a/ui/fields/group.js b/ui/fields/group.js
index d4ea4970..45b34a40 100644
--- a/ui/fields/group.js
+++ b/ui/fields/group.js
@@ -5,7 +5,7 @@ class OBFieldGroup extends OBField {
// languages are common to all instances of this element
static groups = null;
- async connectedCallback() {
+ async connected() {
if (OBFieldGroup.groups === null) {
// prevent multiple calls if this element appears twice in one form
OBFieldGroup.groups = {};
diff --git a/ui/fields/hidden.js b/ui/fields/hidden.js
index 1b071ba0..e01cae15 100644
--- a/ui/fields/hidden.js
+++ b/ui/fields/hidden.js
@@ -1,6 +1,7 @@
import { html, render } from "../vendor.js";
import { OBField } from "../base/field.js";
+// TODO is this need at all? will be removing "hidden" field type and replacing with hidden setting for other field types.
class OBFieldHidden extends OBField {
#init;
diff --git a/ui/fields/language.js b/ui/fields/language.js
index 4258f85d..e87238d5 100644
--- a/ui/fields/language.js
+++ b/ui/fields/language.js
@@ -5,9 +5,8 @@ class OBFieldLanguage extends OBField {
// languages are common to all instances of this element
static languages = null;
static popularLanguages = null;
- valuePending = false;
- async connectedCallback() {
+ async connected() {
if (OBFieldLanguage.languages === null) {
// prevent multiple calls if this element appears twice in one form
OBFieldLanguage.languages = {};
@@ -29,8 +28,6 @@ class OBFieldLanguage extends OBField {
// convert to array
OBFieldLanguage.popularLanguages = Object.values(popularLanguages);
}
-
- this.renderComponent();
}
get value() {
diff --git a/ui/fields/media.js b/ui/fields/media.js
index 81adbb8e..b3f39872 100644
--- a/ui/fields/media.js
+++ b/ui/fields/media.js
@@ -55,7 +55,9 @@ class OBFieldMedia extends OBField {
});
}
- renderEdit() {
+ async renderEdit() {
+ await this.mediaContent();
+
render(
html`
- ${this.#mediaItems.map(
+ ${this._value &&
+ this._value.map(
(mediaItem) => html`
${this.#mediaContent[mediaItem]}
@@ -82,7 +85,8 @@ class OBFieldMedia extends OBField {
`
: html``}
- ${this.#mediaItems.length === 0 &&
+ ${this._value &&
+ this._value.length === 0 &&
this.dataset.hasOwnProperty("single") &&
this.dataset.hasOwnProperty("record") &&
html`
@@ -131,11 +135,13 @@ class OBFieldMedia extends OBField {
);
}
- renderView() {
+ async renderView() {
+ await this.mediaContent();
+
render(
html`