UNPKG

@sertxudeveloper/markdown-editor

Version:
193 lines (155 loc) 4.92 kB
import Editor from '../../Editor'; import { insertText } from '../../utils/Utils'; import BlockStyle from '../BlockStyle'; export type Image = { url: string; alt: string; name: string; }; export default class ImageBrowser { editor: Editor; element?: HTMLDivElement; container?: HTMLDivElement; images: Image[] = []; constructor(editor: Editor) { this.editor = editor; } /** * Initialize the image browser * * @returns void */ init() { this.element = document.createElement('div'); this.element.classList.add('markdown-image-browser'); this.element.addEventListener('click', (e) => { if (e.target === this.element) this.onClose(); }); window.addEventListener('keydown', (e) => { if (!this.element) return; if (e.key === 'Escape') this.onClose(); }); this.container = document.createElement('div'); this.container.classList.add('browser-container'); } /** * Fetch the images from the endpoint and render the image browser * * @returns void */ browse() { if (!this.editor.textarea) return; const textarea = this.editor.textarea; if (!this.element || !this.container) this.init(); this.container.innerHTML = ''; this.initHeader(); const grid = document.createElement('div'); grid.classList.add('browser-grid'); this.fetchImages().then((images: Image[]) => { this.images = images; this.render(grid); }); this.element.appendChild(this.container); document.body.appendChild(this.element); } /** * Render the image browser * * @returns void */ render(grid: HTMLDivElement): void { for (const image of this.images) { let imageElement = this.renderImage(image); grid.appendChild(imageElement); } this.container.appendChild(grid); } /** * Initialize the header * * @returns void */ initHeader() { const header = document.createElement('div'); header.classList.add('browser-header'); const title = document.createElement('span'); title.innerText = 'Select an image'; const close = document.createElement('button'); close.innerHTML = '&times;'; close.addEventListener('click', this.onClose.bind(this)); header.appendChild(title); header.appendChild(close); this.container.appendChild(header); } onClose() { this.element.remove(); } /** * Render the provided image * * @param image Image to render * @returns HTMLDivElement */ renderImage(image: Image): HTMLDivElement { const container = document.createElement('div'); container.classList.add('browser-grid-item'); container.setAttribute('role', 'button'); const img = document.createElement('img'); img.src = image.url; img.alt = image.alt; const name = document.createElement('div'); name.innerText = image.name; container.addEventListener('click', this.insertImage.bind(this, image)); container.appendChild(img); container.appendChild(name); return container; } /** * Insert the selected image into the textarea * * @param image Image to insert * @returns void */ insertImage(image: Image): void { if (!this.editor.textarea) return; const textarea = this.editor.textarea; BlockStyle.applyStyle(textarea, { prefix: `![${image.alt}](${image.url})`, suffix: '', replaceNext: '', scanFor: 'https?://', surroundWithNewlines: true, }); insertText(textarea, { text: '\n', selectionStart: textarea.selectionStart + 1, selectionEnd: textarea.selectionStart + 1, }); this.element.remove(); } /** * Get all the images from the provided endpoint * * @returns Promise<Image[]> */ fetchImages(): Promise<Image[]> { return new Promise((resolve, reject) => { fetch(this.editor.config.imageBrowserUrl, { method: 'GET', headers: { 'Content-Type': 'application/json', Accept: 'application/json', 'X-Requested-With': 'XMLHttpRequest', Referer: window.location.href, }, }) .then((response) => response.json()) .then((json) => { resolve(json); }) .catch((error) => { reject(error); }); }); } }