UNPKG

wj-elements

Version:

WebJET Elements is a modern set of user interface tools harnessing the power of web components designed to simplify web application development.

436 lines (435 loc) 15.6 kB
var __defProp = Object.defineProperty; var __typeError = (msg) => { throw TypeError(msg); }; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg); var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj)); var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value); var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value); var _loadedOptions, _drawPreloadedElements; import WJElement from "./wje-element.js"; import InfiniteScroll from "./wje-infinite-scroll.js"; import List from "./wje-list.js"; import Option from "./wje-option.js"; import { event } from "./event.js"; class Options extends WJElement { /** * Creates an instance of Options. * @class */ constructor() { super(); /** * Stores the loaded options. * @type {Array} * @private */ __privateAdd(this, _loadedOptions, []); __privateAdd(this, _drawPreloadedElements, []); __publicField(this, "dependencies", { "wje-option": Option, "wje-infinite-scroll": InfiniteScroll, "wje-list": List }); __publicField(this, "className", "Options"); /** * Recursively updates the object based on the provided path to the property. * @param {object | Array | null} object * @param {Array<string> | null} pathToProperty * @returns {object | Array | null} */ __publicField(this, "recursiveUpdate", (object, pathToProperty) => { var _a; if (pathToProperty.length === 0) { if (Array.isArray(object)) { return object.filter( (option) => !this.loadedOptions.some( (loadedOption) => loadedOption[this.itemValue] === option[this.itemValue] ) ); } else { console.error("Expected an array but got:", object, pathToProperty); return []; } } const [currentPath, ...remainingPath] = pathToProperty; if (remainingPath.length > 0) { object[currentPath] = this.recursiveUpdate(object[currentPath], remainingPath); } else { object[currentPath] = ((_a = object[currentPath]) == null ? void 0 : _a.filter( (option) => !this.loadedOptions.some( (loadedOption) => loadedOption[this.itemValue] === option[this.itemValue] ) )) ?? []; } return object; }); /** * Generates an HTML option element based on the provided item. * @param {object} item The item to generate the option element for. * @returns {HTMLElement} The generated option element. */ __publicField(this, "htmlItem", (item) => { let option = document.createElement("wje-option"); if (item[this.itemValue] === null || item[this.itemValue] === void 0) { console.warn(`The item ${JSON.stringify(item)} does not have the property ${this.itemValue}`); } if (item[this.itemText] === null || item[this.itemText] === void 0) { console.warn(`The item ${JSON.stringify(item)} does not have the property ${this.itemText}`); } option.setAttribute("value", item[this.itemValue] ?? ""); option.innerText = item[this.itemText] ?? ""; return option; }); } /** * Returns the list of attributes to observe for changes. * @static * @returns {Array<string>} */ static get observedAttributes() { return ["search", "attached"]; } /** * Sets the option array path attribute. * @param {string} value The value to set for the option array path. */ set optionArrayPath(value) { this.setAttribute("option-array-path", value); } /** * Gets the option array path attribute. * @returns {string} The value of the option array path attribute or "data" if not set. */ get optionArrayPath() { return this.getAttribute("option-array-path"); } /** * Checks if the option array path attribute is present. * @returns {boolean} True if the option array path attribute is present, false otherwise. */ get hasOptionArrayPath() { return this.hasAttribute("option-array-path"); } /** * Gets the dropdown height attribute. * @returns {string} The value of the dropdown height attribute or "100%" if not set. */ get dropdownHeight() { return this.getAttribute("dropdown-height") || "100%"; } /** * Sets the dropdown height attribute. * @param {string} value The value to set for the dropdown height. */ set dropdownHeight(value) { this.setAttribute("dropdown-height", value); } /** * Sets the item value attribute. * @param {string} value The value to set for the item value. */ set itemValue(value) { this.setAttribute("item-value", value); } /** * Gets the item value attribute. * @returns {string} The value of the item value attribute or "value" if not set. */ get itemValue() { return this.getAttribute("item-value") || "value"; } /** * Sets the item text attribute. * @param {string} value The value to set for the item text. */ set itemText(value) { this.setAttribute("item-text", value); } /** * Gets the item text attribute. * @returns {string} The value of the item text attribute or "text" if not set. */ get itemText() { return this.getAttribute("item-text") || "text"; } /** * Gets the lazy load size attribute. * @returns {number} The value of the lazy load size attribute or 10 if not set. */ get lazyLoadSize() { return this.getAttribute("lazy-load-size") || 10; } /** * Sets the lazy load size attribute. * @param {number} value The value to set for the lazy load size. */ set lazyLoadSize(value) { this.setAttribute("lazy-load-size", value); } /** * Sets the search attribute. * @param {string} value The value to set for the search. */ set search(value) { this.setAttribute("search", value); } /** * Gets the search attribute. * @returns {string} The value of the search attribute. */ get search() { return this.getAttribute("search"); } /** * Checks if the search attribute is present. * @returns {boolean} True if the search attribute is present, false otherwise. */ get hasSearch() { return this.hasAttribute("search"); } /** * Retrieves the value of the 'search-to-query-params' attribute from the current instance. * @returns {string | null} The value of the 'search-to-query-params' attribute, or null if the attribute is not set. */ get searchToQueryParams() { return this.getAttribute("search-to-query-params"); } /** * Sets the value to define search-to-query params behavior. * @param {string} value The value to be set for the search-to-query-params attribute. */ set searchToQueryParams(value) { this.setAttribute("search-to-query-params", value); } /** * Determines whether the 'search-to-query-params' attribute is present on the element. * @returns {boolean} True if the 'search-to-query-params' attribute exists, otherwise false. */ get hasSearchToQueryParams() { return this.hasAttribute("search-to-query-params"); } /** * Sets the value of the search parameter name attribute. * @param {string} value The string value to set as the search parameter name. */ set searchParamName(value) { this.setAttribute("search-param-name", value); } /** * Gets the search parameter name used in queries. * Retrieves the value of the 'search-param-name' attribute. * If the attribute is not set, it defaults to 'search'. * @returns {string} The search parameter name used for queries. */ get searchParamName() { return this.getAttribute("search-param-name") || "search"; } /** * Sets the queryParams attribute on the element. * @param {string} value The query parameters to set, represented as a string. */ set queryParams(value) { this.setAttribute("query-params", value); } /** * Retrieves the value of the 'query-params' attribute. * @returns {string | null} The value of the 'query-params' attribute, or null if the attribute is not set. */ get queryParams() { return this.getAttribute("query-params"); } /** * Checks if the lazy attribute is present. * @returns {boolean} True if the lazy attribute is present, false otherwise. */ get lazy() { return this.hasAttribute("lazy"); } /** * Sets the lazy attribute. * @param {boolean} value The value to set for the lazy attribute. */ set lazy(value) { this.setAttribute("lazy", value); } /** * Gets the loaded options. * @returns {Array} The loaded options. */ get options() { var _a; return (_a = this.loadedOptions) == null ? void 0 : _a.flat(); } /** * Gets the loaded options. * @type {Array} */ get loadedOptions() { return __privateGet(this, _loadedOptions); } /** * Sets the loaded options. * @type {Array} */ set loadedOptions(loadedOptions) { __privateSet(this, _loadedOptions, loadedOptions); } /** * Array of preloaded elements. * @type {Array} * @private */ get drawPreloadedElements() { return __privateGet(this, _drawPreloadedElements); } set drawPreloadedElements(elements) { __privateSet(this, _drawPreloadedElements, elements); } /** * Sets up the attributes for the component. */ setupAttributes() { this.isShadowRoot = "open"; } /** * Prepares the component before drawing. * Fetches the pages and creates the options elements. */ afterDraw() { } /** * Draws the component. * @returns {DocumentFragment} */ async draw() { let fragment = document.createDocumentFragment(); const slot = document.createElement("slot"); fragment.appendChild(slot); if (this.hasAttribute("lazy")) { if (this.contains(this.infiniteScroll)) { this.drawPreloadedElements.forEach((el) => { el.remove(); }); this.loadedOptions = []; this.infiniteScroll.placementObj.innerHTML = ""; this.infiniteScroll.totalPages = 0; this.infiniteScroll.refresh(); return fragment; } const infiniteScroll = document.createElement("wje-infinite-scroll"); infiniteScroll.setAttribute("placement", "wje-list"); infiniteScroll.setAttribute("height", this.dropdownHeight); infiniteScroll.setAttribute("object-name", this.optionArrayPath); const list = document.createElement("wje-list"); infiniteScroll.append(list); infiniteScroll.dataToHtml = this.htmlItem; infiniteScroll.setCustomData = async (page, signal) => { let processedUrl = `${this.url}${this.search ? `/${this.search}` : ""}?page=${page}&size=${this.lazyLoadSize}${this.queryParams ? `&${this.queryParams}` : ""}`; if (this.hasSearchToQueryParams) { processedUrl = `${this.url}?page=${page}&size=${this.lazyLoadSize}${this.queryParams ? `&${this.queryParams}` : ""}${this.search ? `&${this.searchParamName}=${this.search}` : ""}`; } let res = await this.service.get(processedUrl, null, false, signal); const filteredOptions = this.filterOutDrawnOptions(res); this.loadedOptions.push(...this.processData(filteredOptions)); return filteredOptions; }; event.addListener(infiniteScroll, "wje-infinite-scroll:load", null, (e) => { event.dispatchCustomEvent(this, "wje-options:load", {}); }); if (this.hasAttribute("attached")) { this.appendChild(infiniteScroll); this.drawPreloadedElements.forEach((el) => { list.appendChild(el); }); } this.infiniteScroll = infiniteScroll; } else { this.response = await this.getPages(); let optionsData = this.filterOutDrawnOptions(this.response); optionsData = this.processData(optionsData); this.loadedOptions.push(...optionsData); this.append(...optionsData.map(this.htmlItem)); event.dispatchCustomEvent(this, "wje-options:load", {}); } return fragment; } /** * Processes the given data and returns the options based on the option array path. * @param {any} data The data to be processed. * @returns {any} - The options based on the option array path. */ processData(data) { var _a; const splittedOptionArrayPath = this.optionArrayPath ? (_a = this.optionArrayPath) == null ? void 0 : _a.split(".") : null; let options = data; splittedOptionArrayPath == null ? void 0 : splittedOptionArrayPath.forEach((path) => { options = options[path]; }); return options ?? []; } /** * Filters out drawn options from the response. * @param {object | null} response The response to filter. * @returns {object} The filtered response. */ filterOutDrawnOptions(response) { var _a; const splittedOptionArrayPath = this.optionArrayPath ? (_a = this.optionArrayPath) == null ? void 0 : _a.split(".") : []; let filteredResponse = structuredClone(response); filteredResponse = this.recursiveUpdate(filteredResponse, splittedOptionArrayPath); return filteredResponse; } /** * Fetches the pages from the provided URL. * @param {number} page The page number to fetch. * @returns {Promise<object>} The fetched data. * @throws Will throw an error if the response is not ok. */ async getPages(page) { const response = await fetch(this.url); if (!response.ok) { throw new Error(`An error occurred: ${response.status}`); } return await response.json(); } /** * Finds the selected option data based on the given selected option values. * @param {Array} selectedOptionValues The array of selected option values. * @returns {Array} - The array of option data that matches the selected option values. */ findSelectedOptionData(selectedOptionValues = []) { return this.options.filter((option) => selectedOptionValues.includes(option[this.itemValue])); } /** * Adds an option to the element. * @param {object} optionData The data of the option to be added. */ addOption(optionData) { if (this.loadedOptions.some((option) => option[this.itemValue] === optionData[this.itemValue])) { return; } const item = this.htmlItem(optionData); __privateGet(this, _drawPreloadedElements).push(item); this.prepend(item); this.loadedOptions.push(optionData); } /** * Adds options to the element. * @param {Array} optionsData The array of option data to be added. * @param {boolean} [silent] Whether to suppress events triggered by adding options. */ addOptions(optionsData = [], silent = false) { if (Array.isArray(optionsData)) optionsData == null ? void 0 : optionsData.forEach((od) => this.addOption(od, silent)); else this.addOption(optionsData, silent); } } _loadedOptions = new WeakMap(); _drawPreloadedElements = new WeakMap(); Options.define("wje-options", Options); export { Options as default }; //# sourceMappingURL=wje-options.js.map