|
Post by xea989 on Oct 23, 2024 19:18:17 GMT -5
(I am still trying to get in contact with David to see if this plugin can be given an open-source license or at least a designated caretaker so modernizations can actually be merged into the plugin itself) (I am still trying to get in contact with David to see if this plugin can be given an open-source license or at least a designated caretaker so modernizations can actually be merged into the plugin itself) Maybe post the full code with the updates because I'm old and tired, but I want to help. LOL
|
|
|
Post by Hungry Hungry Hippo on Oct 23, 2024 19:45:44 GMT -5
Now nothing happens when you select by clicks
|
|
|
Post by xea989 on Oct 23, 2024 19:46:12 GMT -5
Now nothing happens when you select by clicks But it works if you highlight manually.
|
|
|
Post by bigballofyarn on Oct 23, 2024 20:10:16 GMT -5
This is being worked on and investigated. If you see any code in the guest thread, it's fine.
|
|
|
Post by eton on Oct 23, 2024 23:59:45 GMT -5
(I am still trying to get in contact with David to see if this plugin can be given an open-source license or at least a designated caretaker so modernizations can actually be merged into the plugin itself)
|
|
|
Post by eton on Oct 24, 2024 0:33:58 GMT -5
I confirm triple and double not working although working on two other forums...investigating further...
Edit: OK, I still could not determine why the selections on that forum would be so broad (e.g., selection on a textNode has the anchorNode as the textNode (as expected) but the focusNode is for whatever reason trying to go beyond the bounds of the post. On other forums both anchorNode and focusNode would be the same textNode since that is the only node of any relevance. I suspect either the dice or eightball plugins since they both have selection manipulation algorithms and have already ruled out the BBCode Buttons plugin. In any event, changing the lines that check post boundaries from using parents to using closest should address the issue There is also now THREE copies of the <dialog> in the header, I'd suggest it gets properly cleaned out and then put the latest code listed below back in there <dialog class="quick-quote-div" style="margin:0; border: grey solid 1px; border-radius: 5px; opacity: 0.8; padding: 5px; background-color: white;"> <form method="dialog"> <input name="quote" value="Quick Quote" type="submit" class="ui-button quick-quote-button" autofocus > </form> </dialog> <!-- Quick Quotes (UPDATED Oct 24, 2024 @ 1729747068093) --> <script> (() => { var isIE = document.all; var mouseX = 0; var mouseY = 0;
function getMouseXY(e) { if (!e) e = window.event; if (e) { mouseX = isIE ? (e.clientX + document.body.scrollLeft) : e.pageX; mouseY = isIE ? (e.clientY + document.body.scrollTop) : e.pageY; } }
document.addEventListener('mousemove', getMouseXY, true); htm_specials_tags = { "remove": [ '.quote_clear', '.quote_header', '.quote_avatar_container', '.spoiler_header' ], "unwrap": [ '.quote_body' ], "replace":[ ['div.quote','className'], ['div.spoiler[id]', 'data-tag'], ['iframe[src*="youtube.com"]','','video'] ] } function cleanupHTML(htm){ const container = $('<div></div>').html(htm); $('' + htm_specials_tags['remove'], container).remove() $('' + htm_specials_tags['unwrap'], container).each((i,e)=>{$(e).contents().unwrap()}); for(let j =0, tag = htm_specials_tags['replace'][0]; j < htm_specials_tags['replace'].length; tag = htm_specials_tags['replace'][++j]){ $(tag[0],container).each((i,e)=>{ let n = e[tag[1]]? $(`<${e[tag[1]]}>${e.innerHTML}</${e[tag[1]]}>`) : (tag[2]? $(`<${tag[2]}>${e.innerHTML}</${tag[2]}>`):$()); if(n.length){ for(const t of e.attributes)n.attr(t.name,t.value); $(e).replaceWith(n); } }); } return container.html() }
function getSelectionHtml() { var html = ""; if (typeof window.getSelection != "undefined") { var sel = window.getSelection(); if ($(sel.anchorNode).closest('.message').is($(sel.focusNode).closest('.message')) && sel.rangeCount) { if($(sel.anchorNode).closest('.quote').is($(sel.focusNode).closest('.quote'))){ quotequote=$(sel.focusNode).parents('.quote'); }else{ quotequote=null;} var container = document.createElement("div"); for (var i = 0, len = sel.rangeCount; i < len; ++i) { container.appendChild(sel.getRangeAt(i).cloneContents()); } html = container.innerHTML; } } else if (typeof document.selection != "undefined") { if (document.selection.type == "Text") { html = document.selection.createRange().htmlText; } } return cleanupHTML(html); }
var messageIDnum, messageIDsliced, messageAuthor, messageTimestamp, messageNew, quoteText, quotequote;
getSelectionHtml.mouseup = function (event) { var htmlSelection = getSelectionHtml(); getSelectionHtml.mouseup.timeout && clearTimeout(getSelectionHtml.mouseup.timeout) quoteText = htmlSelection.replace(/>/g, "]"); quoteText = quoteText.replace(/</g, "["); if ($('.unblocked .message:hover').length != 0) {
if (htmlSelection != '') { getSelectionHtml.mouseup.timeout = setTimeout(function () { $(".quick-quote-div").css({ position: "absolute", top: mouseY, left: mouseX }); $(".quick-quote-div")[0].showModal(); setTimeout(function () { if ($('.quick-quote-div:hover').length == 0) { $('.quick-quote-div')[0].close() htmlSelection = '' quoteText = '' } }, 2500)
}, 600); if(quotequote){ messageNew = `[quote author="${$(quotequote).attr('author')}" source="${$(quotequote).attr('source')}" timestamp="${$(quotequote).attr('timestamp')}"]${quoteText}[/quote]` }else{ messageIDnum = $('.post:hover').attr('id'); messageIDsliced = messageIDnum.substr(messageIDnum.lastIndexOf("-") + 1); messageAuthor = $('.post:hover .mini-profile').find('.user-link').attr('title') || $('.post:hover .mini-profile').find('[itemtype$="/Person"] span[itemprop="name"]').text(); messageTimestamp = $('.post:hover .info').find('abbr:first').attr('data-timestamp'); messageTimestamp = messageTimestamp.substring(0, messageTimestamp.length - 3); messageNew = '[quote author="' + messageAuthor + '" source="/post/' + messageIDsliced + '/thread" timestamp="' + messageTimestamp + '"]' + quoteText + '[/quote]' }
} } }
$('.quick-quote-button').click(function () { if (quoteText != '') { pb.data('quick_reply') ? $('.quick-reply textarea').replaceSelection(messageNew + "\n")[0].scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth' }) : $('<form></form>', { method: 'POST', action: proboards.route('new_post', { thread_id: pb.item('thread', pb.item('post', +messageIDsliced)['thread_id']).id }) }) .append($('<input>', { name: 'quick_message' }).val(messageNew)) .append($('<input>', { name: 'csrf_token' }).val(proboards.data("csrf_token") || "null")) .appendTo('body').attr('id', 'quick_form'), setTimeout(function () { pb.data('quick_reply') && $('.quick-reply textarea')[0].focus(); $('#quick_form').submit() }, 500); htmlSelection = quoteText = ''; $('.quick-quote-div')[0].close(); } });
$(document).ready(function () {
$(document).bind("mouseup", getSelectionHtml.mouseup); $('.quick-quote-div').on('click', (event) => { event.target.tagName == 'DIALOG' && event.target.close(); })
});
})(); /** UPDATES: - encapsulate to avoid global variables getting overwritten - switched to <dialog> for top-layer treatment - used jQuery.fn.replaceSelection to insert at caret position in quick reply - look for timestamp only in .content > .info - search mini-profile only for author - support quoting guest posts - scroll quick reply into view and set focus on typing area - redirect to full reply if no quick reply is available - ignore selections that are outbounds of the post content - moved button click handler out of selection handler to avoid duplicate or multiple quotes on a single click - properly cite nested quotes and add logic to convert them back to BBCode - delayed button popup to allow for triple-click selections - made BBCode convertor expandable and added spoilers to the list of tags that require special treatment - added youtube to specials converter - switched from parents to closest in boundaries test **/ </script>
|
|
|
Post by eton on Oct 24, 2024 0:47:32 GMT -5
maybe not...
|
|
|
Post by eton on Oct 24, 2024 2:28:25 GMT -5
OK, instead of trying to find the needle in the haystack, I've decided to adjust the selection to fit within the confines of the post if it tries to extend beyond the boundaries of the post. This applies to the tail end of the selection (focusNode). If the start of the selection (anchorNode) begins outside the bounds of the post, then that is a try-again situation. <!-- Quick Quotes (UPDATED Oct 24, 2024 @ 1729754075134) -->
<dialog class="quick-quote-div" style="/*display: none;*/margin:0; border: grey solid 1px; border-radius: 5px; opacity: 0.8; padding: 5px; background-color: white;"> <form method="dialog"> <input name="quote" value="Quick Quote" type="submit" class="ui-button quick-quote-button" autofocus > </form> </dialog>
<script> (() => { var isIE = document.all; var mouseX = 0; var mouseY = 0;
function getMouseXY(e) { if (!e) e = window.event; if (e) { mouseX = isIE ? (e.clientX + document.body.scrollLeft) : e.pageX; mouseY = isIE ? (e.clientY + document.body.scrollTop) : e.pageY; } }
document.addEventListener('mousemove', getMouseXY, false); htm_specials_tags = { "remove": [ '.quote_clear', '.quote_header', '.quote_avatar_container', '.spoiler_header' ], "unwrap": [ '.quote_body' ], "replace":[ ['div.quote','className'], ['div.spoiler[id]', 'data-tag'], ['iframe[src*="youtube.com"]','','video'] ] } function cleanupHTML(htm){ const container = $('<div></div>').html(htm); $('' + htm_specials_tags['remove'], container).remove() $('' + htm_specials_tags['unwrap'], container).each((i,e)=>{$(e).contents().unwrap()}); for(let j =0, tag = htm_specials_tags['replace'][0]; j < htm_specials_tags['replace'].length; tag = htm_specials_tags['replace'][++j]){ $(tag[0],container).each((i,e)=>{ let n = e[tag[1]]? $(`<${e[tag[1]]}>${e.innerHTML}</${e[tag[1]]}>`) : (tag[2]? $(`<${tag[2]}>${e.innerHTML}</${tag[2]}>`):$()); if(n.length){ for(const t of e.attributes)n.attr(t.name,t.value); $(e).replaceWith(n); } }); } return container.html() }
function getSelectionHtml() { var html = ""; if (typeof window.getSelection != "undefined") { var sel = window.getSelection(); if ($(sel.anchorNode).closest('.message').length && sel.rangeCount) { if($(sel.anchorNode).closest('.quote').is($(sel.focusNode).closest('.quote'))){ quotequote=$(sel.focusNode).parents('.quote'); }else{ quotequote=null; if($(sel.focusNode).closest('.message').length == 0){ sel.extend($(sel.anchorNode).closest('.quote')[0],$(sel.anchorNode).closest('.quote').contents().length) } } var container = document.createElement("div"); for (var i = 0, len = sel.rangeCount; i < len; ++i) { container.appendChild(sel.getRangeAt(i).cloneContents()); } html = container.innerHTML; } } else if (typeof document.selection != "undefined") { if (document.selection.type == "Text") { html = document.selection.createRange().htmlText; } } return cleanupHTML(html); }
var messageIDnum, messageIDsliced, messageAuthor, messageTimestamp, messageNew, quoteText, quotequote;
getSelectionHtml.mouseup = function (event) { var htmlSelection = getSelectionHtml(); getSelectionHtml.mouseup.timeout && clearTimeout(getSelectionHtml.mouseup.timeout) quoteText = htmlSelection.replace(/>/g, "]"); quoteText = quoteText.replace(/</g, "["); if ($('.unblocked .message:hover').length != 0) {
if (htmlSelection != '') { getSelectionHtml.mouseup.timeout = setTimeout(function () { $(".quick-quote-div").css({ position: "absolute", top: mouseY, left: mouseX }); $(".quick-quote-div")[0].showModal(); setTimeout(function () { if ($('.quick-quote-div:hover').length == 0) { $('.quick-quote-div')[0].close() htmlSelection = '' quoteText = '' } }, 2500)
}, 600); if(quotequote){ messageNew = `[quote author="${$(quotequote).attr('author')}" source="${$(quotequote).attr('source')}" timestamp="${$(quotequote).attr('timestamp')}"]${quoteText}[/quote]` }else{ messageIDnum = $('.post:hover').attr('id'); messageIDsliced = messageIDnum.substr(messageIDnum.lastIndexOf("-") + 1); messageAuthor = $('.post:hover .mini-profile').find('.user-link').attr('title') || $('.post:hover .mini-profile').find('[itemtype$="/Person"] span[itemprop="name"]').text(); messageTimestamp = $('.post:hover .info').find('abbr:first').attr('data-timestamp'); messageTimestamp = messageTimestamp.substring(0, messageTimestamp.length - 3); messageNew = '[quote author="' + messageAuthor + '" source="/post/' + messageIDsliced + '/thread" timestamp="' + messageTimestamp + '"]' + quoteText + '[/quote]' }
} } }
$('.quick-quote-button').click(function () { if (quoteText != '') { pb.data('quick_reply') ? $('.quick-reply textarea').replaceSelection(messageNew + "\n")[0].scrollIntoView({ block: 'start', inline: 'nearest', behavior: 'smooth' }) : $('<form></form>', { method: 'POST', action: proboards.route('new_post', { thread_id: pb.item('thread', pb.item('post', +messageIDsliced)['thread_id']).id }) }) .append($('<input>', { name: 'quick_message' }).val(messageNew)) .append($('<input>', { name: 'csrf_token' }).val(proboards.data("csrf_token") || "null")) .appendTo('body').attr('id', 'quick_form'), setTimeout(function () { pb.data('quick_reply') && $('.quick-reply textarea')[0].focus(); $('#quick_form').submit() }, 500); htmlSelection = quoteText = ''; $('.quick-quote-div')[0].close(); } });
$(document).ready(function () {
$(document).bind("mouseup", getSelectionHtml.mouseup); $('.quick-quote-div').on('click', (event) => { event.target.tagName == 'DIALOG' && event.target.close(); })
});
})(); /** UPDATES: - encapsulate to avoid global variables getting overwritten - switched to <dialog> for top-layer treatment - used jQuery.fn.replaceSelection to insert at caret position in quick reply - look for timestamp only in .content > .info - search mini-profile only for author - support quoting guest posts - scroll quick reply into view and set focus on typing area - redirect to full reply if no quick reply is available - ignore selections that are outbounds of the post content - moved button click handler out of selection handler to avoid duplicate or multiple quotes on a single click - properly cite nested quotes and add logic to convert them back to BBCode - delayed button popup to allow for triple-click selections - made BBCode convertor expandable and added spoilers to the list of tags that require special treatment - added youtube to specials converter - switched from parents to closest in boundaries test and moved focusNode if necessary **/ </script>
|
|
|
Post by Livesindaw00ds on Oct 24, 2024 4:30:54 GMT -5
This is in alpha testing and might not remain a feature on this forum. It has minor issues in different browsers due to some browsers putting menus over highlighted text, but still works. See if you like it. It lets you quickly quote specific text from people's posts without having to quote the whole thing and then pick it apart in the reply box. This will also save on page views for those who like to quote rather than tag. It only works properly if you highlight by holding down your mouse and scrolling. If you're the type to double/triple click to highlight a sentence, it seems to break the quote. Test by clicking
|
|
|
Post by Livesindaw00ds on Oct 24, 2024 4:37:08 GMT -5
|
|
|
Post by Tampaboy19N on Oct 24, 2024 4:37:49 GMT -5
Broke it.... in Opera I selected your entire reply with my mouse.
|
|
|
Post by tinybones on Oct 24, 2024 4:38:36 GMT -5
Brave. Test. same issue with Christina's post...
|
|
|
Post by zachansonlover on Oct 24, 2024 4:41:49 GMT -5
UR browser. It didn't copy all the text even though the whole sentence was selected before I clicked quote.
|
|
|
Post by Steven on Oct 24, 2024 4:47:58 GMT -5
I clicked and highlighted the whole thing in Chrome. It only brought one word to the quick reply. BUT, no code is showing up now.
|
|
|
Post by Idan Keys on Oct 24, 2024 4:57:29 GMT -5
Testing in Edge. I clicked to select the entire sentence. It brought down one word only.
|
|