Source: panel.js

  1. /**
  2. * Panel Component<BR>
  3. * <BR><BR><img src=/tk/lib/components/w/img/panel.png width=30% style="border:1px lime dashed;padding:20px">
  4. * <BR><BR><a href="/tk/lib/components/w/html/panel.html">DEMO</a>
  5. */
  6. class Panel extends HTMLElement {
  7. constructor() {
  8. wc.group("Panel.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("Panel.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("Panel.connectedCallback")
  28. // ADD A RANDOM ID IF NONE EXIST
  29. this.id = this.id || this.constructor.name.toLowerCase() + "-" + wc.uid();
  30. // GET PROPERTIES AND INTERESTING ELEMENTS
  31. this._initialize();
  32. // SHOW THIS COMPONENT
  33. this._render()
  34. // CHECK | UPDATE ATTRIBUTES
  35. this._attributes();
  36. // SUBSCRIBE TO ALL EVENTS OF INTEREST
  37. this._subscribe();
  38. // ADD STATS AND OTHER FINAL STUFF
  39. this._finalize();
  40. wc.groupEnd();
  41. };
  42. /**
  43. * Initial Markup
  44. * @private
  45. * @_template
  46. */
  47. _template() {
  48. wc.group("Panel.template");
  49. var temp;
  50. // ADD COMPONENT MARKTOP
  51. if (wcENV == "prod") {
  52. // FOR PRODUCTION (convert part.html to jstr using h2j)
  53. temp = `<h1>A BLANK TEMPLATE</h1>`+
  54. ''+
  55. `<i class="fa fa-home fa-5x"></i>`+
  56. ''+
  57. `<div class="mt-3">`+
  58. ` <h1 class="btn btn-lg btn-primary">I AM A BOOTSTRAP BUTTON</h4>`+
  59. `</div>`;
  60. } else {
  61. // FOR DEVELOPMENT/LOCAL TESTING
  62. temp = "<wc-include href=/tk/lib/components/w/html/parts/panel.part.html></wc-include>";
  63. }
  64. wc.groupEnd();
  65. return temp;
  66. };
  67. /**
  68. * @private
  69. * @_attributes
  70. */
  71. _attributes() {
  72. wc.group("Panel._attributes");
  73. if (0) {
  74. // TRANSFER ALL ATTRIBUTES NOW (BELOW IS AN EXAMPLE)
  75. // -------------------------------------------------
  76. // SAMPLE CODE BELOW
  77. for (var key in this.propertiesW) {
  78. // SKIP CLASS AND ID
  79. if (key != "class" && key != "id") {
  80. wc.log(key, this.properties[key]);
  81. this.removeAttribute(key);
  82. this.setAttribute(key, this.properties[key]);
  83. }
  84. }
  85. }
  86. wc.groupEnd();
  87. };
  88. /**
  89. * @private
  90. * @_render
  91. */
  92. _render() {
  93. wc.group("Panel._render");
  94. this.innerHTML = this._template();
  95. wc.groupEnd();
  96. };
  97. /**
  98. * Called with .setAttribute(...) function call
  99. * @attributeChangedCallback
  100. */
  101. attributeChangedCallback(attr, oldval, newval) {
  102. wc.group("Panel.attributeChangedCallback:", attr, oldval, newval);
  103. this.properties = this.properties || [];
  104. let obs = Panel.observedAttributes;
  105. for (let i = 0; i < obs.length; i++) {
  106. if (newval) {
  107. this.properties[obs[i]] = newval;
  108. }
  109. }
  110. // YOUR CODE FOR CHANGES GO HERE (MAYBE NULL FIRST TIME THROUGH)
  111. try {
  112. switch(attr)
  113. {
  114. case "header":
  115. //this.querySelector("h1").innerHTML = newval;
  116. break;
  117. default:
  118. break;
  119. }
  120. } catch(e) {
  121. wc.warn(e.name + ' > ' + e.message);
  122. }
  123. wc.groupEnd();
  124. };
  125. /**
  126. * Stores DOM elements of interest for future use
  127. * @private
  128. * @_fetchElements
  129. */
  130. _fetchElements() {
  131. wc.group("Panel._fetchElements");
  132. this.dom = this.dom || [];
  133. this.dom.content = this.innerHTML;
  134. wc.groupEnd();
  135. };
  136. /**
  137. * Component attributes are _fetched and defaults are set if undefined
  138. * @private
  139. * @_fetchAttributes
  140. */
  141. _fetchAttributes() {
  142. wc.group("Panel._fetchAttributes");
  143. this.properties = {
  144. uparam : "",
  145. cname : "Panel",
  146. author : "Mel M. Heravi, Ph.D.",
  147. version : "1.0"
  148. };
  149. // SAVE WIDGET SPECIFIC PROPERTIES
  150. this.propertiesW = [];
  151. // GET ALL COMPONENT PROPERTIES
  152. let attrs = wc.getAttributes(this)
  153. // SAVE IN properties & propertiesW
  154. for (var key in attrs) {
  155. let attr = this.getAttribute(key) || this.properties.key;
  156. this.properties[key] = this.getAttribute(key);
  157. this.propertiesW[key] = this.getAttribute(key);
  158. wc.log(key + ": " + attrs[key]);
  159. }
  160. // SET ALL INITIAL ATTRIBUTES
  161. for (var key in this.properties) {
  162. switch(key)
  163. {
  164. case "header":
  165. break;
  166. default:
  167. break;
  168. }
  169. }
  170. wc.log("ATTRIBUTES: ", this.properties);
  171. wc.groupEnd();
  172. };
  173. /**
  174. * configure the instance object and artifacts
  175. * @configure
  176. * @param {string} data use data if exist else use 'this.properties.cfg' parameter
  177. */
  178. configure(data) {
  179. wc.group("Panel.configure: data=", data);
  180. // START TIME
  181. let time1 = Date.now();
  182. // IF JSON VARIABLE (data) IS PROVIDED
  183. if (data) {
  184. // DIRECT CALL TO ACTION
  185. this._process(data);
  186. } else {
  187. // USUALLY TO INITIALIZE THE COMPONENT FROM A JSON URL
  188. let self = this;
  189. $.getJSON(this.properties.cfg, function(data) {
  190. self._process(data);
  191. }).fail(function(jqXHR, textStatus, errorThrown) {
  192. alert("ERROR: INCOMING TEXT " + jqXHR.responseText);
  193. });
  194. }
  195. // END TIME
  196. let time2 = Date.now();
  197. wc.groupEnd();
  198. return "T:" + (time2-time2);
  199. };
  200. /**
  201. * _process the instance object and artifacts
  202. * @private
  203. * @_process
  204. * MELIFIED
  205. */
  206. _process(data) {
  207. wc.group("Panel._process:", data);
  208. let template = $("#panel-template").html();
  209. // BASIC ASSUMPTIONS
  210. this.isOpen = true;
  211. this.collapsable = data.collapsable || false;
  212. // WE DO EXPECT AT LEAST THE BODY
  213. data.header = data.header || null;
  214. data.footer = data.footer || null;
  215. template = template.replace(/%HEADER%/, data.header);
  216. template = template.replace(/%FOOTER%/, data.footer);
  217. template = template.replace(/%BODY%/, data.body);
  218. // ADD TEMPLATE TO PANEL CONTAINER
  219. $(this).empty().append(template);
  220. // SAVE THESE FOR USE LATER
  221. this.pbody = $(this).find(".wc-panel-body");
  222. this.pheader = $(this).find(".wc-panel-header");
  223. this.pfooter = $(this).find(".wc-panel-footer");
  224. // IF COLLAPSABLE ADD CARET ICONS
  225. if (this.collapsable == true) {
  226. this.pheader
  227. .append("<i class='fa fa-angle-up'></i>")
  228. .append("<i class='fa fa-angle-down'></i>")
  229. .css("cursor", "pointer");
  230. }
  231. // SET PANEL HEIGHT
  232. this.pbody.height(this.properties.height || "300px");
  233. // HIDE FOOTER | FOOTER IF NOT IN JSON
  234. if (!data.footer) this.pfooter.hide();
  235. if (!data.header) this.pheader.hide();
  236. // PUBLISH ALL EVENTS OF INTEREST
  237. this._publish();
  238. wc.groupEnd();
  239. };
  240. /**
  241. * Initialize component
  242. * @_open
  243. * MELIFIED
  244. */
  245. _open() {
  246. wc.group("Panel._open:", this.id);
  247. if (this.isOpen) {
  248. return;
  249. } else {
  250. $(this).find(".wc-panel-header").click();
  251. }
  252. wc.groupEnd();
  253. };
  254. /**
  255. * Initialize component
  256. * @_close
  257. * MELIFIED
  258. */
  259. _close() {
  260. wc.group("Panel._close:", this.id);
  261. if (this.isClose) {
  262. return;
  263. } else {
  264. $(this).find(".wc-panel-header").click();
  265. }
  266. wc.groupEnd();
  267. };
  268. /**
  269. * Initialize component
  270. * @private
  271. * @_initialize
  272. */
  273. _initialize() {
  274. wc.group("Panel._initialize:", this.id);
  275. // FETCH ALL INTERESTING ELEMENTS
  276. this._fetchElements();
  277. // FETCH ALL ATTRIBUTES
  278. this._fetchAttributes();
  279. wc.groupEnd();
  280. };
  281. /**
  282. * Save data for analytics and final wrap up
  283. * @private
  284. * @_finalize
  285. */
  286. _finalize() {
  287. wc.group("Panel._finalize:", this.id);
  288. this.classList.add("wc");
  289. // ADD ANALYTICS HERE
  290. wc.setStats(this, this.properties.cname, this.properties.version);
  291. // SHOW IT NOW (NO FLICKERS)
  292. this.style.visibility = "visible";
  293. wc.groupEnd();
  294. };
  295. /**
  296. * Invoked When component is removed. Usually with a .remove() function call
  297. * @disconnectedCallback
  298. */
  299. disconnectedCallback() {
  300. wc.group("Panel.disconnectedCallback")
  301. wc.groupEnd();
  302. };
  303. /**
  304. * Destroy the instance object and artifacts
  305. * @destroy
  306. */
  307. destroy() {
  308. wc.group("Panel.destroy");
  309. // FREE ALL MEMORY
  310. // you should delete all created objects here
  311. // FREE POINTER
  312. delete this;
  313. // REMOVE ITEM FROM DOM
  314. this.parentNode.removeChild(this);
  315. wc.groupEnd();
  316. };
  317. /**
  318. * @private
  319. * @_publish
  320. * MELIFIED
  321. */
  322. _publish() {
  323. wc.group("Panel._publish");
  324. let header = $(this).find(".wc-panel-header");
  325. if (this.collapsable == true) {
  326. // PUBLISH CLICK EVENTS
  327. $(this).find(".wc-panel-header").on("click", () => {
  328. let fa = $(this).find(".fa");
  329. if (this.isOpen) {
  330. this.isOpen = false;
  331. } else {
  332. this.isOpen = true;
  333. }
  334. $(fa).toggle();
  335. $(this.pbody).slideToggle();
  336. wc.publish("wc-panel", {
  337. id: self.id,
  338. time: new Date().getTime(),
  339. action: "click",
  340. status: this.isOpen
  341. });
  342. });
  343. }
  344. wc.groupEnd();
  345. return true;
  346. };
  347. /**
  348. * Subscribe all to events of interest
  349. * @private
  350. * @_subscribe
  351. * MELIFIED
  352. */
  353. _subscribe() {
  354. wc.group("Panel._subscribe:", this.id);
  355. let self = this;
  356. // SUBSCRIPTION START
  357. wc.subscribe("wc-panel", function(msg,data) {
  358. if (data.id == self.id) {
  359. wc.info(`SUBSCRIPTION TRIGGERED ${JSON.stringify(data)}`)
  360. switch(data.action)
  361. {
  362. case "toggle":
  363. $(self).find(".wc-panel-header").click();
  364. break;
  365. case "open":
  366. self._open();
  367. break;
  368. case "close":
  369. self._close();
  370. break;
  371. default:
  372. break;
  373. }
  374. }
  375. });
  376. // SUBSCRIPTION END
  377. wc.groupEnd();
  378. }
  379. /**
  380. * FOR TESTING THE COMPONENT
  381. * @test
  382. * MELIFIED
  383. */
  384. test() {
  385. console.group("test.panel");
  386. // LIST OF COMMANDS FROM Panel.test
  387. var tests = [
  388. {action:"close", value:{}},
  389. {action:"open", value:{}},
  390. {action:"toggle", value:{}},
  391. {action:"open", value:{}},
  392. ]
  393. for (var i = 0; i < tests.length; i++) {
  394. wc.tester("wc-panel", "my-panel", tests[i], (i+1)*2000)
  395. }
  396. console.groupEnd();
  397. };
  398. }
  399. window.customElements.define('wc-panel', Panel);