451-tools
Version:
Censorship resilient and distributed publishing: informed by the needs of publishers and their audiences, More Mirrors implements a set of offline fallback strategies for censorship resilient websites.
110 lines (89 loc) • 3.09 kB
JavaScript
(() => {
const BOOKMARK_NAMESPACE = '451-tools';
const template = document.createElement('template');
template.innerHTML = `
<button type="button" part="button"></button>
`;
class BookmarkButton extends HTMLElement {
constructor () {
super();
const shadowRoot = this.attachShadow({ mode: 'open' });
shadowRoot.appendChild(template.content.cloneNode(true));
this.button = shadowRoot.querySelector('button');
this.button.addEventListener('click', this.handleClick.bind(this));
}
async connectedCallback () {
if (!this.path) {
throw new Error('BookmarkButton: The "path" attribute is required.');
}
const isBookmarked = await this.isBookmarked();
this.button.textContent = isBookmarked
? this.removeBookmarkText
: this.bookmarkText;
}
async handleClick (e) {
e.preventDefault();
const bookmarkUrl = `/${BOOKMARK_NAMESPACE}/bookmark/${encodeURIComponent(this.path)}`;
const wasBookmarked = await this.isBookmarked();
fetch(bookmarkUrl, {
method: wasBookmarked ? 'DELETE' : 'POST',
headers: { 'Content-Type': 'application/json' },
body:
!wasBookmarked && this.metadata
? JSON.stringify({ metadata: this.metadata })
: null,
}).then((res) => {
if (res.ok) {
this.button.textContent = wasBookmarked
? this.bookmarkText
: this.removeBookmarkText;
}
});
}
async isBookmarked () {
const bookmarkUrl = `/${BOOKMARK_NAMESPACE}/bookmark/${encodeURIComponent(
this.path
)}`;
return fetch(bookmarkUrl, { method: 'GET' }).then((res) => res.ok);
}
get bookmarkText () {
return this.getAttribute('bookmark-text') || 'Bookmark';
}
get removeBookmarkText () {
return this.getAttribute('remove-bookmark-text') || 'Remove Bookmark';
}
get path () {
return this.getAttribute('path');
}
get metadata () {
const title = this.getAttribute('metadata-title');
const description = this.getAttribute('metadata-description');
const imageSrc = this.getAttribute('metadata-image-src');
const imageHeight = this.getAttribute('metadata-image-height');
const imageWidth = this.getAttribute('metadata-image-width');
if (!title && !description && !imageSrc) {
return null;
}
return {
...(title && { title }),
...(description && { description }),
...(imageSrc && {
image: {
src: imageSrc,
...(imageHeight && { height: imageHeight }),
...(imageWidth && { width: imageWidth }),
},
}),
};
}
static get observedAttributes () {
return ['bookmark-text'];
}
attributeChangedCallback (name, oldValue, newValue) {
if (name === 'bookmark-text' && oldValue !== newValue) {
this.button.textContent = newValue;
}
}
}
customElements.define('bookmark-button', BookmarkButton);
})();