UNPKG

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
(() => { 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); })();