/**
* Accordion Component<BR>
* <BR><BR><img src=/tk/lib/components/w/img/accordion.png width=30% style="border:1px lime dashed;padding:20px">
* <BR><BR><a href="/tk/lib/components/w/html/accordion.html">DEMO</a>
*/
class Accordion extends HTMLElement {
constructor() {
wc.group("Accordion.constructor")
super();
wc.groupEnd();
};
/**
* Set observable values here. When Changed, attributeChangedCallback is invoked
* @observedAttributes
*/
static get observedAttributes() {
wc.group("Accordion.observedAttributes");
this.observables = [];
wc.groupEnd();
return this.observables;
};
/**
* Called when this is attached to DOM
* @connectedCallback.
*/
connectedCallback() {
wc.group("Accordion.connectedCallback")
let self = this;
// ADD A RANDOM ID IF NONE EXIST
if (!this.id) {
this.id = this.constructor.name.toLowerCase() + "-" + wc.uid();
}
// GET PROPERTIES AND INTERESTING ELEMENTS
this._initialize();
// CONFIGURE FROM JSON
if (this.properties.cfg) {
this.configure();
}
// SUBSCRIBE TO ALL EVENTS OF INTEREST
this._subscribe();
// ADD STATS AND OTHER FINAL STUFF
this._finalize();
wc.groupEnd();
};
/**
* Initial Markup
* @private
* @_template
*/
_template() {
wc.group("Accordion.template");
var temp = this.dom.content;
wc.groupEnd();
return temp;
};
/**
* Called with .setAttribute(...) function call
* @attributeChangedCallback
*/
attributeChangedCallback(attr, oldval, newval) {
wc.group("Accordion.attributeChangedCallback:", attr, oldval, newval);
this.properties = this.properties || [];
let obs = Accordion.observedAttributes;
for (let i = 0; i < obs.length; i++) {
if (newval) {
this.properties[obs[i]] = newval;
}
}
// YOUR CODE FOR CHANGES GO HERE (MAYBE NULL FIRST TIME THROUGH)
try {
switch(attr)
{
case "header":
//this.querySelector("h1").innerHTML = newval;
break;
default:
break;
}
} catch(e) {
wc.warn(e.name + ' > ' + e.message);
}
wc.groupEnd();
};
/**
* Stores DOM elements of interest for future use
* @private
* @_fetchElements
*/
_fetchElements() {
wc.group("Accordion._fetchElements");
this.dom = this.dom || [];
this.dom.content = this.innerHTML;
wc.groupEnd();
};
/**
* Component attributes are _fetched and defaults are set if undefined
* @private
* @_fetchAttributes
*/
_fetchAttributes() {
wc.group("Accordion._fetchAttributes");
this.properties = {
uparam : "",
cname : "Accordion",
author : "Mel M. Heravi",
version : "1.0",
show : 0
};
// SAVE WIDGET SPECIFIC PROPERTIES
this.propertiesW = [];
// SAVE ALL OTHER PROPERTIES
let attrs = wc.getAttributes(this)
for (var key in attrs) {
let attr = this.getAttribute(key) || this.properties.key;
this.properties[key] = this.getAttribute(key);
this.propertiesW[key] = this.getAttribute(key);
wc.log(key + ": " + attrs[key]);
}
// SET ALL INITIAL ATTRIBUTES
for (var key in this.properties) {
switch(key)
{
case "header":
break;
default:
break;
}
}
wc.log("ATTRIBUTES: ", this.properties);
wc.groupEnd();
};
/**
* configure the instance object and artifacts
* @configure
* @param {string} data use data if exist else use 'this.properties.cfg' parameter
*/
configure(data) {
wc.group("Accordion.configure:", data);
// IF JSON VARIABLE (data) IS PROVIDED
if (data) {
this._process(data);
} else {
let self = this;
$.getJSON(this.properties.cfg, function(data) {
self._process(data);
}).fail(function(jqXHR, textStatus, errorThrown) {
alert("ERROR: INCOMING TEXT " + jqXHR.responseText);
});
}
wc.groupEnd();
};
/**
* _process the instance object and artifacts
* @private
* @_process
*/
_process(data) {
wc.group("Accordion._process:", data);
let self = this;
for (var i = 0; i < data.length; i++) {
$(this).append(`
<div class="card" id="${this.id}-card-${i}">
<div class="card-header" id="${this.id}-card-header-${i}">
<div class="float-left">
${data[i].header}
</div>
<div class="float-right">
${data[i].icon}
</div>
</div>
<div class="card-body" id="${this.id}-card-body-${i}">
${data[i].body}
</div>
</div>`);
}
// OPEN DEFAULT ITEM
this.open(this.properties.show, "default-panel");
// LOAD CONTENT INTO BODIES
for (var i = 0; i < data.length; i++) {
$(`#${this.id}-card-header-${i}`).attr("sid", i);
$(`#${this.id}-card-header-${i}`).unbind().on("click", function() {
let sid = $(this).attr("sid");
// IF ALREADY OPEN DO NOTHING
if (sid != self.properties.show) {
self.open(sid,"click");
}
});
}
wc.groupEnd();
};
/**
* Initialize component
* @private
* @_initialize
*/
_initialize() {
wc.group("Accordion._initialize:", this.id);
// FETCH ALL INTERESTING ELEMENTS
this._fetchElements();
// FETCH ALL ATTRIBUTES
this._fetchAttributes();
wc.groupEnd();
};
/**
* Save data for analytics and final wrap up
* @private
* @_finalize
*/
_finalize() {
wc.group("Accordion._finalize:", this.id);
this.classList.add("wc");
// ADD ANALYTICS HERE
wc.setStats(this, this.properties.cname, this.properties.version);
// SHOW IT NOW (NO FLICKERS)
this.style.visibility = "visible";
wc.groupEnd();
};
/**
* Invoked When component is removed. Usually with a .remove() function call
* @disconnectedCallback
*/
disconnectedCallback() {
wc.group("Accordion.disconnectedCallback")
// FREE MEMORY AND CLEANUP
wc.groupEnd();
};
/**
* Destroy the instance object and artifacts
* @destroy
*/
destroy() {
wc.group("Accordion.destroy");
// FREE ALL MEMORY
// you should delete all created objects here
// FREE POINTER
delete this;
// REMOVE ITEM FROM DOM
this.parentNode.removeChild(this);
wc.groupEnd();
};
/**
* OPEN CARD BY INDEX
* @open
* @param {integer} ind index of card to open
*/
open(ind, action) {
wc.group("Accordion.open:", ind);
$(this).find(".card-header").removeClass("active");
$(this).find(".card-body").hide()
let b = this.querySelector(`#${this.id}-card-body-${ind}`);
let h = this.querySelector(`#${this.id}-card-header-${ind}`);
$(b).show();
$(h).addClass("active");
this.properties.show = ind;
if (0) {
wc.publish("wc-accordion", {
time: new Date().getTime(),
action: action,
id: this.id,
show: this.properties.show
});
}
wc.groupEnd();
};
/**
* Subscribe all to events of interest
* @private
* @_subscribe
*/
_subscribe() {
wc.group("Accordion._subscribe:");
let self = this;
wc.subscribe("wc-accordion", function(msg,data) {
self._request(data)
wc.info("wc-accordion subscription was triggered:", JSON.stringify(data));
});
wc.groupEnd();
}
/**
* @_request
*/
_request(data) {
wc.group("Accordion._request:", this.id, JSON.stringify(data));
wc.info("wc-accordion-request SUBSCRIPTION WAS TRIGGERED:", JSON.stringify(data));
var that = $("#" + data.id)[0];
switch(data.request)
{
case "open":
that.open(data.panel,"click");
break;
case "load":
// OPEN THE PANEL FIRST
that.open(data.panel,"click");
// LOAD CONTENT FROM URL
if (typeof data.url != "undefined") {
$(`#${data.id}-card-${data.panel} .card-body`).load(data.url);
}
// LOAD CONTENT FROM HTML
if (typeof data.html != "undefined") {
$(`#${data.id}-card-${data.panel} .card-body`).html(data.html);
}
break;
default:
console.error("DO NOT HAVE SUCH REQUEST: " + data.request);
break;
}
wc.groupEnd();
return true;
};
/**
* @test
*/
static test(what) {
wc.group("Accordion.test:", what);
let w = document.querySelector("wc-accordion");
switch(what)
{
case "open":
wc.publish("wc-accordion", {time:new Date().getTime(), id:w.id, request:"open", panel:0, requestor:"my-accordion-1"});
break;
case "load":
wc.publish("wc-accordion", {time:new Date().getTime(), id:w.id, requestor:"my-accordion-1", request:"load", panel:1, url:"/mtk/render?ajax=1&callback=tk::dummy::3"})
break;
case "html":
wc.publish("wc-accordion", {time:new Date().getTime(), id:w.id, requestor:"my-accordion-1", request:"load", panel:2, html:"<h1>It Worked!</h1>"})
break;
}
wc.groupEnd();
return true;
}
}
window.customElements.define('wc-accordion', Accordion);
// SO I CAN CALL THE STATIC METHOD GLOBALLY
window.Accordion = Accordion;