<div class="container-fluid">
<header>
<h1>Custom Element Demo</h1>
</header>
<hr/>
<div class="row">
<div class="col-sm-6">
<div id="prefill">
<div class="input-group">
<span class="input-group-addon">
Autofill this form
</span>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="opts">
</div>
<button class="btn btn-secondary dropdown-toggle form-control" type="button" id="opts" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">Select Data</button>
</div>
</div>
<hr />
<form>
<div class="form">
<div class="form-group">
<label for="width">Width <small class="text-muted">(in px)</small></label>
<input type="number" class="form-control" id="width" placeholder="Width">
</div>
<div class="form-group">
<label for="alt">Alt <small class="text-muted">(can be empty)</small></label>
<input type="text" class="form-control" id="alt" placeholder="Alt Attriibute">
</div>
<div class="form-group">
<label for="src">Source Image <small class="text-muted">(src)</small></label>
<input type="url" class="form-control" id="src" placeholder="http://.....">
</div>
<div class="form-group">
<label for="caption">Caption <small class="text-muted">(figcaption)</small></label>
<input type="text" class="form-control" id="caption" placeholder="Caption">
</div>
</div>
<div>
<button type="button" class="btn btn-primary" id="append">Add</button>
<button type="button" class="btn btn-danger float-right" id="clear">Remove all</button>
<button type="reset" class="btn btn-warning">Reset</button>
</div>
</form>
<hr>
</div>
<div class="col-sm-6">
<div id="app"></div>
</div>
</div>
</div>
let elName = 'img-figure';
const template = state => `<figure>
<img
src="${state.src}"
alt="${state.alt || state.caption}">
<figcaption>${state.caption}</figcaption>
</figure>
`;
class ImgFigure extends HTMLElement {
connectedCallback() {
this.src = this.getAttribute("src") || null;
this.caption = this.getAttribute("caption") || "";
this.alt = this.getAttribute("alt") || null;
this.render();
}
render() {
this.innerHTML = template({
src: this.src,
alt: this.alt,
caption: this.caption
});
}
}
customElements.define("img-figure", ImgFigure);
const maxWidth = 400;
const data = [
{
src: "//res.cloudinary.com/time2hack/image/upload/q_auto:good/goodbye-xmlhttprequest-ajax-with-fetch-api-demo.png",
alt: "GoodBye XMLHttpRequest",
caption: "GoodBye XMLHttpRequest; AJAX with fetch API (with Demo)"
},
{
src: "//res.cloudinary.com/time2hack/image/upload/iterating-data-with-map-reduce-foreach-and-filter.png",
alt: "Array Iteration Functions",
caption: 'Iterating data with Map, Reduce, ForEach and Filter'
},
{
src: "//res.cloudinary.com/time2hack/image/upload/q_auto:good/ways-to-host-single-page-application-spa-static-site-for-free.png",
alt: "Free Static Hosting",
caption:
"Ways to host single page application (SPA) and Static Site for FREE"
},
{
src: "//res.cloudinary.com/time2hack/image/upload/v1508699480/javascript-template-literals.png",
alt: "JavaScript Template Literals",
caption: "Benefits of JavaScript Template Literals and Tagged Templates"
}
];
const card = data => {
const id = `${+new Date}`;
return `<div class="card" id="card_${id}">
<div class="card-header">
<ul class="nav nav-tabs card-header-tabs">
<!--
<li class="nav-item">
<a class="nav-link disabled" href="#">#card_${id}</a>
</li>
-->
<li class="nav-item">
<a class="nav-link active" data-target="#card_${id} .preview" href="#">Preview</a>
</li>
<li class="nav-item">
<a class="nav-link" data-target="#card_${id} .source" href="#">Source</a>
</li>
<li class="nav-item">
<a class="nav-link" data-target="#card_${id} .data" href="#">Data</a>
</li>
</ul>
</div>
<div class="card-body tab-bodies">
<div class="preview active">${elSrc(data)}</div>
<div class="source">${source(data)}</div>
<div class="data"><pre>${JSON.stringify(data, null, 2)}</pre></div>
</div>
</div>
`;
};
const elSrc = data => {
console.log(elName)
return `<${elName}
style="max-width: ${data.maxWidth || maxWidth}px"
src="${data.src}"
alt="${data.alt}"
caption="${data.caption}"
></${elName}>`;
}
// Add element in conventional way
const element = data => {
// create element
const i = document.createElement(elName);
//set the required attributes
i.setAttribute("src", data.src);
i.setAttribute("caption", data.caption);
i.setAttribute("alt", data.alt);
i.style.maxWidth = data.maxWidth || maxWidth;
return i;
};
const clear = () => (document.querySelector("#app").innerHTML = "");
const _prettify = block => {
window.PR &&
(function(block) {
block.classList.add("prettyprint");
PR.prettyPrint();
})(block);
};
const source = data => {
const src = elSrc(data).replace(/</ig, '<').replace(/>/ig, '>');
return `<pre>${src}</pre>`;
};
const getFormData = () => {
return {
maxWidth: document.querySelector("#width").value,
alt: document.querySelector("#alt").value,
src: document.querySelector("#src").value,
caption: document.querySelector("#caption").value
};
};
const add = data => {
const d = document.createElement('div');
d.innerHTML = card(data);
document.querySelector("#app").insertBefore(d, document.querySelector("#app").firstChild);
Array.prototype.slice.call(document.querySelectorAll('pre:not(.prettyprinted)'))
.forEach(el => _prettify(el))
}
//attach to the DOM
clear();
add(data[0]);
data.forEach((item, index) => {
const container = document.querySelector('#prefill .dropdown-menu');
const a = document.createElement('a');
a.classList.add('dropdown-item')
a.setAttribute('href', '#');
a.setAttribute('data-index', index);
a.innerHTML = `<img src="${item.src}" height="35" alt="${item.alt}" class="rounded" /> ${item.caption}`;
container.appendChild(a);
})
document.querySelector("#append").addEventListener("click", () => {
add(getFormData());
});
document.querySelector("#clear").addEventListener("click", () => {
clear();
});
document.querySelector("#prefill").addEventListener("click", (e) => {
e.preventDefault();
if(e.target.classList.contains('dropdown-item')){
const index = e.target.dataset.index;
document.querySelector("#width").value = data[index].maxWidth;
document.querySelector("#alt").value = data[index].alt
document.querySelector("#src").value = data[index].src
document.querySelector("#caption").value = data[index].caption;
document.querySelector('#prefill .dropdown-menu').classList.remove('show')
}
});
document.querySelector("#opts").addEventListener("click", (e) => {
e.preventDefault();
const toggle = document.querySelector('#prefill .dropdown-menu').classList.contains('show');
document.querySelector('#prefill .dropdown-menu').classList[toggle ? 'remove' : 'add']('show');
});
//All the tab changing events
document.querySelector("#app").addEventListener("click", (e) => {
e.preventDefault();
const {target} = e;
const a = 'active';
if(target.classList.contains('nav-link') && target.dataset.target) {
const t = target.dataset.target;
const c = t.split(' ')[0];
document.querySelector(`${c} .nav-link.${a}`).classList.remove(a);
target.classList.add(a);
document.querySelector(`${c} .tab-bodies > .${a}`).classList.remove(a);
document.querySelector(target.dataset.target).classList.add(a);
}
})