PageSourceSearch

https://geoconfirmed.org/Components/QuillEditor.dkjomxn3yq.razor.js

js geoconfirmed.org collected 2026-09-28 11:04:33 UTC 4,639 bytes, 140 lines download raw bytes

1const QUILL_CSS_URL = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.snow.css';
2const QUILL_JS_URL = 'https://cdn.jsdelivr.net/npm/[email protected]/dist/quill.js';
3
4let quillLoaderPromise = null;
5const instances = new Map();
6
7function loadQuill() {
8    if (quillLoaderPromise) return quillLoaderPromise;
9
10    quillLoaderPromise = new Promise((resolve, reject) => {
11        if (!document.querySelector('link[data-quill-css]')) {
12            const link = document.createElement('link');
13            link.rel = 'stylesheet';
14            link.href = QUILL_CSS_URL;
15            link.setAttribute('data-quill-css', '');
16            document.head.appendChild(link);
17        }
18
19        if (window.Quill) {
20            resolve(window.Quill);
21            return;
22        }
23
24        const existing = document.querySelector('script[data-quill-js]');
25        if (existing) {
26            existing.addEventListener('load', () => resolve(window.Quill));
27            existing.addEventListener('error', () => reject(new Error('Failed to load Quill from jsdelivr')));
28            return;
29        }
30
31        const script = document.createElement('script');
32        script.src = QUILL_JS_URL;
33        script.async = true;
34        script.setAttribute('data-quill-js', '');
35        script.addEventListener('load', () => resolve(window.Quill));
36        script.addEventListener('error', () => reject(new Error('Failed to load Quill from jsdelivr')));
37        document.head.appendChild(script);
38    });
39
40    return quillLoaderPromise;
41}
42
43export async function init(id, initialHtml, uploadUrl, placeholder, dotNetRef) {
44    const Quill = await loadQuill();
45    const container = document.getElementById(id);
46    if (!container) return;
47
48    const toolbar = [
49        [{ header: [2, 3, 4, false] }],
50        ['bold', 'italic', 'blockquote'],
51        [{ list: 'ordered' }, { list: 'bullet' }],
52        [{ indent: '-1' }, { indent: '+1' }],
53        [{ align: [] }],
54        ['link', 'image'],
55        ['clean']
56    ];
57
58    const quill = new Quill(container, {
59        theme: 'snow',
60        placeholder: placeholder || '',
61        modules: { toolbar: { container: toolbar } }
62    });
63
64    if (initialHtml) {
65        quill.clipboard.dangerouslyPasteHTML(initialHtml, 'silent');
66    }
67
68    if (uploadUrl) {
69        const toolbarModule = quill.getModule('toolbar');
70        toolbarModule.addHandler('image', () => {
71            const input = document.createElement('input');
72            input.type = 'file';
73            input.accept = 'image/png,image/jpeg,image/gif,image/webp,image/svg+xml';
74            input.addEventListener('change', async () => {
75                const file = input.files && input.files[0];
76                if (!file) return;
77
78                const formData = new FormData();
79                formData.append('file', file, file.name);
80
81                try {
82                    const res = await fetch(uploadUrl, {
83                        method: 'POST',
84                        credentials: 'same-origin',
85                        body: formData
86                    });
87
88                    if (!res.ok) {
89                        console.error('Quill image upload failed', res.status, await res.text());
90                        return;
91                    }
92
93                    const data = await res.json();
94                    if (!data || !data.url) {
95                        console.error('Quill image upload: response missing url', data);
96                        return;
97                    }
98
99                    const range = quill.getSelection(true);
100                    quill.insertEmbed(range.index, 'image', data.url, 'user');
101                    quill.setSelection(range.index + 1, 0, 'user');
102                } catch (err) {
103                    console.error('Quill image upload error', err);
104                }
105            });
106            input.click();
107        });
108    }
109
110    const handler = () => {
111        const html = quill.root.innerHTML;
112        dotNetRef.invokeMethodAsync('OnContentChangedFromJs', html);
113    };
114    quill.on('text-change', handler);
115
116    instances.set(id, { quill, dotNetRef, handler });
117}
118
119export function setContent(id, html) {
120    const entry = instances.get(id);
121    if (!entry) return;
122
123    const current = entry.quill.root.innerHTML;
124    if (current === html) return;
125
126    entry.quill.clipboard.dangerouslyPasteHTML(html || '', 'silent');
127}
128
129export function dispose(id) {
130    const entry = instances.get(id);
131    if (!entry) return;
132
133    try {
134        entry.quill.off('text-change', entry.handler);
135    } catch (_) {
136        // ignore — Quill may already be torn down
137    }
138
139    instances.delete(id);
140}

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.