PageSourceSearch

https://edi.wang/js/app/post.z348nh7y90.mjs

js edi.wang collected 2026-10-03 20:17:49 UTC 7,299 bytes, 212 lines download raw bytes

1import { fetch2 } from './httpService.mjs?v=1500'
2import { formatUtcTime, parseMetaContent } from './utils.module.mjs';
3import { resizeImages, applyImageZooming } from './post.imageutils.mjs';
4import { renderCodeHighlighter, renderLaTeX } from './post.highlight.mjs';
5import { renderMermaid } from './post.mermaid.mjs';
6import { calculateReadingTime } from './post.readingtime.mjs';
7import { recordPostView } from './postview.mjs';
8import { error } from './toastService.mjs';
9
10const commentEditorStylesheetId = 'comment-markdown-editor-stylesheet';
11const commentEditorStylesheetPath = '/_content/Moonglade.Editor.StaticAssets/moonglade-editor/moonglade-editor.css';
12const commentEditorModulePath = '/_content/Moonglade.Editor.StaticAssets/moonglade-editor/moonglade-editor.code.js';
13let commentEditorModulePromise = null;
14let commentMarkdownEditor = null;
15let commentMarkdownEditorEnabled = false;
16
17function ensureCommentEditorStylesheet() {
18    if (document.getElementById(commentEditorStylesheetId)) {
19        return;
20    }
21
22    const link = document.createElement('link');
23    link.id = commentEditorStylesheetId;
24    link.rel = 'stylesheet';
25    link.href = commentEditorStylesheetPath;
26    document.head.append(link);
27}
28
29async function ensureCommentEditorModule() {
30    commentEditorModulePromise ??= import(commentEditorModulePath);
31    return await commentEditorModulePromise;
32}
33
34async function enableCommentMarkdownEditor() {
35    if (commentMarkdownEditorEnabled) {
36        return;
37    }
38
39    const editorElement = document.querySelector('#comment-markdown-editor');
40    const textarea = document.querySelector('#input-comment-content');
41    if (!editorElement || !textarea) {
42        return;
43    }
44
45    ensureCommentEditorStylesheet();
46    const { createMoongladeCodeEditor } = await ensureCommentEditorModule();
47
48    textarea.removeAttribute('required');
49    textarea.classList.add('d-none');
50    editorElement.classList.remove('d-none');
51    commentMarkdownEditor = createMoongladeCodeEditor({
52        element: editorElement,
53        textarea,
54        content: textarea.value || '',
55        language: 'markdown',
56        height: '180px',
57        lineWrapping: true
58    });
59    commentMarkdownEditorEnabled = true;
60    commentMarkdownEditor.focus();
61}
62
63function disableCommentMarkdownEditor() {
64    const editorElement = document.querySelector('#comment-markdown-editor');
65    const textarea = document.querySelector('#input-comment-content');
66
67    if (commentMarkdownEditor) {
68        commentMarkdownEditor.syncToTextarea();
69        commentMarkdownEditor.destroy();
70        commentMarkdownEditor = null;
71    }
72
73    editorElement?.replaceChildren();
74    editorElement?.classList.add('d-none');
75
76    if (textarea) {
77        textarea.classList.remove('d-none');
78        textarea.setAttribute('required', 'required');
79    }
80
81    commentMarkdownEditorEnabled = false;
82}
83
84function resetCommentMarkdownEditor() {
85    const toggle = document.querySelector('#input-comment-use-markdown-editor');
86    if (toggle) {
87        toggle.checked = false;
88    }
89
90    disableCommentMarkdownEditor();
91}
92
93function syncCommentMarkdownEditor() {
94    commentMarkdownEditor?.syncToTextarea();
95}
96
97function isCommentMarkdownEditorEnabled() {
98    return commentMarkdownEditorEnabled && !!commentMarkdownEditor;
99}
100
101async function toggleCommentMarkdownEditor(event) {
102    const checkbox = event.currentTarget;
103    checkbox.disabled = true;
104
105    try {
106        if (checkbox.checked) {
107            await enableCommentMarkdownEditor();
108        }
109        else {
110            disableCommentMarkdownEditor();
111        }
112    }
113    catch (err) {
114        checkbox.checked = false;
115        disableCommentMarkdownEditor();
116        error(err);
117    }
118    finally {
119        checkbox.disabled = false;
120    }
121}
122
123async function submitComment(pid) {
124    const thxForComment = document.querySelector('#thx-for-comment');
125    const thxForCommentNonReview = document.querySelector('#thx-for-comment-non-review');
126    const loadingIndicator = document.querySelector('#loadingIndicator');
127    const btnSubmitComment = document.querySelector('#btn-submit-comment');
128    const commentForm = document.querySelector('#comment-form');
129    const commentContentInput = document.querySelector('#input-comment-content');
130
131    syncCommentMarkdownEditor();
132
133    const username = document.querySelector('#input-comment-name').value;
134    const content = commentContentInput.value;
135    const email = document.querySelector('#input-comment-email').value;
136    const source = document.querySelector('#input-comment-source')?.value ?? '';
137    const formRenderedUtc = Number(document.querySelector('#input-comment-form-rendered-utc')?.value ?? 0);
138
139    if (isCommentMarkdownEditorEnabled() && !content.trim()) {
140        commentMarkdownEditor.focus();
141        error(commentContentInput.dataset.commentRequiredMessage || commentContentInput.placeholder);
142        return;
143    }
144
145    thxForComment.style.display = 'none';
146    thxForCommentNonReview.style.display = 'none';
147    loadingIndicator.style.display = 'block';
148    btnSubmitComment.classList.add('disabled');
149    btnSubmitComment.setAttribute('disabled', 'disabled');
150
151    try {
152        const data = await fetch2(`/api/comment/${pid}`, 'POST', { username, content, email, source, formRenderedUtc });
153        resetCommentMarkdownEditor();
154        commentForm.reset();
155        resetCommentFormRenderedAt(data.formRenderedUtc);
156
157        if (data.requireCommentReview) {
158            thxForComment.style.display = 'block';
159        }
160        else {
161            thxForCommentNonReview.style.display = 'block';
162        }
163    } catch (err) {
164        error(err);
165    } finally {
166        loadingIndicator.style.display = 'none';
167        btnSubmitComment.classList.remove('disabled');
168        btnSubmitComment.removeAttribute('disabled');
169    }
170}
171
172function resetCommentFormRenderedAt(formRenderedUtc) {
173    const input = document.querySelector('#input-comment-form-rendered-utc');
174    if (input && Number.isFinite(formRenderedUtc)) {
175        input.value = formRenderedUtc.toString();
176    }
177}
178
179document.addEventListener('DOMContentLoaded', () => {
180    resizeImages('.post-content img');
181    if (window.innerWidth >= 768) {
182        applyImageZooming('.post-content img');
183    }
184
185    renderMermaid().catch(err => console.error(err));
186    renderCodeHighlighter();
187    renderLaTeX('pre.language-latex code');
188
189    if (parseMetaContent('post-is-published')) {
190
191        let pid = document.querySelector('article').dataset.postid;
192
193        const blogContent = document.querySelector('.post-content').innerText;
194        let roundedReadingTime = calculateReadingTime(blogContent);
195
196        const elem = document.getElementById('reading-time');
197        if (elem) {
198            elem.innerText = `Estimated Reading Time: ${roundedReadingTime} minute(s)`;
199        }
200
201        document.getElementById('comment-form')?.addEventListener('submit', function (e) {
202            e.preventDefault();
203            submitComment(pid);
204        });
205        document.getElementById('input-comment-use-markdown-editor')?.addEventListener('change', toggleCommentMarkdownEditor);
206        document.getElementById('btn-submit-comment')?.addEventListener('click', syncCommentMarkdownEditor);
207
208        formatUtcTime();
209
210        recordPostView(pid);
211    }
212});

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.