PageSourceSearch

https://www.acgyxyz.com/wp-content/themes/lolimeow-shiroki/assets/js/comments.js?ver=16.35

js acgyxyz.com collected 2026-10-09 22:11:07 UTC 15,894 bytes, 388 lines download raw bytes

1(function() {
2    'use strict';
3
4    // 📝 评论表单 AJAX 提交(使用事件委托,兼容 Swup 动态加载的表单)
5    function bindCommentFormSubmit() {
6        // 避免重复绑定
7        if (document.body && document.body.dataset.shirokiCommentSubmitBound === 'true') {
8            return;
9        }
10        if (document.body) {
11            document.body.dataset.shirokiCommentSubmitBound = 'true';
12        }
13
14        document.body.addEventListener('submit', function(e) {
15            const commentForm = e.target.closest('#commentform');
16            if (!commentForm) return;
17
18            e.preventDefault();
19
20            const commentField = commentForm.querySelector('#comment');
21            if (commentField && !commentField.value.trim()) {
22                commentField.classList.add('shiroki-field-error');
23                if (window.ShirokiBubbleTooltip) {
24                    var emptyMsg = window.ShirokiBubbleTooltip.getEmptyValidationMessage
25                        ? window.ShirokiBubbleTooltip.getEmptyValidationMessage()
26                        : ((window.shirokiBubbleConfig && window.shirokiBubbleConfig.emptyValidationMsg) || '请输入内容');
27                    window.ShirokiBubbleTooltip.showValidationError(commentField, emptyMsg);
28                }
29                return;
30            }
31
32            const formData = new FormData(commentForm);
33            const messageArea = document.querySelector('.message-content');
34            const submitBtn = commentForm.querySelector('.submit-btn');
35            const submitBtnIcon = submitBtn.querySelector('i');
36
37            // 更改按钮状态为提交中
38            submitBtn.disabled = true;
39            submitBtnIcon.className = 'fa fa-spinner fa-spin';
40            submitBtn.innerHTML = `${submitBtnIcon.outerHTML} 正在发表...`;
41
42            // 添加AJAX请求参数
43            formData.append('action', 'ajax_comment');
44            formData.append('security', document.querySelector('#comment_nonce_field').value);
45
46            fetch(window.ajax_object.ajaxurl, {
47                method: 'POST',
48                body: formData,
49                credentials: 'same-origin'
50            })
51            .then(response => response.json())
52            .then(data => {
53                if (data.success) {
54                    // 清空输入框
55                    commentForm.querySelector('textarea').value = '';
56
57                    // 更新用户信息显示
58                    const userNameElement = document.querySelector('.user-info .user-name');
59                    const userEmailElement = document.querySelector('.user-info .user-email');
60                    if (userNameElement && !window.ajax_object .is_user_logged_in) {
61                        userNameElement.textContent = formData.get('author');
62                    }
63                    if (userEmailElement && !window.ajax_object .is_user_logged_in) {
64                        userEmailElement.textContent = formData.get('email');
65                    }
66
67                    // 获取新评论容器
68                    const commentNew = document.querySelector('.comment-new');
69                    const newContent = commentNew.querySelector('.new-content');
70
71                    // 插入新评论
72                    const newComment = createCommentElement(data.data.comment);
73                    newContent.insertAdjacentElement('afterbegin', newComment);
74
75                    // 显示新评论容器并添加动画效果
76                    commentNew.style.display = 'block';
77                    void commentNew.offsetWidth;
78                    commentNew.classList.add('show');
79
80                    // 初始化新评论中的懒加载图片
81                    const lazyImages = newComment.querySelectorAll('img.lazy');
82                    lazyImages.forEach(img => {
83                        const imageObserver = new IntersectionObserver((entries, observer) => {
84                            entries.forEach(entry => {
85                                if (entry.isIntersecting) {
86                                    img.src = img.dataset.src;
87                                    img.classList.remove('lazy');
88                                    observer.unobserve(img);
89                                }
90                            });
91                        });
92                        imageObserver.observe(img);
93                    });
94
95                    // 更新评论计数
96                    updateCommentCount();
97
98                    showMessage(data.data.message || '评论提交成功!', 'success');
99                } else {
100                    showMessage(data.data || '提交失败,请检查输入!', 'error');
101                }
102            })
103            .catch(error => {
104                console.error('评论提交错误:', error);
105                showMessage('网络错误,请重试!', 'error');
106            })
107            .finally(() => {
108                // 恢复按钮状态
109                submitBtn.disabled = false;
110                submitBtnIcon.className = 'fa fa-paper-plane';
111                submitBtn.innerHTML = `${submitBtnIcon.outerHTML} 发表评论`;
112            });
113        });
114    }
115
116    // 创建评论元素
117    function createCommentElement(comment) {
118        // 使用临时div包裹处理空格问题
119        const tempDiv = document.createElement('div');
120        tempDiv.innerHTML = comment.trim();
121        return tempDiv.firstElementChild;
122    }
123
124    // 更新评论数量
125    function updateCommentCount() {
126        const countElement = document.querySelector('.post-comments h2');
127        const currentCount = parseInt(countElement.textContent.match(/\d+/)[0]);
128        countElement.textContent = countElement.textContent.replace(/\d+/, currentCount + 1);
129    }
130
131    // 回复按钮处理
132    document.body.addEventListener('click', function(e) {
133        if (e.target.closest('.comment-reply-link')) {
134            e.preventDefault();
135            const replyLink = e.target.closest('.comment-reply-link');
136            const commentId = replyLink.dataset.commentid;
137            document.querySelector('#comment_parent').value = commentId;
138            document.getElementById('cancel-comment-reply-link').style.display = 'inline';
139        }
140    });
141});
142
143// 评论工具栏功能初始化
144function initCommentToolbar() {
145    const commentTextarea = document.querySelector('#comment');
146    const emojiBtn = document.querySelector('.emoji-btn');
147    const uploadBtn = document.querySelector('.upload-btn');
148    const codeBtn = document.querySelector('.code-btn');
149    const emojiPanel = document.querySelector('.emoji-panel');
150    const codePanel = document.querySelector('.code-panel');
151    const uploadInput = document.querySelector('.upload-input');
152    
153    if(emojiBtn && emojiPanel) {
154        emojiBtn.addEventListener('click', (e) => {
155            e.stopPropagation();
156            // 添加元素存在性检查
157            const isVisible = emojiPanel && emojiPanel.style.display === 'block';
158            if(emojiPanel) {
159                emojiPanel.style.display = isVisible ? 'none' : 'block';
160                codePanel && (codePanel.style.display = 'none');
161            }
162            
163            if(emojiPanel && !isVisible) {
164                const firstTab = emojiPanel.querySelector('.emoji-tabs span');
165                if(firstTab) {
166                    firstTab.click();
167                }
168            }
169        });
170
171        const emojis = {
172            emoji: [
173                '😀','😁','😂','🤣','😃','😄',
174                '😅','😆','😉','😊','😋','😎',
175                '😍','🥰','😘','😗','😙','😚',
176                '😛','😝','🤗','🤔','🤨','😐',
177                '😑','😶','🙄','😏','😣','😥',
178                '😮','🤤','😴','😪','😵','😵',
179                '😵','🤯','🤠','🤡','🤥','🤫',
180                '🤔','🤨','😐','😑','😶','🙄',
181            ],
182            custom: ['(⌒▽⌒)', '( ̄▽ ̄)', '(=・ω・=)', '(`・ω・´)', 
183                '(〜 ̄△ ̄)〜', '(・∀・)', '(°∀°)ノ', '( ̄3 ̄)', '╮( ̄▽ ̄)╭',
184                '(*>.<*)', '( ˃̶͈◡˂̶͈ ) hi!','⚆_⚆?', '⚆_⚆', '(。•ˇ‸ˇ•。)',
185                'Ciallo~(∠・ω< )⌒☆', 'ԅ(¯﹃¯ԅ)', '(¯﹃¯)', '(ノへ ̄、)',
186                'd=====( ̄▽ ̄*)b','[]~( ̄▽ ̄)~*','○| ̄|_','Σ( ° △ °|||)︴',
187                'o((⊙﹏⊙))o.','✧(≖ ◡ ≖✿)','( ̄_, ̄ )',' ̄へ ̄'
188            ]        
189        };
190
191        const emojiContent = emojiPanel.querySelector('.emoji-content');
192        const emojiTabs = emojiPanel.querySelectorAll('.emoji-tabs span');
193                emojiTabs.forEach(tab => {
194            tab.addEventListener('click', () => {
195                const type = tab.dataset.tab;
196                emojiTabs.forEach(t => t.classList.remove('active'));
197                tab.classList.add('active');
198                emojiContent.innerHTML = '';
199                emojis[type].forEach(emoji => {
200                    const span = document.createElement('span');
201                    span.textContent = emoji;
202                    span.addEventListener('click', () => {
203                        insertAtBoxmoe(commentTextarea, emoji);
204                        emojiPanel.style.display = 'none';
205                    });
206                    emojiContent.appendChild(span);
207                });
208            });
209            
210            // 默认激活emoji标签
211            if(tab.classList.contains('active')) {
212                tab.click();
213            }
214        });
215    }
216
217    // 图片上传功能
218    if(uploadBtn && uploadInput) {
219        uploadBtn.addEventListener('click', () => {
220            uploadInput.click();
221        });
222
223        uploadInput.addEventListener('change', async (e) => {
224            const file = e.target.files[0];
225            if(file) {
226                if(file.size > 2 * 1024 * 1024) { // 2MB限制
227                    showMessage('图片大小不能超过2MB', 'error');
228                    return;
229                }
230                
231                try {
232                    const imgUrl = await uploadImage(file);
233                    insertAtBoxmoe(commentTextarea, `![${file.name}](${imgUrl})`);
234                } catch(err) {
235                    showMessage('图片上传失败', 'error');
236                }
237            }
238        });
239    }
240
241    // pl代码高亮插入功能
242    if(codeBtn && codePanel) {
243        const closeBtn = codePanel.querySelector('.close-btn');
244        const insertBtn = codePanel.querySelector('.insert-code-btn');
245        const codeInput = codePanel.querySelector('.code-input');
246        const langSelect = codePanel.querySelector('.code-language');
247
248        // 初始化代码面板位置
249        codePanel.style.display = 'none';
250        
251        codeBtn.addEventListener('click', (e) => {
252            e.stopPropagation();
253            codePanel.style.display = codePanel.style.display === 'none' ? 'block' : 'none';
254            emojiPanel && (emojiPanel.style.display = 'none');
255            if(codePanel.style.display === 'block') {
256                codeInput.focus();
257            }
258        });
259
260        closeBtn.addEventListener('click', () => {
261            codePanel.style.display = 'none';
262        });
263
264        insertBtn.addEventListener('click', () => {
265            const code = codeInput.value.trim();
266            if(code) {
267                // 修改为WordPress兼容的pre+code标签格式
268                const codeBlock = `\n<pre><code class="language-">\n${code}\n</code></pre>\n`;
269                insertAtBoxmoe(commentTextarea, codeBlock);
270                codeInput.value = '';
271                codePanel.style.display = 'none';
272            }
273        });
274
275        // 回车键提交支持
276        codeInput.addEventListener('keydown', (e) => {
277            if(e.key === 'Enter' && (e.ctrlKey || e.metaKey)) {
278                insertBtn.click();
279            }
280        });
281    }
282
283    document.addEventListener('click', (e) => {
284        // 添加元素存在性检查
285        if(emojiPanel && emojiBtn) {
286            if(!emojiPanel.contains(e.target) && !emojiBtn.contains(e.target)) {
287                emojiPanel.style.display = 'none';
288            }
289        }
290        if(codePanel && codeBtn) {
291            if(!codePanel.contains(e.target) && !codeBtn.contains(e.target)) {
292                codePanel.style.display = 'none';
293            }
294        }
295    });
296}
297// 评论回复初始化
298function initCommentReply() {
299    const commentForm = document.getElementById('respond');
300    const cancelReply = document.getElementById('cancel-comment-reply-link');
301    const commentList = document.querySelector('.comments-list');
302    if (!commentForm || !cancelReply || !commentList) return;
303    let originalPosition = null; 
304    document.querySelectorAll('.comment-reply-link').forEach(link => {
305        link.addEventListener('click', (e) => {
306            e.preventDefault();
307            if (!commentForm) return;        
308            if (!originalPosition) {
309                originalPosition = commentForm.parentNode;
310            }
311            const commentItem = link.closest('.comment-item');
312            const commentContent = commentItem?.querySelector('.comment-content');               
313            if (!commentContent) return;         
314            cancelReply.style.display = 'inline-block';
315            commentContent.appendChild(commentForm);
316            commentForm.scrollIntoView({ behavior: 'smooth', block: 'center' });
317            commentForm.querySelector('#comment')?.focus();
318        });
319    });
320    if(cancelReply) {
321        cancelReply.addEventListener('click', (e) => {
322            e.preventDefault();
323            cancelReply.style.display = 'none';
324            if (originalPosition) {
325                originalPosition.appendChild(commentForm);
326            }
327            commentForm?.scrollIntoView({ behavior: 'smooth', block: 'center' });
328        });
329    }
330}
331
332// 评论消息初始化
333function showMessage(message, type = 'success') {
334    const messageEl = document.querySelector('.comment-message');
335    const contentEl = messageEl.querySelector('.message-content');
336    
337    messageEl.className = 'comment-message ' + type;
338    contentEl.textContent = message;
339    messageEl.classList.add('show');
340
341    setTimeout(() => {
342        messageEl.classList.remove('show');
343    }, 5000);
344}
345
346//编辑器辅助函数
347function insertAtBoxmoe(textarea, text) {
348    const start = textarea.selectionStart;
349    const end = textarea.selectionEnd;
350    const value = textarea.value;
351    
352    textarea.value = value.substring(0, start) + text + value.substring(end);
353    textarea.selectionStart = textarea.selectionEnd = start + text.length;
354    textarea.focus();
355}
356
357// 评论列表显示/隐藏功能初始化
358function initCommentsToggle() {
359    const toggle = document.querySelector('.comments-toggle');
360    const commentsList = document.querySelector('.comments-list');
361    
362    if (!toggle || !commentsList) return;
363    
364    // 从localStorage获取状态
365    const isOpen = localStorage.getItem('commentsListOpen') === 'true';
366    
367    // 初始化状态
368    if (isOpen) {
369        toggle.classList.add('active');
370        toggle.querySelector('span').textContent = '收起评论列表';
371        commentsList.classList.add('show');
372    }
373    
374    toggle.addEventListener('click', () => {
375        const isActive = toggle.classList.toggle('active');
376        toggle.querySelector('span').textContent = isActive ? '收起评论列表' : '查看评论列表';
377        commentsList.classList.toggle('show');
378        
379        // 保存状态到localStorage
380        localStorage.setItem('commentsListOpen', isActive);
381    });
382}
383
384document.addEventListener("DOMContentLoaded", () => {
385    initCommentReply();
386    initCommentToolbar();
387    initCommentsToggle();
388});

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.