app.js 43 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551
  1. (() => {
  2. // application/scripts/height_equaler.js
  3. var height_equaler = class {
  4. #to;
  5. #from;
  6. constructor(from, to) {
  7. this.#from = from;
  8. this.#to = to;
  9. this.#set_styles();
  10. new ResizeObserver(() => {
  11. this.#update();
  12. }).observe(from);
  13. setTimeout(() => {
  14. this.#update();
  15. }, 100);
  16. }
  17. get height() {
  18. return this.#from.offsetHeight;
  19. }
  20. #set_styles() {
  21. this.#to.style.height = "0px";
  22. this.#to.style.transition = "height 0.5s";
  23. }
  24. #update() {
  25. this.#to.style.height = this.height + "px";
  26. }
  27. };
  28. // application/scripts/product.js
  29. var product = class _product {
  30. name;
  31. description;
  32. author;
  33. image;
  34. stock_count;
  35. barcode;
  36. thumbnail;
  37. constructor(target) {
  38. this.name = null;
  39. this.description = null;
  40. this.author = null;
  41. this.image = null;
  42. this.stock_count = null;
  43. this.barcode = null;
  44. this.thumbnail = null;
  45. if ("name" in target) this.name = target["name"];
  46. if ("description" in target) this.description = target["description"];
  47. if ("author" in target) this.author = target["author"];
  48. if ("image" in target) this.image = target["image"];
  49. if ("stock_count" in target) this.stock_count = target["stock_count"];
  50. if ("barcode" in target) this.barcode = target["barcode"];
  51. if ("thumbnail" in target) this.thumbnail = target["thumbnail"];
  52. }
  53. get dump() {
  54. return {
  55. "name": this.name,
  56. "description": this.description,
  57. "author": this.author,
  58. "image": this.image,
  59. "stock_count": this.stock_count,
  60. "barcode": this.barcode,
  61. "thumbnail": this.thumbnail
  62. };
  63. }
  64. get ready() {
  65. if (this.name === null || this.description === null) return false;
  66. if (this.author === null || this.image === null) return false;
  67. if (this.stock_count === null || this.barcode === null) return false;
  68. if (this.thumbnail === null) return false;
  69. return true;
  70. }
  71. copy() {
  72. return new _product(this.dump);
  73. }
  74. };
  75. // application/scripts/products_loader.js
  76. var products_loader = class _products_loader {
  77. static async all() {
  78. const request2 = await fetch("/products/");
  79. const response = await request2.json();
  80. return _products_loader.#response_to_collection(response);
  81. }
  82. static #response_to_collection(response) {
  83. const result = new Array();
  84. if (response.result !== "success") {
  85. return result;
  86. }
  87. response.collection.forEach((serialized) => {
  88. result.push(new product(serialized));
  89. });
  90. return result;
  91. }
  92. static async search_name(name) {
  93. return await _products_loader.#search(
  94. "/product/search/name",
  95. name
  96. );
  97. }
  98. static async search_author(author) {
  99. return await _products_loader.#search(
  100. "/product/search/author",
  101. author
  102. );
  103. }
  104. static async #search(path, parameter) {
  105. const coded = encodeURI(parameter);
  106. const request2 = await fetch(path + "/" + coded);
  107. const response = await request2.json();
  108. return _products_loader.#response_to_collection(response);
  109. }
  110. };
  111. // application/scripts/fullscreen.js
  112. var fullscreen = class {
  113. #node;
  114. constructor() {
  115. this.#node = null;
  116. }
  117. get visible() {
  118. return this.#node !== null;
  119. }
  120. _build_node() {
  121. throw new TypeError("This is virtual method!");
  122. }
  123. get #opacity() {
  124. if (!this.visible) {
  125. throw new TypeError("Can not change opacity of not existed.");
  126. }
  127. return Number(this.#node.style.opacity);
  128. }
  129. set #opacity(target) {
  130. if (!this.visible) {
  131. throw new TypeError("Can not change opacity of not existed.");
  132. }
  133. this.#node.style.opacity = String(target);
  134. }
  135. get_query(selector) {
  136. if (!this.visible) {
  137. throw new TypeError("Can not get item from not visible.");
  138. }
  139. return this.#node.querySelector(selector);
  140. }
  141. #prepare() {
  142. const container = document.createElement("div");
  143. container.classList.add("fullscreen-viewer");
  144. container.style.transition = "opacity 0.5s";
  145. container.appendChild(this._build_node());
  146. return container;
  147. }
  148. hide() {
  149. if (!this.visible) {
  150. return;
  151. }
  152. this.#opacity = 0;
  153. setTimeout(() => {
  154. if (!this.visible) {
  155. return;
  156. }
  157. this.#node.remove();
  158. this.#node = null;
  159. }, 500);
  160. }
  161. show() {
  162. if (this.visible) {
  163. return;
  164. }
  165. this.#node = this.#prepare();
  166. this.#opacity = 0;
  167. document.querySelector("body").appendChild(this.#node);
  168. setTimeout(() => {
  169. this.#opacity = 1;
  170. }, 100);
  171. }
  172. };
  173. // application/scripts/product_fullscreen.js
  174. var product_fullscreen = class extends fullscreen {
  175. #target;
  176. constructor(target) {
  177. super();
  178. this.#target = target;
  179. }
  180. get target() {
  181. return this.#target;
  182. }
  183. _build_node() {
  184. const container = document.createElement("div");
  185. container.classList.add("product-fullscreen-viewer");
  186. const image = document.createElement("div");
  187. image.style.backgroundImage = 'url("' + this.target.image + '")';
  188. image.classList.add("image");
  189. container.appendChild(image);
  190. const title = document.createElement("div");
  191. title.classList.add("title");
  192. container.appendChild(title);
  193. const title_content = document.createElement("h1");
  194. title_content.innerText = this.target.name;
  195. title.appendChild(title_content);
  196. const bottom = document.createElement("div");
  197. bottom.classList.add("bottom-side");
  198. container.appendChild(bottom);
  199. const bottom_header = document.createElement("div");
  200. bottom_header.classList.add("bottom-header");
  201. bottom.appendChild(bottom_header);
  202. const barcode_icon = document.createElement("span");
  203. barcode_icon.classList.add("material-icons");
  204. barcode_icon.innerText = "qr_code_scanner";
  205. const barcode_content = document.createElement("span");
  206. barcode_content.innerText = this.target.barcode;
  207. barcode_content.classList.add("numbers");
  208. const barcode = document.createElement("p");
  209. barcode.appendChild(barcode_icon);
  210. barcode.appendChild(barcode_content);
  211. bottom_header.appendChild(barcode);
  212. const author_icon = document.createElement("span");
  213. author_icon.classList.add("material-icons");
  214. author_icon.innerText = "attribution";
  215. const author_content = document.createElement("span");
  216. author_content.innerText = this.target.author;
  217. const author = document.createElement("p");
  218. author.appendChild(author_icon);
  219. author.appendChild(author_content);
  220. bottom_header.appendChild(author);
  221. const description = document.createElement("div");
  222. description.classList.add("description");
  223. bottom.appendChild(description);
  224. const description_content = document.createElement("p");
  225. description_content.innerText = this.target.description;
  226. description.appendChild(description_content);
  227. const close_button = document.createElement("button");
  228. close_button.classList.add("material-icons");
  229. close_button.classList.add("close");
  230. close_button.innerText = "close";
  231. container.appendChild(close_button);
  232. close_button.addEventListener("click", () => {
  233. this.hide();
  234. });
  235. return container;
  236. }
  237. };
  238. // application/scripts/user.js
  239. var user = class {
  240. #nick;
  241. #apikey;
  242. constructor(nick, apikey) {
  243. this.#nick = nick;
  244. this.#apikey = apikey;
  245. }
  246. get nick() {
  247. return this.#nick;
  248. }
  249. get apikey() {
  250. return this.#apikey;
  251. }
  252. };
  253. // application/scripts/login_manager.js
  254. var login_manager = class {
  255. get apikey() {
  256. return localStorage.getItem("apikey");
  257. }
  258. get logged_in() {
  259. return localStorage.getItem("apikey") !== null;
  260. }
  261. #create_request(data) {
  262. return {
  263. method: "POST",
  264. body: JSON.stringify(data),
  265. headers: {
  266. "Content-Type": "application/json"
  267. }
  268. };
  269. }
  270. async get_user() {
  271. if (!this.logged_in) {
  272. return null;
  273. }
  274. const request_data = this.#create_request({
  275. apikey: this.apikey
  276. });
  277. const request2 = await fetch("/user", request_data);
  278. const response = await request2.json();
  279. if (response.result !== "success") {
  280. return null;
  281. }
  282. return new user(
  283. response.nick,
  284. response.apikey
  285. );
  286. }
  287. async login(nick, password) {
  288. const request_data = this.#create_request({
  289. nick,
  290. password
  291. });
  292. const request2 = await fetch("/user/login", request_data);
  293. const response = await request2.json();
  294. if (response.result !== "success") {
  295. return false;
  296. }
  297. localStorage.setItem("apikey", response.apikey);
  298. return true;
  299. }
  300. logout() {
  301. localStorage.removeItem("apikey");
  302. }
  303. };
  304. // application/scripts/confirm_action.js
  305. var confirm_action = class {
  306. #node;
  307. #action;
  308. constructor() {
  309. this.#node = null;
  310. this.#action = true;
  311. }
  312. get _description() {
  313. throw new TypeError("It must be overwriten.");
  314. }
  315. get _title() {
  316. return "You must confirm it.";
  317. }
  318. _action() {
  319. throw new TypeError("It must be overwriten.");
  320. }
  321. show() {
  322. if (this.#node !== null) {
  323. return;
  324. }
  325. this.#action = true;
  326. this.#node = this.#create_window();
  327. document.querySelector("body").appendChild(this.#node);
  328. setTimeout(() => {
  329. this.#node.style.opacity = "1";
  330. }, 100);
  331. }
  332. hide() {
  333. if (this.#node === null) {
  334. return;
  335. }
  336. this.#action = false;
  337. this.#node.style.opacity = "0";
  338. setTimeout(() => {
  339. if (this.#node === null) {
  340. return;
  341. }
  342. this.#node.remove();
  343. this.#node = null;
  344. }, 500);
  345. }
  346. #create_window() {
  347. const container = document.createElement("div");
  348. container.classList.add("confirm-window");
  349. container.style.transition = "opacity 0.5s";
  350. container.style.opacity = "0";
  351. const center = document.createElement("div");
  352. center.classList.add("center");
  353. container.appendChild(center);
  354. const title = document.createElement("div");
  355. title.classList.add("title");
  356. center.appendChild(title);
  357. const title_text = document.createElement("h3");
  358. title_text.innerText = this._title;
  359. title.appendChild(title_text);
  360. const description = document.createElement("div");
  361. description.classList.add("description");
  362. center.appendChild(description);
  363. const description_text = document.createElement("p");
  364. description_text.innerText = this._description;
  365. description.appendChild(description_text);
  366. const buttons = document.createElement("div");
  367. buttons.classList.add("buttons");
  368. center.appendChild(buttons);
  369. const cancel_button = document.createElement("button");
  370. cancel_button.classList.add("cancel");
  371. cancel_button.classList.add("material-icons");
  372. cancel_button.innerText = "clear";
  373. buttons.appendChild(cancel_button);
  374. const confirm_button = document.createElement("button");
  375. confirm_button.classList.add("confirm");
  376. confirm_button.classList.add("material-icons");
  377. confirm_button.innerText = "send";
  378. buttons.appendChild(confirm_button);
  379. cancel_button.addEventListener("click", () => {
  380. this.hide();
  381. });
  382. confirm_button.addEventListener("click", () => {
  383. if (this.#action === false) {
  384. return;
  385. }
  386. this._action();
  387. this.hide();
  388. });
  389. return container;
  390. }
  391. };
  392. // application/scripts/request.js
  393. var request = class {
  394. get settings() {
  395. return {
  396. "method": this.method,
  397. "headers": this.headers,
  398. "body": this.body
  399. };
  400. }
  401. get _apikey() {
  402. const manager = new login_manager();
  403. if (manager.logged_in) {
  404. return manager.apikey;
  405. }
  406. throw new Error("User must be logged in.");
  407. }
  408. get method() {
  409. throw new TypeError("It must be overwrite.");
  410. }
  411. get url() {
  412. throw new TypeError("It must be overwrite.");
  413. }
  414. get headers() {
  415. if (this.method === "GET") {
  416. return {};
  417. }
  418. return {
  419. "Content-Type": "application/json"
  420. };
  421. }
  422. get body() {
  423. if (this.data === null) {
  424. return "";
  425. }
  426. return JSON.stringify(this.data);
  427. }
  428. get _response() {
  429. throw new TypeError("It must be overwrite.");
  430. }
  431. async connect() {
  432. const request2 = await fetch(this.url, this.settings);
  433. if (!request2.ok) {
  434. throw new Error('Fail when requested: "' + this.url + '".');
  435. }
  436. const response = await request2.json();
  437. if (!("result" in response)) {
  438. throw new Error("Bad response, not contain result.");
  439. }
  440. return new this._response(response);
  441. }
  442. get data() {
  443. throw new TypeError("This must be overwrite.");
  444. }
  445. };
  446. // application/scripts/bool_response.js
  447. var bool_response = class {
  448. #result;
  449. #cause;
  450. constructor(target) {
  451. this.#result = target.result === "success";
  452. this.#cause = null;
  453. if (!this.result) {
  454. this.#cause = target.cause;
  455. }
  456. }
  457. get cause() {
  458. return this.#cause;
  459. }
  460. get result() {
  461. return this.#result;
  462. }
  463. };
  464. // application/scripts/delete_request.js
  465. var delete_request = class extends request {
  466. #product;
  467. constructor(product2) {
  468. super();
  469. this.#product = product2;
  470. }
  471. get _response() {
  472. return bool_response;
  473. }
  474. get data() {
  475. return {
  476. "apikey": this._apikey
  477. };
  478. }
  479. get url() {
  480. return "/product/barcode/" + this.#product.barcode;
  481. }
  482. get method() {
  483. return "DELETE";
  484. }
  485. };
  486. // application/scripts/product_containers.js
  487. var product_containers = class {
  488. #content;
  489. #where;
  490. #inserted;
  491. constructor(where) {
  492. this.#where = where;
  493. this.#content = new Array();
  494. this.#inserted = new Array();
  495. }
  496. add_list(target) {
  497. target.forEach((count) => {
  498. this.add(count);
  499. });
  500. return this;
  501. }
  502. add(target) {
  503. const current = new product_container(target);
  504. this.#content.push(current);
  505. return this;
  506. }
  507. clean() {
  508. this.#content = new Array();
  509. return this;
  510. }
  511. update() {
  512. this.#hide();
  513. setTimeout(() => {
  514. this.#content.forEach((count) => {
  515. this.#inserted.push(count);
  516. count.add(this.#where);
  517. });
  518. }, 500);
  519. return this;
  520. }
  521. #hide() {
  522. this.#inserted.forEach((count) => {
  523. if (!this.#content.includes(count)) {
  524. count.drop();
  525. }
  526. });
  527. this.#inserted = new Array();
  528. return this;
  529. }
  530. };
  531. // application/scripts/searcher.js
  532. var searcher = class _searcher {
  533. #input;
  534. #category;
  535. #manager;
  536. #result;
  537. static #instances;
  538. static #add(instance) {
  539. if (typeof _searcher.#instances !== "object") {
  540. _searcher.#instances = new Array();
  541. }
  542. _searcher.#instances.push(instance);
  543. }
  544. static reload() {
  545. if (typeof _searcher.#instances !== "object") {
  546. return;
  547. }
  548. _searcher.#instances.forEach((instance) => {
  549. instance.update();
  550. });
  551. }
  552. constructor(search_form, manager, result) {
  553. this.#input = search_form.querySelector('input[type="text"]');
  554. this.#category = search_form.querySelector("select");
  555. this.#manager = manager;
  556. this.#result = result;
  557. this.#selector_complete();
  558. search_form.addEventListener("submit", (target) => {
  559. target.preventDefault();
  560. this.update();
  561. });
  562. _searcher.#add(this);
  563. }
  564. get categories() {
  565. return {
  566. "name": "Name",
  567. "author": "Author"
  568. };
  569. }
  570. #selector_complete() {
  571. const category = this.#category;
  572. const categories = this.categories;
  573. Object.keys(categories).forEach((name) => {
  574. const option = document.createElement("option");
  575. option.value = name;
  576. option.innerText = categories[name];
  577. category.appendChild(option);
  578. });
  579. }
  580. get #loader() {
  581. return {
  582. "name": products_loader.search_name,
  583. "author": products_loader.search_author
  584. }[this.category];
  585. }
  586. get category() {
  587. return this.#category.value;
  588. }
  589. get phrase() {
  590. return this.#input.value.trim();
  591. }
  592. get #result_title() {
  593. return this.#result.innerText;
  594. }
  595. set #result_title(target) {
  596. this.#result.innerText = target;
  597. }
  598. async update() {
  599. if (this.phrase.length === 0) {
  600. this.show_all();
  601. return;
  602. }
  603. this.#insert(await this.#loader(this.phrase));
  604. }
  605. #insert(list) {
  606. if (list.length === 0) {
  607. this.#result_title = "Not found anything.";
  608. } else {
  609. this.#result_title = "Browse our products!";
  610. }
  611. this.#manager.clean().add_list(list).update();
  612. }
  613. async show_all() {
  614. this.#insert(await products_loader.all());
  615. }
  616. };
  617. // application/scripts/delete_product_window.js
  618. var delete_product_window = class extends confirm_action {
  619. #target;
  620. constructor(target) {
  621. super();
  622. this.#target = target;
  623. }
  624. get _title() {
  625. return "Do you want remove it?";
  626. }
  627. get _description() {
  628. let content = "You try to remove " + this.#target.name + ". ";
  629. content += "You can not restore it, when confirm.";
  630. return content;
  631. }
  632. async _action() {
  633. new delete_request(this.#target).connect();
  634. searcher.reload();
  635. }
  636. };
  637. // application/scripts/formscreen.js
  638. var formscreen = class extends fullscreen {
  639. #form;
  640. #result;
  641. constructor() {
  642. super();
  643. this.#form = null;
  644. this.#result = null;
  645. }
  646. get _name() {
  647. throw new TypeError("This is virtual getter!");
  648. }
  649. _process() {
  650. this._error = "This is abstract, and must be overwriten.";
  651. }
  652. _build_form() {
  653. throw new TypeError("This is virtual method!");
  654. }
  655. _get_input(name) {
  656. return this.get_query('input[name="' + name + '"]');
  657. }
  658. _build_node() {
  659. const center = document.createElement("div");
  660. center.classList.add("center");
  661. const title = document.createElement("div");
  662. title.classList.add("title");
  663. center.appendChild(title);
  664. const title_content = document.createElement("h3");
  665. title_content.innerText = this._name;
  666. title.appendChild(title_content);
  667. const form = document.createElement("form");
  668. center.appendChild(form);
  669. form.addEventListener("click", () => {
  670. this._clear_results();
  671. });
  672. this.#form = document.createElement("div");
  673. this.#form.classList.add("content");
  674. form.appendChild(this.#form);
  675. this.#result = document.createElement("div");
  676. this.#result.classList.add("result");
  677. form.appendChild(this.#result);
  678. const bottom = document.createElement("div");
  679. bottom.classList.add("bottom");
  680. form.appendChild(bottom);
  681. const close_button = document.createElement("button");
  682. close_button.classList.add("close");
  683. close_button.classList.add("material-icons");
  684. close_button.innerText = "close";
  685. close_button.type = "button";
  686. bottom.appendChild(close_button);
  687. const send_button = document.createElement("button");
  688. send_button.classList.add("send");
  689. send_button.classList.add("material-icons");
  690. send_button.innerText = "send";
  691. send_button.type = "submit";
  692. bottom.appendChild(send_button);
  693. close_button.addEventListener("click", () => {
  694. this.hide();
  695. });
  696. form.addEventListener("submit", (target) => {
  697. target.preventDefault();
  698. this._process();
  699. });
  700. this._build_form();
  701. return center;
  702. }
  703. _create_input(name, label_text, placeholder, worker = null) {
  704. const container = document.createElement("div");
  705. container.classList.add("input-container");
  706. container.classList.add("input-" + name);
  707. const label = document.createElement("label");
  708. label.htmlFor = name;
  709. label.innerText = label_text;
  710. container.appendChild(label);
  711. const input = document.createElement("input");
  712. input.type = "text";
  713. input.placeholder = placeholder;
  714. input.name = name;
  715. input.id = name;
  716. container.appendChild(input);
  717. if (worker !== null) {
  718. worker(input);
  719. }
  720. if (!this.#form) {
  721. throw new Error("Screen is not visible yet!");
  722. }
  723. this.#form.appendChild(container);
  724. return () => {
  725. return input.value;
  726. };
  727. }
  728. _clear_results() {
  729. if (!this.#result) {
  730. return;
  731. }
  732. while (this.#result.lastChild) {
  733. this.#result.lastChild.remove();
  734. }
  735. }
  736. set _info(target) {
  737. this._clear_results();
  738. const info = document.createElement("p");
  739. info.classList.add("info");
  740. info.innerText = target;
  741. if (this.#result) {
  742. this.#result.appendChild(info);
  743. }
  744. }
  745. set _error(target) {
  746. this._clear_results();
  747. const info = document.createElement("p");
  748. info.classList.add("error");
  749. info.innerText = target;
  750. if (this.#result) {
  751. this.#result.appendChild(info);
  752. }
  753. }
  754. set _success(target) {
  755. this._clear_results();
  756. const info = document.createElement("p");
  757. info.classList.add("success");
  758. info.innerText = target;
  759. if (this.#result) {
  760. this.#result.appendChild(info);
  761. }
  762. }
  763. };
  764. // application/scripts/product_base.js
  765. var product_base = class {
  766. name;
  767. description;
  768. author;
  769. barcode;
  770. stock_count;
  771. constructor(target = null) {
  772. this.name = this._extract(target, "name");
  773. this.description = this._extract(target, "description");
  774. this.author = this._extract(target, "author");
  775. this.barcode = this._extract(target, "barcode");
  776. this.stock_count = this._extract(target, "stock_count");
  777. if (this.stock_count !== null) {
  778. this.stock_count = Number(this.stock_count);
  779. }
  780. }
  781. get dump() {
  782. return {
  783. "name": this.name,
  784. "description": this.description,
  785. "author": this.author,
  786. "barcode": this.barcode,
  787. "stock_count": this.stock_count
  788. };
  789. }
  790. _extract(dict, name) {
  791. if (dict === null) {
  792. return null;
  793. }
  794. if (name in dict) {
  795. return dict[name];
  796. }
  797. return null;
  798. }
  799. get avairable() {
  800. return this.stock_count > 0;
  801. }
  802. };
  803. // application/scripts/edit_request.js
  804. var edit_request = class extends request {
  805. #target;
  806. #updated;
  807. constructor(target, updated) {
  808. super();
  809. this.#target = target;
  810. this.#updated = updated;
  811. }
  812. get _response() {
  813. return bool_response;
  814. }
  815. get data() {
  816. return Object.assign(this.#updated.dump, {
  817. "apikey": this._apikey
  818. });
  819. }
  820. get method() {
  821. return "POST";
  822. }
  823. get url() {
  824. return "/product/update/barcode/" + this.#target.barcode;
  825. }
  826. };
  827. // application/scripts/edit_image_request.js
  828. var edit_image_request = class extends request {
  829. #image;
  830. #target;
  831. constructor(target, image) {
  832. super();
  833. this.#target = target;
  834. this.#image = image;
  835. }
  836. get _response() {
  837. return bool_response;
  838. }
  839. get data() {
  840. return {
  841. "image": this.#image,
  842. "apikey": this._apikey
  843. };
  844. }
  845. get method() {
  846. return "POST";
  847. }
  848. get url() {
  849. return "/product/update/image/barcode/" + this.#target.barcode;
  850. }
  851. };
  852. // application/scripts/product_editor.js
  853. var product_editor = class extends formscreen {
  854. #target;
  855. #name;
  856. #description;
  857. #author;
  858. #barcode;
  859. #stock_count;
  860. #image;
  861. constructor(target) {
  862. super();
  863. this.#target = target;
  864. }
  865. get target() {
  866. return this.#target;
  867. }
  868. get _name() {
  869. return "Product editor";
  870. }
  871. _build_form() {
  872. this.#name = this._create_input(
  873. "name",
  874. "Name:",
  875. "Sample...",
  876. (input) => {
  877. input.value = this.#target.name;
  878. }
  879. );
  880. this.#description = this._create_input(
  881. "description",
  882. "Description:",
  883. "This is sample product...",
  884. (input) => {
  885. input.value = this.#target.description;
  886. }
  887. );
  888. this.#author = this._create_input(
  889. "author",
  890. "Author:",
  891. "Jack Black",
  892. (input) => {
  893. input.value = this.#target.author;
  894. }
  895. );
  896. this.#barcode = this._create_input(
  897. "barcode",
  898. "Barcode (EAN):",
  899. "123456789012...",
  900. (input) => {
  901. input.type = "number";
  902. input.value = this.#target.barcode;
  903. }
  904. );
  905. this.#stock_count = this._create_input(
  906. "stock_count",
  907. "Stock count:",
  908. "10...",
  909. (input) => {
  910. input.type = "number";
  911. input.value = this.#target.stock_count;
  912. }
  913. );
  914. this._create_input(
  915. "image",
  916. "Change product image:",
  917. "",
  918. (input) => {
  919. this.#image = input;
  920. input.type = "file";
  921. input.accept = "image/*";
  922. }
  923. );
  924. }
  925. async #code_image() {
  926. if (this.#image.files.length === 0) {
  927. return null;
  928. }
  929. const file = this.#image.files.item(0);
  930. const buffer = await file.arrayBuffer();
  931. const list = new Uint8Array(buffer);
  932. let content = new String();
  933. list.forEach((code) => {
  934. content += String.fromCharCode(code);
  935. });
  936. return btoa(content);
  937. }
  938. async #submit() {
  939. const copy = this.#target.copy();
  940. copy.name = this.#name();
  941. copy.description = this.#description();
  942. copy.author = this.#author();
  943. copy.barcode = this.#barcode();
  944. copy.stock_count = this.#stock_count();
  945. const request2 = new edit_request(this.#target, copy);
  946. const response = await request2.connect();
  947. if (!response.result) {
  948. throw new Error(response.cause);
  949. }
  950. this.#target = copy;
  951. }
  952. async #image_submit() {
  953. const image = await this.#code_image();
  954. if (image === null) {
  955. return;
  956. }
  957. const request2 = new edit_image_request(this.#target, image);
  958. const response = await request2.connect();
  959. if (!response.result) {
  960. throw new Error(response.cause);
  961. }
  962. }
  963. async _process() {
  964. try {
  965. this._info = "Uploading...";
  966. await this.#submit();
  967. this._info = "Processing image...";
  968. await this.#image_submit();
  969. this._success = "Updated success!";
  970. searcher.reload();
  971. setTimeout(() => {
  972. this.hide();
  973. }, 500);
  974. } catch (error) {
  975. this._error = new String(error);
  976. }
  977. }
  978. };
  979. // application/scripts/rents_screen.js
  980. var rents_screen = class extends formscreen {
  981. #target;
  982. #email;
  983. #phone;
  984. get _phone() {
  985. return this.#phone();
  986. }
  987. constructor(target) {
  988. super();
  989. this.#target = target;
  990. }
  991. get _target() {
  992. return this.#target;
  993. }
  994. _build_form() {
  995. this.#email = this._create_input(
  996. "email",
  997. "E-mail:",
  998. "[email protected]",
  999. (input) => {
  1000. input.type = "email";
  1001. }
  1002. );
  1003. this.#phone = this._create_input(
  1004. "phone",
  1005. "Phone number:",
  1006. "123-456-789",
  1007. (input) => {
  1008. input.type = "tel";
  1009. input.pattern = "[0-9]{3}-[0-9]{3}-[0-9]{3}";
  1010. }
  1011. );
  1012. }
  1013. };
  1014. // application/scripts/product_rent.js
  1015. var product_rent = class extends rents_screen {
  1016. get _name() {
  1017. return "Product rent";
  1018. }
  1019. _process() {
  1020. }
  1021. };
  1022. // application/scripts/product_give_back.js
  1023. var product_give_back = class extends rents_screen {
  1024. get _name() {
  1025. return "Product give back";
  1026. }
  1027. _process() {
  1028. }
  1029. };
  1030. // application/scripts/product_container.js
  1031. var product_container = class {
  1032. #target;
  1033. #node;
  1034. #login;
  1035. constructor(target) {
  1036. this.#target = new product(target.dump);
  1037. this.#node = null;
  1038. this.#login = new login_manager().logged_in;
  1039. }
  1040. get #header() {
  1041. const header = document.createElement("div");
  1042. header.classList.add("header");
  1043. const title = document.createElement("h3");
  1044. title.innerText = this.#target.name;
  1045. header.appendChild(title);
  1046. if (this.#login) {
  1047. header.appendChild(this.#manage);
  1048. }
  1049. return header;
  1050. }
  1051. get #manage() {
  1052. const manage = document.createElement("div");
  1053. manage.classList.add("manage");
  1054. const rent_button = document.createElement("button");
  1055. rent_button.classList.add("material-icons");
  1056. rent_button.classList.add("rent-button");
  1057. rent_button.innerText = "backpack";
  1058. manage.appendChild(rent_button);
  1059. const give_back_button = document.createElement("button");
  1060. give_back_button.classList.add("material-icons");
  1061. give_back_button.classList.add("give-back-button");
  1062. give_back_button.innerText = "save_alt";
  1063. manage.appendChild(give_back_button);
  1064. const edit_button = document.createElement("button");
  1065. edit_button.classList.add("material-icons");
  1066. edit_button.classList.add("edit-button");
  1067. edit_button.innerText = "edit";
  1068. manage.appendChild(edit_button);
  1069. const delete_button = document.createElement("button");
  1070. delete_button.classList.add("material-icons");
  1071. delete_button.classList.add("delete-button");
  1072. delete_button.innerText = "remove_circle_outline";
  1073. manage.appendChild(delete_button);
  1074. rent_button.addEventListener("click", () => {
  1075. new product_rent(this.#target).show();
  1076. });
  1077. give_back_button.addEventListener("click", () => {
  1078. new product_give_back(this.#target).show();
  1079. });
  1080. edit_button.addEventListener("click", () => {
  1081. new product_editor(this.#target).show();
  1082. });
  1083. delete_button.addEventListener("click", () => {
  1084. new delete_product_window(this.#target).show();
  1085. });
  1086. return manage;
  1087. }
  1088. get #description() {
  1089. const container = document.createElement("div");
  1090. container.classList.add("description");
  1091. const description = document.createElement("p");
  1092. description.innerText = this.#target.description;
  1093. description.classList.add("content");
  1094. const author_container = document.createElement("div");
  1095. author_container.classList.add("author");
  1096. const author = document.createElement("span");
  1097. author.innerText = this.#target.author;
  1098. const author_icon = document.createElement("span");
  1099. author_icon.classList.add("material-icons");
  1100. author_icon.innerText = "attribution";
  1101. author_container.appendChild(author_icon);
  1102. author_container.appendChild(author);
  1103. const stock_count = document.createElement("p");
  1104. stock_count.classList.add("stock-count");
  1105. stock_count.classList.add("material-icons");
  1106. if (this.#target.stock_count > 0) {
  1107. stock_count.innerText = "check_circle";
  1108. stock_count.classList.add("avairable");
  1109. } else {
  1110. stock_count.innerText = "cancel";
  1111. stock_count.classList.add("unavairable");
  1112. }
  1113. const barcode_container = document.createElement("p");
  1114. barcode_container.classList.add("barcode");
  1115. const barcode = document.createElement("span");
  1116. barcode.innerText = this.#target.barcode;
  1117. barcode.classList.add("numbers");
  1118. const barcode_icon = document.createElement("span");
  1119. barcode_icon.classList.add("material-icons");
  1120. barcode_icon.innerText = "qr_code_scanner";
  1121. barcode_container.appendChild(barcode_icon);
  1122. barcode_container.appendChild(barcode);
  1123. container.appendChild(description);
  1124. container.appendChild(author_container);
  1125. container.appendChild(barcode_container);
  1126. container.appendChild(stock_count);
  1127. return container;
  1128. }
  1129. get #cache_bypass() {
  1130. return "?cache=" + new String(Math.floor(Math.random() * 100));
  1131. }
  1132. get #image() {
  1133. const image = document.createElement("img");
  1134. image.classList.add("image");
  1135. image.src = this.#target.thumbnail + this.#cache_bypass;
  1136. image.alt = this.#target.name;
  1137. image.addEventListener("click", () => {
  1138. new product_fullscreen(this.#target).show();
  1139. });
  1140. return image;
  1141. }
  1142. get node() {
  1143. if (this.#node !== null) {
  1144. return this.#node;
  1145. }
  1146. const bottom_container = document.createElement("div");
  1147. bottom_container.classList.add("bottom-container");
  1148. bottom_container.appendChild(this.#description);
  1149. bottom_container.appendChild(this.#image);
  1150. const container = document.createElement("div");
  1151. container.classList.add("product");
  1152. container.appendChild(this.#header);
  1153. container.appendChild(bottom_container);
  1154. return this.#node = container;
  1155. }
  1156. add(target) {
  1157. const node = this.node;
  1158. node.style.opacity = "0";
  1159. node.style.transition = "opacity 0.5s";
  1160. target.appendChild(node);
  1161. setTimeout(() => {
  1162. node.style.opacity = "1";
  1163. }, 50);
  1164. }
  1165. drop() {
  1166. const container = this.#node;
  1167. if (container === null) {
  1168. throw new TypeError("It is not showed yet.");
  1169. }
  1170. container.style.opacity = "1";
  1171. container.style.transition = "opacity 0.5s";
  1172. setTimeout(() => {
  1173. container.style.opacity = "0";
  1174. }, 50);
  1175. setTimeout(() => {
  1176. this.#node = null;
  1177. container.remove();
  1178. }, 550);
  1179. }
  1180. };
  1181. // application/scripts/login_prompt.js
  1182. var login_prompt = class extends formscreen {
  1183. #nick;
  1184. #password;
  1185. constructor(target) {
  1186. super();
  1187. target.addEventListener("click", () => {
  1188. this.show();
  1189. });
  1190. }
  1191. get _name() {
  1192. return "Login";
  1193. }
  1194. async _process() {
  1195. try {
  1196. this._info = "Processing...";
  1197. await this.#login();
  1198. this._success = "Logged in!";
  1199. setTimeout(() => {
  1200. location.reload();
  1201. }, 250);
  1202. } catch (error) {
  1203. this._error = new String(error);
  1204. }
  1205. }
  1206. async #login() {
  1207. const manager = new login_manager();
  1208. const result = await manager.login(
  1209. this.#nick(),
  1210. this.#password()
  1211. );
  1212. if (result) {
  1213. return;
  1214. }
  1215. throw new Error("Can not login. Check nick and password.");
  1216. }
  1217. _build_form() {
  1218. this.#nick = this._create_input(
  1219. "nick",
  1220. "Nick:",
  1221. "Sample..."
  1222. );
  1223. this.#password = this._create_input(
  1224. "password",
  1225. "Password:",
  1226. "ABCDEFGH",
  1227. (input) => {
  1228. input.type = "password";
  1229. }
  1230. );
  1231. }
  1232. };
  1233. // application/scripts/create_request.js
  1234. var create_request = class extends request {
  1235. #image;
  1236. #product;
  1237. constructor(product2, image) {
  1238. super();
  1239. this.#image = image;
  1240. this.#product = product2;
  1241. }
  1242. get _response() {
  1243. return bool_response;
  1244. }
  1245. get data() {
  1246. return Object.assign(this.#product.dump, {
  1247. "image": this.#image,
  1248. "apikey": this._apikey
  1249. });
  1250. }
  1251. get method() {
  1252. return "POST";
  1253. }
  1254. get url() {
  1255. return "/product/create";
  1256. }
  1257. };
  1258. // application/scripts/product_adder.js
  1259. var product_adder = class extends formscreen {
  1260. #name;
  1261. #description;
  1262. #author;
  1263. #barcode;
  1264. #stock_count;
  1265. #image;
  1266. get _name() {
  1267. return "Add product";
  1268. }
  1269. _build_form() {
  1270. this.#name = this._create_input(
  1271. "name",
  1272. "Name:",
  1273. "Sample..."
  1274. );
  1275. this.#description = this._create_input(
  1276. "description",
  1277. "Description:",
  1278. "This is sample product..."
  1279. );
  1280. this.#author = this._create_input(
  1281. "author",
  1282. "Author:",
  1283. "Jack Black"
  1284. );
  1285. this.#barcode = this._create_input(
  1286. "barcode",
  1287. "Barcode (EAN):",
  1288. "123456789012...",
  1289. (input) => {
  1290. input.type = "number";
  1291. }
  1292. );
  1293. this.#stock_count = this._create_input(
  1294. "stock_count",
  1295. "Stock count:",
  1296. "10...",
  1297. (input) => {
  1298. input.type = "number";
  1299. }
  1300. );
  1301. this._create_input(
  1302. "image",
  1303. "Product image:",
  1304. "",
  1305. (input) => {
  1306. this.#image = input;
  1307. input.type = "file";
  1308. input.accept = "image/*";
  1309. }
  1310. );
  1311. }
  1312. async #code_image() {
  1313. if (this.#image.files.length === 0) {
  1314. throw new Error("Upload image for product.");
  1315. }
  1316. const file = this.#image.files.item(0);
  1317. const buffer = await file.arrayBuffer();
  1318. const list = new Uint8Array(buffer);
  1319. let content = new String();
  1320. list.forEach((code) => {
  1321. content += String.fromCharCode(code);
  1322. });
  1323. return btoa(content);
  1324. }
  1325. async #submit() {
  1326. const product2 = new product_base();
  1327. product2.name = this.#name();
  1328. product2.description = this.#description();
  1329. product2.author = this.#author();
  1330. product2.stock_count = this.#stock_count();
  1331. product2.barcode = this.#barcode();
  1332. const image = await this.#code_image();
  1333. const request2 = new create_request(product2, image);
  1334. const response = await request2.connect();
  1335. if (!response.result) {
  1336. throw new Error(response.cause);
  1337. }
  1338. }
  1339. async _process() {
  1340. try {
  1341. this._info = "Uploading...";
  1342. await this.#submit();
  1343. this._success = "Created success!";
  1344. searcher.reload();
  1345. setTimeout(() => {
  1346. this.hide();
  1347. }, 500);
  1348. } catch (error) {
  1349. this._error = new String(error);
  1350. }
  1351. }
  1352. };
  1353. // application/scripts/login_bar.js
  1354. var login_bar = class {
  1355. #manager;
  1356. constructor(target) {
  1357. this.#manager = new login_manager();
  1358. if (!this.#manager.logged_in) {
  1359. this.#not_logged(target);
  1360. return;
  1361. }
  1362. this.#logged(target);
  1363. }
  1364. #not_login_propertly() {
  1365. this.#manager.logout();
  1366. location.reload();
  1367. }
  1368. async #logged(target) {
  1369. const user2 = await this.#manager.get_user();
  1370. if (user2 === null) {
  1371. this.#not_login_propertly();
  1372. }
  1373. const info_icon = document.createElement("span");
  1374. info_icon.classList.add("icon");
  1375. info_icon.classList.add("material-icons");
  1376. info_icon.innerText = "account_circle";
  1377. const info_content = document.createElement("span");
  1378. info_content.innerText = user2.nick;
  1379. const info = document.createElement("p");
  1380. info.classList.add("login-info");
  1381. info.appendChild(info_icon);
  1382. info.appendChild(info_content);
  1383. target.appendChild(info);
  1384. const logout_button = document.createElement("button");
  1385. logout_button.innerText = "logout";
  1386. logout_button.classList.add("logout-button");
  1387. logout_button.classList.add("material-icons");
  1388. target.appendChild(logout_button);
  1389. const add_product_button = document.createElement("button");
  1390. add_product_button.innerText = "add";
  1391. add_product_button.classList.add("add-product-button");
  1392. add_product_button.classList.add("material-icons");
  1393. target.appendChild(add_product_button);
  1394. add_product_button.addEventListener("click", () => {
  1395. new product_adder().show();
  1396. });
  1397. logout_button.addEventListener("click", () => {
  1398. this.#manager.logout();
  1399. location.reload();
  1400. });
  1401. }
  1402. #not_logged(target) {
  1403. const login_button = document.createElement("button");
  1404. login_button.innerText = "account_circle";
  1405. login_button.classList.add("login-button");
  1406. login_button.classList.add("material-icons");
  1407. target.appendChild(login_button);
  1408. new login_prompt(login_button);
  1409. }
  1410. };
  1411. // application/scripts/scroll_up.js
  1412. var scroll_up = class {
  1413. #button;
  1414. constructor(button) {
  1415. this.#button = button;
  1416. this.#update();
  1417. document.addEventListener("scroll", () => {
  1418. this.#update();
  1419. });
  1420. this.#button.addEventListener("click", () => {
  1421. this.scroll();
  1422. });
  1423. }
  1424. scroll() {
  1425. this.#position = 0;
  1426. }
  1427. get #position() {
  1428. return document.scrollingElement.scrollTop;
  1429. }
  1430. set #position(target) {
  1431. document.scrollingElement.scrollTop = target;
  1432. }
  1433. get #visible() {
  1434. return Number(this.#button.style.opacity) === 1;
  1435. }
  1436. set #visible(target) {
  1437. this.#button.style.opacity = target ? "1" : "0";
  1438. }
  1439. get #margin() {
  1440. return 20;
  1441. }
  1442. #update() {
  1443. this.#visible = this.#position > this.#margin;
  1444. }
  1445. };
  1446. // application/scripts/color_theme.js
  1447. var color_theme = class {
  1448. #button;
  1449. #themes;
  1450. get themes() {
  1451. return Object.keys(this.#themes);
  1452. }
  1453. theme_name(target) {
  1454. return this.#themes[target];
  1455. }
  1456. constructor(button, themes = null) {
  1457. this.#button = button;
  1458. this.#themes = themes;
  1459. if (this.#themes === null) {
  1460. this.#themes = {
  1461. "dark-theme": "Dark",
  1462. "white-theme": "White"
  1463. };
  1464. }
  1465. this.#load();
  1466. this.#button.addEventListener("click", () => {
  1467. this.change();
  1468. });
  1469. }
  1470. get current() {
  1471. if (localStorage.hasOwnProperty("theme")) {
  1472. return localStorage.getItem("theme");
  1473. }
  1474. return this.themes[this.themes.length - 1];
  1475. }
  1476. #load() {
  1477. this.#show(this.current);
  1478. }
  1479. #save(target) {
  1480. localStorage.setItem("theme", target);
  1481. }
  1482. #show(target) {
  1483. const themes = this.themes;
  1484. const body = document.querySelector("body");
  1485. body.classList.forEach((count) => {
  1486. if (themes.indexOf(count) !== -1) {
  1487. body.classList.remove(count);
  1488. }
  1489. });
  1490. body.classList.add(target);
  1491. }
  1492. change() {
  1493. const themes = this.themes;
  1494. const current = this.current;
  1495. let position = themes.indexOf(current) + 1;
  1496. if (position === themes.length) {
  1497. position = 0;
  1498. }
  1499. const updated = themes[position];
  1500. this.#save(updated);
  1501. this.#show(updated);
  1502. }
  1503. };
  1504. // application/scripts/core.js
  1505. document.addEventListener("DOMContentLoaded", async () => {
  1506. const top_bar_spacing = new height_equaler(
  1507. document.querySelector(".top-bar"),
  1508. document.querySelector(".top-bar-spacing")
  1509. );
  1510. const container = document.querySelector(".products");
  1511. const search_bar = document.querySelector("form.search");
  1512. const search_title = document.querySelector(".search-title");
  1513. const login_space = document.querySelector(".top-bar .right");
  1514. const scroll_up_button = document.querySelector(".scroll-up-button");
  1515. const reverse_colors = document.querySelector(".reverse-colors");
  1516. const manager = new product_containers(container);
  1517. new login_bar(login_space);
  1518. new scroll_up(scroll_up_button);
  1519. new color_theme(reverse_colors);
  1520. new searcher(search_bar, manager, search_title).show_all();
  1521. });
  1522. })();