137 lines
4.1 KiB
JavaScript
137 lines
4.1 KiB
JavaScript
|
|
||
|
const html = (content) => {
|
||
|
let template = document.createElement("template");
|
||
|
template.innerHTML = content;
|
||
|
return template.content
|
||
|
};
|
||
|
|
||
|
class NewsSummary extends HTMLElement {
|
||
|
constructor() {
|
||
|
super();
|
||
|
|
||
|
this.cache = true;
|
||
|
this.state = {};
|
||
|
}
|
||
|
|
||
|
async read(part, id) {
|
||
|
let hn = "https://hacker-news.firebaseio.com/v0";
|
||
|
|
||
|
switch(part) {
|
||
|
case "list":
|
||
|
return await fetch(`${hn}/topstories.json`).then(r => r.json()).then(r => r);
|
||
|
case "details":
|
||
|
return await fetch(`${hn}/item/${id}.json`).then(r => r.json()).then(r => r);
|
||
|
default:
|
||
|
return {}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Returns a value or false
|
||
|
*
|
||
|
* useful for truthy expressions where objects or arrays are defined, but empty
|
||
|
*
|
||
|
* @param {Any} val
|
||
|
*/
|
||
|
_exists(val) {
|
||
|
|
||
|
// console.log('typeof', val, typeof val);
|
||
|
|
||
|
if(typeof val !== 'object' || val === null) {
|
||
|
return !!val ? val : false;
|
||
|
} else {
|
||
|
|
||
|
if(typeof val === "object") {
|
||
|
|
||
|
if(val.length !== 'undefined') {
|
||
|
return !!val.length ? val : false;
|
||
|
} else {
|
||
|
|
||
|
return (Object.getOwnPropertyNames(val).length > 0) ? val : false;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* Local Storage Helper
|
||
|
*/
|
||
|
_store() {
|
||
|
return {
|
||
|
get: (key) => {
|
||
|
return this._exists(JSON.parse(window.localStorage.getItem(key)));
|
||
|
},
|
||
|
set: (key, val) => {
|
||
|
return this._exists(window.localStorage.setItem(key, JSON.stringify(val)));
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
async connectedCallback() {
|
||
|
console.log('connected');
|
||
|
|
||
|
// get identifiers list
|
||
|
if(this.cache) {
|
||
|
console.log('cache enabled...');
|
||
|
|
||
|
if(this._store().get("list")) {
|
||
|
console.log('found in cache...');
|
||
|
this.state.list = this._store().get("list");
|
||
|
} else {
|
||
|
console.log('building cache...');
|
||
|
let list = await this.read("list");
|
||
|
this.state.list = list;
|
||
|
this._store().set("list", list);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
// get details from idenifiers list
|
||
|
if (this.cache) {
|
||
|
console.log('cache enabled...');
|
||
|
if (this._store().get("details")) {
|
||
|
console.log('found in cache...');
|
||
|
this.state.details = this._store().get("details");
|
||
|
} else {
|
||
|
console.log('building cache...');
|
||
|
this.state.details = [];
|
||
|
|
||
|
for (let i =0; i < 15; i++) {
|
||
|
let item = await this.read("details", this.state.list[i]);
|
||
|
this.state.details.push(item);
|
||
|
}
|
||
|
|
||
|
this._store().set("details", this.state.details);
|
||
|
}
|
||
|
|
||
|
console.log('...done');
|
||
|
}
|
||
|
|
||
|
this._render();
|
||
|
|
||
|
}
|
||
|
|
||
|
// _template() {
|
||
|
// return html`
|
||
|
// <section class="surfaced">
|
||
|
// <h6 class="inline capitalized title"><a href="${item.url}">${item.title}</a></h6>
|
||
|
// <div class="weak is-sm">[ hype: ${item.score} | topic: <a href="">${item.type}</a> | source: <a href="">${item.by}</a> | <a href="">${item.kids.length} comments</a> ]</div>
|
||
|
// </section>
|
||
|
// `;
|
||
|
// }
|
||
|
|
||
|
_render() {
|
||
|
this.innerHTML = `
|
||
|
${this.state.details.map(item => `
|
||
|
<div class="surfaced" style="margin-bottom: 8px;">
|
||
|
<h6 class="inline capitalized title"><a href="${item.url}">${item.title}</a></h6>
|
||
|
<div>
|
||
|
<small class="weak">[ hype: ${item.score} | topic: <a href="">${item.type}</a> | source: <a href="">${item.by}</a> | <a href="">${(item.kids || []).length} comments</a> ]</small>
|
||
|
</div>
|
||
|
</div>
|
||
|
`).join('')}
|
||
|
`;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
customElements.define('news-summary', NewsSummary);
|