(() => { // application/scripts/height_equaler.js var height_equaler = class { #to; #from; constructor(from, to) { this.#from = from; this.#to = to; this.#set_styles(); new ResizeObserver(() => { this.#update(); }).observe(from); setTimeout(() => { this.#update(); }, 100); } get height() { return this.#from.offsetHeight; } #set_styles() { this.#to.style.height = "0px"; this.#to.style.transition = "height 0.5s"; } #update() { this.#to.style.height = this.height + "px"; } }; // application/scripts/product.js var product = class { name; description; author; image; stock_count; barcode; constructor(target) { this.name = null; this.description = null; this.author = null; this.image = null; this.stock_count = null; this.barcode = null; if ("name" in target) this.name = target["name"]; if ("description" in target) this.description = target["description"]; if ("author" in target) this.author = target["author"]; if ("image" in target) this.image = target["image"]; if ("stock_count" in target) this.stock_count = target["stock_count"]; if ("barcode" in target) this.barcode = target["barcode"]; } get dump() { return { "name": this.name, "description": this.description, "author": this.author, "image": this.image, "stock_count": this.stock_count, "barcode": this.barcode }; } get ready() { if (this.name === null || this.description === null) return false; if (this.author === null || this.image === null) return false; if (this.stock_count === null || this.barcode === null) return false; return true; } }; // application/scripts/products_loader.js var products_loader = class _products_loader { static async all() { const request = await fetch("/products/"); const response = await request.json(); return _products_loader.#response_to_collection(response); } static #response_to_collection(response) { const result = new Array(); if (response.result !== "success") { return result; } response.collection.forEach((serialized) => { result.push(new product(serialized)); }); return result; } static async search_name(name) { return await _products_loader.#search( "/product/search/name", name ); } static async search_author(author) { return await _products_loader.#search( "/product/search/author", author ); } static async #search(path, parameter) { const coded = encodeURI(parameter); const request = await fetch(path + "/" + coded); const response = await request.json(); return _products_loader.#response_to_collection(response); } }; // application/scripts/fullscreen.js var fullscreen = class { #node; constructor() { this.#node = null; } get visible() { return this.#node !== null; } _build_node() { throw new TypeError("This is virtual method!"); } get #opacity() { if (!this.visible) { throw new TypeError("Can not change opacity of not existed."); } return Number(this.#node.style.opacity); } get_query(selector) { if (!this.visible) { throw new TypeError("Can not get item from not visible."); } return this.#node.querySelector(selector); } get #close() { const close_button = document.createElement("button"); close_button.classList.add("material-icons"); close_button.classList.add("close"); close_button.innerText = "close"; close_button.addEventListener("click", () => { this.hide(); }); return close_button; } #prepare() { if (!this.visible) { throw new TypeError("Can not prepare not existed."); } this.#node.style.transition = "opacity 0.5s"; this.#node.classList.add("fullscreen-viewer"); this.#node.appendChild(this.#close); } set #opacity(target) { if (!this.visible) { throw new TypeError("Can not change opacity of not existed."); } this.#node.style.opacity = String(target); } hide() { if (!this.visible) { return; } this.#opacity = 0; setTimeout(() => { if (!this.visible) { return; } this.#node.remove(); this.#node = null; }, 500); } show() { if (this.visible) { return; } this.#node = this._build_node(); this.#prepare(); this.#opacity = 0; document.querySelector("body").appendChild(this.#node); setTimeout(() => { this.#opacity = 1; }, 100); } }; // application/scripts/product_fullscreen.js var product_fullscreen = class extends fullscreen { #target; constructor(target) { super(); this.#target = target; } get target() { return this.#target; } _build_node() { const container = document.createElement("div"); container.classList.add("product-fullscreen-viewer"); const image = document.createElement("div"); image.style.backgroundImage = 'url("' + this.target.image + '")'; image.classList.add("image"); container.appendChild(image); const title = document.createElement("div"); title.classList.add("title"); container.appendChild(title); const title_content = document.createElement("h1"); title_content.innerText = this.target.name; title.appendChild(title_content); const bottom = document.createElement("div"); bottom.classList.add("bottom-side"); container.appendChild(bottom); const bottom_header = document.createElement("div"); bottom_header.classList.add("bottom-header"); bottom.appendChild(bottom_header); const barcode_icon = document.createElement("span"); barcode_icon.classList.add("material-icons"); barcode_icon.innerText = "qr_code_scanner"; const barcode_content = document.createElement("span"); barcode_content.innerText = this.target.barcode; barcode_content.classList.add("numbers"); const barcode = document.createElement("p"); barcode.appendChild(barcode_icon); barcode.appendChild(barcode_content); bottom_header.appendChild(barcode); const author_icon = document.createElement("span"); author_icon.classList.add("material-icons"); author_icon.innerText = "attribution"; const author_content = document.createElement("span"); author_content.innerText = this.target.author; const author = document.createElement("p"); author.appendChild(author_icon); author.appendChild(author_content); bottom_header.appendChild(author); const description = document.createElement("div"); description.classList.add("description"); bottom.appendChild(description); const description_content = document.createElement("p"); description_content.innerText = this.target.description; description.appendChild(description_content); return container; } }; // application/scripts/user.js var user = class { #nick; #apikey; constructor(nick, apikey) { this.#nick = nick; this.#apikey = apikey; } get nick() { return this.#nick; } get apikey() { return this.#apikey; } }; // application/scripts/login_manager.js var login_manager = class { get apikey() { return localStorage.getItem("apikey"); } get logged_in() { return localStorage.getItem("apikey") !== null; } #create_request(data) { return { method: "POST", body: JSON.stringify(data), headers: { "Content-Type": "application/json" } }; } async get_user() { if (!this.logged_in) { return null; } const request_data = this.#create_request({ apikey: this.apikey }); const request = await fetch("/user", request_data); const response = await request.json(); if (response.result !== "success") { return null; } return new user( response.nick, response.apikey ); } async login(nick, password) { const request_data = this.#create_request({ nick, password }); const request = await fetch("/user/login", request_data); const response = await request.json(); if (response.result !== "success") { return false; } localStorage.setItem("apikey", response.apikey); return true; } logout() { localStorage.removeItem("apikey"); } }; // application/scripts/product_container.js var product_container = class { #target; #node; #login; constructor(target) { this.#target = new product(target.dump); this.#node = null; this.#login = new login_manager().logged_in; } get #header() { const header = document.createElement("div"); header.classList.add("header"); const title = document.createElement("h3"); title.innerText = this.#target.name; header.appendChild(title); if (this.#login) { const manage = document.createElement("div"); manage.classList.add("manage"); header.appendChild(manage); manage.appendChild(this.#rent); manage.appendChild(this.#give_back); } return header; } get #rent() { const rent_button = document.createElement("button"); rent_button.classList.add("material-icons"); rent_button.classList.add("rent-button"); rent_button.innerText = "backpack"; return rent_button; } get #give_back() { const give_back_button = document.createElement("button"); give_back_button.classList.add("material-icons"); give_back_button.classList.add("rent-button"); give_back_button.innerText = "save_alt"; return give_back_button; } get #description() { const container = document.createElement("div"); container.classList.add("description"); const description = document.createElement("p"); description.innerText = this.#target.description; description.classList.add("content"); const author_container = document.createElement("div"); author_container.classList.add("author"); const author = document.createElement("span"); author.innerText = this.#target.author; const author_icon = document.createElement("span"); author_icon.classList.add("material-icons"); author_icon.innerText = "attribution"; author_container.appendChild(author_icon); author_container.appendChild(author); const stock_count = document.createElement("p"); stock_count.classList.add("stock-count"); stock_count.classList.add("material-icons"); if (this.#target.stock_count > 0) { stock_count.innerText = "check_circle"; stock_count.classList.add("avairable"); } else { stock_count.innerText = "cancel"; stock_count.classList.add("unavairable"); } const barcode_container = document.createElement("p"); barcode_container.classList.add("barcode"); const barcode = document.createElement("span"); barcode.innerText = this.#target.barcode; barcode.classList.add("numbers"); const barcode_icon = document.createElement("span"); barcode_icon.classList.add("material-icons"); barcode_icon.innerText = "qr_code_scanner"; barcode_container.appendChild(barcode_icon); barcode_container.appendChild(barcode); container.appendChild(description); container.appendChild(author_container); container.appendChild(barcode_container); container.appendChild(stock_count); return container; } get #image() { const image = document.createElement("img"); image.classList.add("image"); image.src = this.#target.image; image.alt = this.#target.name; image.addEventListener("click", () => { new product_fullscreen(this.#target).show(); }); return image; } get node() { if (this.#node !== null) { return this.#node; } const bottom_container = document.createElement("div"); bottom_container.classList.add("bottom-container"); bottom_container.appendChild(this.#description); bottom_container.appendChild(this.#image); const container = document.createElement("div"); container.classList.add("product"); container.appendChild(this.#header); container.appendChild(bottom_container); return this.#node = container; } add(target) { const node = this.node; node.style.opacity = "0"; node.style.transition = "opacity 0.5s"; target.appendChild(node); setTimeout(() => { node.style.opacity = "1"; }, 50); } drop() { const container = this.#node; if (container === null) { throw new TypeError("It is not showed yet."); } container.style.opacity = "1"; container.style.transition = "opacity 0.5s"; setTimeout(() => { container.style.opacity = "0"; }, 50); setTimeout(() => { this.#node = null; container.remove(); }, 550); } }; // application/scripts/product_containers.js var product_containers = class { #content; #where; #inserted; constructor(where) { this.#where = where; this.#content = new Array(); this.#inserted = new Array(); } add_list(target) { target.forEach((count) => { this.add(count); }); return this; } add(target) { const current = new product_container(target); this.#content.push(current); return this; } clean() { this.#content = new Array(); return this; } update() { this.#hide(); setTimeout(() => { this.#content.forEach((count) => { this.#inserted.push(count); count.add(this.#where); }); }, 500); return this; } #hide() { this.#inserted.forEach((count) => { if (!this.#content.includes(count)) { count.drop(); } }); this.#inserted = new Array(); return this; } }; // application/scripts/searcher.js var searcher = class { #input; #category; #manager; #result; constructor(search_form, manager, result) { this.#input = search_form.querySelector('input[type="text"]'); this.#category = search_form.querySelector("select"); this.#manager = manager; this.#result = result; this.#selector_complete(); search_form.addEventListener("submit", (target) => { target.preventDefault(); this.update(); }); } get categories() { return { "name": "Name", "author": "Author" }; } #selector_complete() { const category = this.#category; const categories = this.categories; Object.keys(categories).forEach((name) => { const option = document.createElement("option"); option.value = name; option.innerText = categories[name]; category.appendChild(option); }); } get #loader() { return { "name": products_loader.search_name, "author": products_loader.search_author }[this.category]; } get category() { return this.#category.value; } get phrase() { return this.#input.value.trim(); } get #result_title() { return this.#result.innerText; } set #result_title(target) { this.#result.innerText = target; } async update() { if (this.phrase.length === 0) { this.show_all(); return; } this.#insert(await this.#loader(this.phrase)); } #insert(list) { if (list.length === 0) { this.#result_title = "Not found anything."; } else { this.#result_title = "Browse our products!"; } this.#manager.clean().add_list(list).update(); } async show_all() { this.#insert(await products_loader.all()); } }; // application/scripts/login_prompt.js var login_prompt = class extends fullscreen { constructor(target) { super(); target.addEventListener("click", () => { this.show(); }); } get _nick() { return this.get_query("#nick").value; } get _password() { return this.get_query("#password").value; } get _result() { return this.get_query("#result"); } async _login() { const manager = new login_manager(); const result = await manager.login(this._nick, this._password); if (result) { this._result.style.color = "green"; this._result.innerText = "Login success!"; setTimeout(() => { location.reload(); }, 500); return; } this._result.style.color = "red"; this._result.innerText = "Can not login! Check login and password."; } _build_node() { const container = document.createElement("div"); container.classList.add("login-prompt"); const center = document.createElement("form"); center.classList.add("center"); container.appendChild(center); const nick_label = document.createElement("label"); nick_label.innerText = "Your nick:"; nick_label.htmlFor = "nick"; center.appendChild(nick_label); const nick = document.createElement("input"); nick.type = "text"; nick.name = "nick"; nick.id = "nick"; nick.placeholder = "Nick..."; center.appendChild(nick); const password_label = document.createElement("label"); password_label.innerText = "Your password:"; password_label.htmlFor = "password"; center.appendChild(password_label); const password = document.createElement("input"); password.type = "password"; password.name = "password"; password.id = "password"; password.placeholder = "Password..."; center.appendChild(password); const submit = document.createElement("button"); submit.type = "submit"; submit.classList.add("material-icons"); submit.innerText = "send"; center.appendChild(submit); const result = document.createElement("p"); result.id = "result"; result.classList.add("result"); center.appendChild(result); center.addEventListener("submit", (target) => { target.preventDefault(); this._login(); }); return container; } }; // application/scripts/product_adder.js var product_adder = class extends fullscreen { _build_node() { const container = document.createElement("div"); container.classList.add("product-adder"); const center = document.createElement("form"); center.classList.add("center"); container.appendChild(center); const label_name = document.createElement("label"); label_name.setAttribute("for", "name"); label_name.textContent = "Name:"; center.appendChild(label_name); const name = document.createElement("input"); name.type = "text"; name.id = "name"; name.name = "name"; name.placeholder = "Sample..."; center.appendChild(name); const label_description = document.createElement("label"); label_description.setAttribute("for", "description"); label_description.textContent = "Description:"; center.appendChild(label_description); const description = document.createElement("input"); description.type = "text"; description.id = "description"; description.name = "description"; description.placeholder = "This is exa..."; center.appendChild(description); const label_author = document.createElement("label"); label_author.setAttribute("for", "author"); label_author.textContent = "Author:"; center.appendChild(label_author); const author = document.createElement("input"); author.type = "text"; author.id = "author"; author.name = "author"; author.placeholder = "John Snow..."; center.appendChild(author); const label_barcode = document.createElement("label"); label_barcode.setAttribute("for", "barcode"); label_barcode.textContent = "Barcode:"; center.appendChild(label_barcode); const barcode = document.createElement("input"); barcode.type = "number"; barcode.id = "barcode"; barcode.name = "barcode"; barcode.placeholder = "Enter EAN-12..."; center.appendChild(barcode); const label_stock_count = document.createElement("label"); label_stock_count.setAttribute("for", "stock-count"); label_stock_count.textContent = "On stock:"; center.appendChild(label_stock_count); const stock_count = document.createElement("input"); stock_count.type = "number"; stock_count.id = "stock-count"; stock_count.name = "stock-count"; stock_count.placeholder = "20..."; center.appendChild(stock_count); const button = document.createElement("button"); button.type = "submit"; button.id = "add"; button.name = "add"; button.className = "material-icons"; button.textContent = "add"; center.appendChild(button); return container; } }; // application/scripts/login_bar.js var login_bar = class { #manager; constructor(target) { this.#manager = new login_manager(); if (!this.#manager.logged_in) { this.#not_logged(target); return; } this.#logged(target); } #not_login_propertly() { this.#manager.logout(); location.reload(); } async #logged(target) { const user2 = await this.#manager.get_user(); if (user2 === null) { this.#not_login_propertly(); } const info_icon = document.createElement("span"); info_icon.classList.add("icon"); info_icon.classList.add("material-icons"); info_icon.innerText = "account_circle"; const info_content = document.createElement("span"); info_content.innerText = user2.nick; const info = document.createElement("p"); info.classList.add("login-info"); info.appendChild(info_icon); info.appendChild(info_content); target.appendChild(info); const logout_button = document.createElement("button"); logout_button.innerText = "logout"; logout_button.classList.add("logout-button"); logout_button.classList.add("material-icons"); target.appendChild(logout_button); const add_product_button = document.createElement("button"); add_product_button.innerText = "add"; add_product_button.classList.add("add-product-button"); add_product_button.classList.add("material-icons"); target.appendChild(add_product_button); add_product_button.addEventListener("click", () => { new product_adder().show(); }); logout_button.addEventListener("click", () => { this.#manager.logout(); location.reload(); }); } #not_logged(target) { const login_button = document.createElement("button"); login_button.innerText = "account_circle"; login_button.classList.add("login-button"); login_button.classList.add("material-icons"); target.appendChild(login_button); new login_prompt(login_button); } }; // application/scripts/core.js document.addEventListener("DOMContentLoaded", async () => { const top_bar_spacing = new height_equaler( document.querySelector(".top-bar"), document.querySelector(".top-bar-spacing") ); const container = document.querySelector(".products"); const search_bar = document.querySelector("form.search"); const search_title = document.querySelector(".search-title"); const login_space = document.querySelector(".top-bar .right"); const manager = new product_containers(container); new login_bar(login_space); new searcher(search_bar, manager, search_title).show_all(); }); })();