Source: v1.js

  1. /**
  2. * V1 Component<BR>
  3. * <BR><BR><img src=/tk/lib/components/w/img/v1.png width=30% style="border:1px lime dashed;padding:20px">
  4. * <BR><BR><a href="/tk/lib/components/w/html/v1.html">DEMO</a>
  5. */
  6. class V1 extends HTMLElement {
  7. constructor() {
  8. wc.group("V1.constructor")
  9. super();
  10. wc.groupEnd();
  11. };
  12. /**
  13. * Set observable values here. When Changed, attributeChangedCallback is invoked
  14. * @observedAttributes
  15. */
  16. static get observedAttributes() {
  17. wc.group("V1.observedAttributes");
  18. this.observables = [];
  19. wc.groupEnd();
  20. return this.observables;
  21. };
  22. /**
  23. * Called when this is attached to DOM
  24. * @connectedCallback.
  25. */
  26. connectedCallback() {
  27. wc.group("V1.connectedCallback")
  28. let self = this;
  29. // ADD A RANDOM ID IF NONE EXIST
  30. if (!this.id) {
  31. this.id = this.constructor.name.toLowerCase() + "-" + wc.uid();
  32. }
  33. // GET PROPERTIES AND INTERESTING ELEMENTS
  34. this._initialize();
  35. // IF PAGE IS RELOADED
  36. if (wc.refreshed()) {
  37. this.properties.page = wc.parseQuery().page;
  38. console.log("THIS PAGE IS RELOADED:", this.properties.page);
  39. }
  40. this.configure();
  41. // ADD STATS AND OTHER FINAL STUFF
  42. this._finalize();
  43. wc.groupEnd();
  44. };
  45. /**
  46. * Called with .setAttribute(...) function call
  47. * @attributeChangedCallback
  48. */
  49. attributeChangedCallback(attr, oldval, newval) {
  50. wc.group("V1.attributeChangedCallback:", attr, oldval, newval);
  51. this.properties = this.properties || [];
  52. let obs = V1.observedAttributes;
  53. for (let i = 0; i < obs.length; i++) {
  54. if (newval) {
  55. this.properties[obs[i]] = newval;
  56. }
  57. }
  58. // YOUR CODE FOR CHANGES GO HERE (MAYBE NULL FIRST TIME THROUGH)
  59. try {
  60. switch(attr)
  61. {
  62. case "header":
  63. break;
  64. default:
  65. break;
  66. }
  67. } catch(e) {
  68. wc.warn(e.name + ' > ' + e.message);
  69. }
  70. wc.groupEnd();
  71. };
  72. /**
  73. * Stores DOM elements of interest for future use
  74. * @private
  75. * @_fetchElements
  76. */
  77. _fetchElements() {
  78. wc.group("V1._fetchElements");
  79. this.dom = this.dom || [];
  80. this.dom.content = this.innerHTML;
  81. wc.groupEnd();
  82. };
  83. /**
  84. * Component attributes are _fetched and defaults are set if undefined
  85. * @private
  86. * @_fetchAttributes
  87. */
  88. _fetchAttributes() {
  89. wc.group("V1._fetchAttributes");
  90. this.properties = {
  91. uparam : "",
  92. cname : "V1",
  93. author : "Mel M. Heravi",
  94. version : "1.0"
  95. };
  96. // SAVE WIDGET SPECIFIC PROPERTIES
  97. this.propertiesW = [];
  98. // SAVE ALL OTHER PROPERTIES
  99. let attrs = wc.getAttributes(this)
  100. for (var key in attrs) {
  101. let attr = this.getAttribute(key) || this.properties.key;
  102. this.properties[key] = this.getAttribute(key);
  103. this.propertiesW[key] = this.getAttribute(key);
  104. wc.log(key + ": " + attrs[key]);
  105. }
  106. // SET ALL INITIAL ATTRIBUTES
  107. for (var key in this.properties) {
  108. switch(key)
  109. {
  110. case "header":
  111. break;
  112. default:
  113. break;
  114. }
  115. }
  116. wc.log("ATTRIBUTES: ", this.properties);
  117. wc.groupEnd();
  118. };
  119. /**
  120. * configure the instance object and artifacts
  121. * @configure
  122. * @param {string} data use data if exist else use 'this.properties.cfg' parameter
  123. */
  124. configure() {
  125. wc.group("V1.configure:");
  126. let self = this;
  127. $.getJSON(this.properties.path + "/config.json", function(data) {
  128. self._process(data);
  129. }).fail(function(jqXHR, textStatus, errorThrown) {
  130. alert("ERROR: INCOMING TEXT " + jqXHR.responseText);
  131. });
  132. wc.groupEnd();
  133. };
  134. /**
  135. * _process the instance object and artifacts
  136. * @private
  137. * @_process
  138. */
  139. _process(data) {
  140. wc.group("V1._process:", data);
  141. this.data = data;
  142. this.cname = this.properties.cname.toLowerCase();
  143. let tstr = "";
  144. tstr += `
  145. <div class="v1-msg alert alert-warning alert-dismissible fade show" style="margin-bottom:0;display:none;border-radius:0" role="alert">
  146. <div class="container-fluid">
  147. <div class="row">
  148. <div class="col-12 padding-0 margin-0">
  149. <button type="button" class="close" data-dismiss="alert" aria-label="Close">
  150. <span aria-hidden="true">&times;</span>
  151. </button>
  152. <strong class="wc-far">WARNING:</strong> <msg>waiting...</msg>
  153. </div>
  154. </div>
  155. </div>
  156. </div>`;
  157. tstr += `
  158. <div class="${this.cname}__header sticky-top">
  159. <wc-include href="${data.header}"></wc-include>
  160. </div>`;
  161. for (var i = 0; i < data.pages.length; i++) {
  162. tstr += `<div class="${this.cname}__page ${data.pages[i].page}"></div>`;
  163. }
  164. tstr += `
  165. <div class="${this.cname}__footer">
  166. <wc-include href="${data.footer}"></wc-include>
  167. </div>`;
  168. // ADD COMPONENT MARKTOP
  169. this.innerHTML = tstr;
  170. wc.wait4(".navbar", ()=> {
  171. this.show(this.properties.page);
  172. // LISTEN TO HASH CHANGES
  173. wc.popstate(() => {
  174. let x = document.location.search.replace("?page=","")
  175. if (x != "") {
  176. // CLICK ON PAGE LINK
  177. this.show(x, false);
  178. // PUBLISH SHOW EVENT
  179. wc.publish(`${this.cname}`, {
  180. time: new Date().getTime(),
  181. action: "popstate",
  182. id: x
  183. });
  184. }
  185. });
  186. });
  187. wc.groupEnd();
  188. };
  189. /**
  190. * Initialize component
  191. * @private
  192. * @_initialize
  193. */
  194. _initialize() {
  195. wc.group("V1._initialize:", this.id);
  196. // FETCH ALL INTERESTING ELEMENTS
  197. this._fetchElements();
  198. // FETCH ALL ATTRIBUTES
  199. this._fetchAttributes();
  200. wc.groupEnd();
  201. };
  202. /**
  203. * Save data for analytics and final wrap up
  204. * @private
  205. * @_finalize
  206. */
  207. _finalize() {
  208. wc.group("V1._finalize:", this.id);
  209. this.classList.add("wc");
  210. // ADD ANALYTICS HERE
  211. wc.setStats(this, this.properties.cname, this.properties.version);
  212. // SHOW IT NOW (NO FLICKERS)
  213. this.style.visibility = "visible";
  214. wc.groupEnd();
  215. };
  216. /**
  217. * Invoked When component is removed. Usually with a .remove() function call
  218. * @disconnectedCallback
  219. */
  220. disconnectedCallback() {
  221. wc.group("V1.disconnectedCallback")
  222. // FREE MEMORY AND CLEANUP
  223. wc.groupEnd();
  224. };
  225. /**
  226. * Destroy the instance object and artifacts
  227. * @destroy
  228. */
  229. destroy() {
  230. wc.group("V1.destroy");
  231. // FREE ALL MEMORY
  232. // you should delete all created objects here
  233. // FREE POINTER
  234. delete this;
  235. // REMOVE ITEM FROM DOM
  236. this.parentNode.removeChild(this);
  237. wc.groupEnd();
  238. };
  239. /**
  240. * refresh a page
  241. * @refresh
  242. */
  243. refresh(page) {
  244. wc.group("V1.refresh:", page);
  245. // EMPTY CONTENT
  246. $("." + page).empty();
  247. // RE-LOAD THE PAGE
  248. this.show(page);
  249. wc.groupEnd();
  250. return page;
  251. };
  252. /**
  253. * show a page
  254. * @show
  255. */
  256. msg(flag, type, dismissable, msg, timeout) {
  257. wc.group("V1.show:", flag, msg);
  258. if (timeout) {
  259. wc.timeout(() => {
  260. this.msg("hide");
  261. }, timeout);
  262. }
  263. if (msg) {
  264. $("wc-v1 .v1-msg msg").html(msg);
  265. }
  266. // RESET CLASSES
  267. $("wc-v1 .v1-msg")
  268. .removeClass("alert-info alert-success alert-danger alert-warning")
  269. .addClass("alert-" + type);
  270. // SHOW/HIDE DISMISS BTN
  271. if (dismissable == false) {
  272. $("wc-v1 .v1-msg .close").hide()
  273. }
  274. switch(type)
  275. {
  276. case "info":
  277. $("wc-v1 .v1-msg strong").text("INFO:")
  278. break;
  279. case "warning":
  280. $("wc-v1 .v1-msg strong").text("WARNING:")
  281. break;
  282. case "success":
  283. $("wc-v1 .v1-msg strong").text("SUCCESS:")
  284. break;
  285. case "danger":
  286. $("wc-v1 .v1-msg strong").text("ERROR:")
  287. break;
  288. }
  289. if (flag == "show") {
  290. $("wc-v1 .v1-msg").slideDown();
  291. } else {
  292. $("wc-v1 .v1-msg").slideUp();
  293. }
  294. wc.groupEnd();
  295. };
  296. /**
  297. * show a page
  298. * @show
  299. */
  300. show(page, push=true) {
  301. wc.group("V1.show:", page);
  302. // FLIP ALL TILES BACK TO NORMAL
  303. $("wc-tile-front").mouseout()
  304. $("[page-id]").removeClass("active")
  305. $(`[page-id=${page}]`).addClass("active")
  306. // HIDE ALL PAGES
  307. $(`.${this.cname}__page`).hide();
  308. let obj = $.grep(this.data.pages, function(obj) {
  309. return obj.page === page;
  310. });
  311. let apage = $("." + page);
  312. let empty = apage.is(":empty");
  313. if (obj[0].cache == "false" || empty) {
  314. apage.load(obj[0].url)
  315. }
  316. // SHOW THIS PAGE
  317. apage.show();
  318. // PUBLISH SHOW EVENT
  319. wc.publish(`${this.cname}`, {
  320. time: new Date().getTime(),
  321. action: "show",
  322. id: page
  323. });
  324. // SAVE BROWSER HISTORY
  325. if (push) {
  326. wc.pushstate(page);
  327. }
  328. wc.groupEnd();
  329. return page;
  330. };
  331. /**
  332. * for testing only
  333. * @tester
  334. */
  335. tester(page) {
  336. wc.group("V1.tester:", page);
  337. let self = this;
  338. let str = `<div class="btn-group btn-group-sm btn-group-tester" role="group" aria-label="btn-tester" style="position:fixed;bottom:60px;right:10px;z-index:99999999">`;
  339. for (var i = 0; i < this.data.pages.length; i++) {
  340. str += `<button type="button" class="btn btn-danger wc-v1-btn-tester">${this.data.pages[i].page}</button>`;
  341. }
  342. str += "</div>"
  343. $("body").v1end(str);
  344. $(".wc-v1-btn-tester").on("click", function() {
  345. self.show($(this).text());
  346. });
  347. wc.groupEnd();
  348. };
  349. }
  350. window.customElements.define('wc-v1', V1);