PageSourceSearch

https://evecodes.com/wp-content/plugins/wp-dapp-main/assets/js/hive-comment.js?ver=0.7.4.1761880409

js evecodes.com collected 2026-10-09 23:33:14 UTC 18,950 bytes, 317 lines download raw bytes

1/**
2 * WP-Dapp Hive Comment Integration
3 * Allows users to post replies to Hive directly from WordPress using Keychain.
4 */
5jQuery(document).ready(function($) {
6    // Check if Keychain is available
7    function isKeychainAvailable() {
8        return typeof hive_keychain !== 'undefined';
9    }
10
11    // Counter to generate unique IDs per reply form
12    let wpdappFormCounter = 0;
13
14    // Function to generate permlink
15    function generatePermlink(text) {
16        let permlink = text.toLowerCase()
17            .replace(/[^a-z0-9-]/g, '-')
18            .replace(/-+/g, '-')
19            .replace(/^-|-$/g, '');
20        permlink = permlink.substring(0, 50);
21        return permlink + '-' + Date.now().toString(36);
22    }
23
24    function addInlineReplyButtons() {
25        if (!wpdapp_frontend.show_reply_buttons) return;
26        $('.wpdapp-comment-list > li.wpdapp-comment').each(function() {
27            const $comment = $(this);
28            const hiveKey = $comment.data('hive-key');
29            if (!hiveKey) return;
30            const parts = String(hiveKey).split('/');
31            const author = parts[0] || '';
32            const permlink = parts[1] || '';
33            const $actions = $comment.children('.wpdapp-comment-body').children('.wpdapp-comment-actions');
34            if ($actions.length && $actions.find('.wpdapp-reply-button').length === 0) {
35                // Put Keychain reply button first, then the external link
36                $actions.prepend('<button type="button" class="wpdapp-reply-button" aria-label="' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.replyWithKeychain : 'Reply with Keychain') + '" data-author="' + author + '" data-permlink="' + permlink + '">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.replyWithKeychain : 'Reply with Keychain') + '</button>');
37            }
38        });
39    }
40
41    // Initial injection on page load
42    addInlineReplyButtons();
43
44    // Note: Top-level reply button is rendered server-side in the footer to avoid duplicates
45
46    // Username persistence: prefer localStorage, fallback to sessionStorage
47    let hiveUsername = (function() {
48        try { return localStorage.getItem('wpdapp_hive_username') || sessionStorage.getItem('wpdapp_hive_username') || null; } catch(e) { return sessionStorage.getItem('wpdapp_hive_username') || null; }
49    })();
50
51    // Open reply form (no connect step)
52    $(document).on('click', '.wpdapp-reply-button', function(e) {
53        e.preventDefault();
54        const $button = $(this);
55
56        let $form = $button.next('.wpdapp-reply-form');
57        if ($form.length === 0) {
58            const formId = ++wpdappFormCounter;
59            const usernameInputId = 'wpdapp-username-' + formId;
60            const connected = !!hiveUsername;
61            $form = $('<div class="wpdapp-reply-form" role="form" aria-live="polite" data-form-id="' + formId + '">' +
62                '<div class="wpdapp-conn-row">' +
63                    '<span class="wpdapp-status-chip ' + (connected ? 'connected' : 'not-connected') + '">' + (connected ? (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.statusConnected : 'Connected') : (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.statusNotConnected : 'Not connected')) + '</span>' +
64                    (connected
65                        ? '<p class="wpdapp-connected-as">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.connectedAs : 'Connected as:') + ' <span class="wpdapp-username-display">' + hiveUsername + '</span> <button type="button" class="wpdapp-change-account">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.change : 'Change') + '</button></p>'
66                        : '<label class="wpdapp-username-label" for="' + usernameInputId + '">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.enterHiveUsername : 'Enter your Hive username:') + '</label>' +
67                          '<input type="text" class="wpdapp-username" id="' + usernameInputId + '" placeholder="' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.hiveUsernamePlaceholder : 'Hive username') + '">'
68                      ) +
69                '</div>' +
70                '<textarea aria-label="' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.yourReply : 'Your reply') + '" placeholder="' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.yourReplyPlaceholder : 'Your reply...') + '"></textarea>' +
71                '<button type="button" class="wpdapp-submit-reply">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.submit : 'Submit') + '</button>' +
72                '<button type="button" class="wpdapp-cancel-reply">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.cancel : 'Cancel') + '</button>' +
73                '</div>');
74            $button.after($form);
75        }
76        $form.slideDown();
77        $form.find('textarea').focus();
78
79        // If Keychain missing, inform inline but do not block
80        if (!isKeychainAvailable() && $form.find('.wpdapp-keychain-warning').length === 0) {
81            $form.prepend('<div class="wpdapp-form-error wpdapp-keychain-warning" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.keychainNotDetected : 'Hive Keychain not detected. Please install the extension.') + '</div>');
82        }
83    });
84
85    // Change account: switch to edit mode
86    $(document).on('click', '.wpdapp-change-account', function() {
87        const $form = $(this).closest('.wpdapp-reply-form');
88        const formId = $form.data('form-id') || Date.now();
89        const editId = 'wpdapp-username-edit-' + formId;
90        const current = $form.find('.wpdapp-username-display').text().trim() || hiveUsername || '';
91        const label = '<label class="wpdapp-username-label" for="' + editId + '">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.enterHiveUsername : 'Enter your Hive username:') + '</label>';
92        const input = '<input type="text" class="wpdapp-username-edit" id="' + editId + '" value="' + current + '">';
93        const actions = '<button type="button" class="wpdapp-save-account">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.save : 'Save') + '</button>' +
94                        '<button type="button" class="wpdapp-cancel-account">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.cancel : 'Cancel') + '</button>';
95        $form.find('.wpdapp-connected-as').html(label + ' ' + input + ' ' + actions);
96        $form.find('#' + editId).focus();
97    });
98
99    // Save new account
100    $(document).on('click', '.wpdapp-save-account', function() {
101        const $form = $(this).closest('.wpdapp-reply-form');
102        const newUsername = ($form.find('.wpdapp-username-edit').val() || '').trim();
103        if (!newUsername) {
104            $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.pleaseEnterUsername : 'Please enter your Hive username.') + '</div>');
105            setTimeout(() => $form.find('.wpdapp-form-error').remove(), 3000);
106            return;
107        }
108        hiveUsername = newUsername;
109        try { localStorage.setItem('wpdapp_hive_username', hiveUsername); } catch(e) {}
110        sessionStorage.setItem('wpdapp_hive_username', hiveUsername);
111        $form.find('.wpdapp-connected-as').html(
112            (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.connectedAs : 'Connected as:') +
113            ' <span class="wpdapp-username-display">' + hiveUsername + '</span> ' +
114            '<button type="button" class="wpdapp-change-account">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.change : 'Change') + '</button>'
115        );
116        // Ensure chip shows connected
117        const $chip = $form.find('.wpdapp-status-chip');
118        $chip.removeClass('not-connected').addClass('connected').text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.statusConnected : 'Connected');
119    });
120
121    // Cancel account edit
122    $(document).on('click', '.wpdapp-cancel-account', function() {
123        const $form = $(this).closest('.wpdapp-reply-form');
124        const display = hiveUsername ? hiveUsername : '';
125        const inner = hiveUsername
126            ? (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.connectedAs : 'Connected as:') + ' <span class="wpdapp-username-display">' + display + '</span> ' +
127              '<button type="button" class="wpdapp-change-account">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.change : 'Change') + '</button>'
128            : '';
129        if (inner) {
130            $form.find('.wpdapp-connected-as').html(inner);
131        } else {
132            // If nothing stored, revert to input row
133            const formId = $form.data('form-id') || Date.now();
134            const usernameInputId = 'wpdapp-username-' + formId;
135            $form.find('.wpdapp-connected-as').html('<label class="wpdapp-username-label" for="' + usernameInputId + '">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.enterHiveUsername : 'Enter your Hive username:') + '</label>' +
136                '<input type="text" class="wpdapp-username" id="' + usernameInputId + '" placeholder="' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.hiveUsernamePlaceholder : 'Hive username') + '">');
137            const $chip = $form.find('.wpdapp-status-chip');
138            $chip.removeClass('connected').addClass('not-connected').text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.statusNotConnected : 'Not connected');
139        }
140    });
141
142    // Cancel
143    $(document).on('click', '.wpdapp-cancel-reply', function() {
144        $(this).parent().slideUp();
145    });
146
147    // Submit
148    let isSyncInFlight = false;
149
150    $(document).on('click', '.wpdapp-submit-reply', function() {
151        const $form = $(this).parent();
152        const content = $form.find('textarea').val().trim();
153
154        if (!content) {
155            $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.pleaseEnterReply : 'Please enter a reply.') + '</div>');
156            setTimeout(() => $form.find('.wpdapp-form-error').remove(), 3000);
157            return;
158        }
159        if (content.length < 3) {
160            $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.replyMinLength : 'Reply must be at least 3 characters.') + '</div>');
161            setTimeout(() => $form.find('.wpdapp-form-error').remove(), 3000);
162            return;
163        }
164        if (content.length > 5000) {
165            $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.replyMaxLength : 'Reply must be at most 5000 characters.') + '</div>');
166            setTimeout(() => $form.find('.wpdapp-form-error').remove(), 3000);
167            return;
168        }
169
170        // Determine username: stored or typed
171        let usedUsername = hiveUsername;
172        if (!usedUsername) {
173            const typed = $form.find('.wpdapp-username').val();
174            if (typed && typed.trim().length > 0) {
175                usedUsername = typed.trim();
176            } else {
177                $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.pleaseEnterUsername : 'Please enter your Hive username.') + '</div>');
178                setTimeout(() => $form.find('.wpdapp-form-error').remove(), 3000);
179                return;
180            }
181        }
182
183        if (!isKeychainAvailable()) {
184            alert((wpdapp_frontend.i18n ? wpdapp_frontend.i18n.keychainNotDetected : 'Hive Keychain not detected. Please install the extension.'));
185            return;
186        }
187
188        const $button = $form.prev('.wpdapp-reply-button');
189        const parentAuthor = $button.data('author');
190        const parentPermlink = $button.data('permlink');
191        const permlink = generatePermlink(content);
192
193        const operations = [
194            ['comment', {
195                parent_author: parentAuthor,
196                parent_permlink: parentPermlink,
197                author: usedUsername,
198                permlink: permlink,
199                title: '',
200                body: content,
201                json_metadata: JSON.stringify({ app: 'wp-dapp/0.7.4', format: 'markdown' })
202            }]
203        ];
204
205        $(this).text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.posting : 'Posting...').prop('disabled', true).addClass('loading');
206
207        hive_keychain.requestBroadcast(usedUsername, operations, 'posting', function(response) {
208            $(this).text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.submit : 'Submit').prop('disabled', false).removeClass('loading');
209            if (response.success) {
210                // Persist username after first success
211                hiveUsername = usedUsername;
212                try { localStorage.setItem('wpdapp_hive_username', hiveUsername); } catch(e) {}
213                sessionStorage.setItem('wpdapp_hive_username', hiveUsername);
214                // Update status chip/UI
215                $form.find('.wpdapp-username, .wpdapp-username-label').remove();
216                const $chip = $form.find('.wpdapp-status-chip');
217                $chip.removeClass('not-connected').addClass('connected').text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.statusConnected : 'Connected');
218                if ($form.find('.wpdapp-connected-as').length === 0) {
219                    $chip.after('<p class="wpdapp-connected-as">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.connectedAs : 'Connected as:') + ' ' + hiveUsername + '</p>');
220                } else {
221                    $form.find('.wpdapp-connected-as').text((wpdapp_frontend.i18n ? wpdapp_frontend.i18n.connectedAs : 'Connected as:') + ' ' + hiveUsername);
222                }
223
224                $form.append('<div class="wpdapp-form-success" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.postedSyncing : 'Reply posted successfully! Syncing...') + '</div>');
225                if (isSyncInFlight) return;
226                isSyncInFlight = true;
227                $.ajax({
228                    url: wpdapp_frontend.ajax_url,
229                    type: 'POST',
230                    data: { action: 'wpdapp_sync_comments', nonce: wpdapp_frontend.nonce, post_id: wpdapp_frontend.post_id },
231                    success: function(syncResponse) {
232                        if (syncResponse.success) {
233                            $.ajax({
234                                url: wpdapp_frontend.ajax_url,
235                                type: 'POST',
236                                data: { action: 'wpdapp_render_hive_c
236omments', nonce: wpdapp_frontend.nonce, post_id: wpdapp_frontend.post_id },
237                                success: function(renderResponse) {
238                                    if (renderResponse.success && renderResponse.data && renderResponse.data.html) {
239                                        var $footer = $('.wpdapp-hive-comments-footer').first();
240                                        if ($footer.length) { $footer.remove(); }
241                                        $('.wpdapp-hive-comments').first().replaceWith(renderResponse.data.html);
242                                        $form.find('.wpdapp-form-success').text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.replyPostedSynced : 'Reply posted and synced!');
243                                    } else {
244                                        $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.syncedRefreshFailed : 'Synced, but failed to refresh comments.') + '</div>');
245                                    }
246                                },
247                                error: function() {
248                                    $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.syncedRefreshError : 'Synced, but refresh failed.') + '</div>');
249                                }
250                            });
251                        } else {
252                            $form.append('<div class="wpdapp-form-error" role="status">' + (wpdapp_frontend.i18n ? wpdapp_frontend.i18n.syncFailedPrefix : 'Posted to Hive, but sync failed:') + ' ' + (syncResponse.data || 'Unknown error') + '</div>');
253                        }
254                    },
255                    complete: function() {
256                        isSyncInFlight = false;
257                        setTimeout(() => $form.find('.wpdapp-form-success, .wpdapp-form-error').remove(), 5000);
258                        $form.slideUp();
259                        $form.find('textarea').val('');
260                    }
261                });
262            } else {
263                $form.append('<div class="wpdapp-form-error">Error: ' + response.message + '</div>');
264                setTimeout(() => $form.find('.wpdapp-form-error').remove(), 5000);
265            }
266        }.bind(this));
267    });
268
269    // Handle sync button
270    $(document).on('click', '.wpdapp-sync-button', function(e) {
271        e.preventDefault();
272        const $button = $(this);
273        if (isSyncInFlight) return;
274        isSyncInFlight = true;
275        const isForce = $button.data('force') ? 1 : 0;
276        $button.text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.syncing : (isForce ? 'Importing...' : 'Syncing...')).prop('disabled', true).addClass('loading');
277        $.ajax({
278            url: wpdapp_frontend.ajax_url,
279            type: 'POST',
280            data: {
281                action: 'wpdapp_sync_comments',
282                nonce: wpdapp_frontend.nonce,
283                post_id: wpdapp_frontend.post_id,
284                force: isForce
285            },
286            success: function(syncResponse) {
287                if (syncResponse.success) {
288                    // Fetch fresh rendered HTML and replace the block
289                    $.ajax({
290                        url: wpdapp_frontend.ajax_url,
291                        type: 'POST',
292                        data: {
293                            action: 'wpdapp_render_hive_comments',
294                            nonce: wpdapp_frontend.nonce,
295                            post_id: wpdapp_frontend.post_id
296                        },
297                        success: function(renderResponse) {
298                            if (renderResponse.success && renderResponse.data && renderResponse.data.html) {
299                                var $footer = $('.wpdapp-hive-comments-footer').first();
300                                if ($footer.length) {
301                                    $footer.remove();
302                                }
303                                $('.wpdapp-hive-comments').first().replaceWith(renderResponse.data.html);
304                                // Re-inject inline reply buttons after DOM refresh
305                                addInlineReplyButtons();
306                            }
307                        }
308                    });
309                }
310            },
311            complete: function() {
312                isSyncInFlight = false;
313                $button.text(wpdapp_frontend.i18n ? wpdapp_frontend.i18n.syncHiveComments : 'Sync (copy) Hive replies into WP comments').prop('disabled', false).removeClass('loading');
314            }
315        });
316    });
317});

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.