Go Back   vb.org Archive > vBulletin 4 Discussion > vB4 Programming Discussions
FAQ Community Calendar Today's Posts Search

Reply
 
Thread Tools Display Modes
  #1  
Old 06-08-2014, 06:21 PM
MarkFL's Avatar
MarkFL MarkFL is offline
 
Join Date: Feb 2014
Location: St. Augustine, FL
Posts: 3,853
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default Appending data to a post via javascript

Hello all,

I help administrate a math forum running vBulletin 4.2.1. I have recently added an element to the editpost, newreply and newthread templates that introduces a live preview of LaTeX to aid in debugging code more efficiently than using the "Preview Post" function repeatedly.

Within this element, I have an input button that, using the onclick event, will copy the value of an internal textarea element to the post body using the javascript code:

Code:
document.getElementsByClassName('cke_source')[0].value += document.getElementById('MathInput').value
This works fine unless the user has opted for the WYSIWYG editor, in which case the DOM is constructed differently.

My question: is there a way to append data to the post message that will work regardless of the editor chosen by the user? I have tried manipulating {vb:raw post.message} to no avail.

I appreciate any insights into how to get this to work.

Best Regards,

Mark.
Reply With Quote
Благодарность от:
mathforum
  #2  
Old 06-27-2014, 04:06 AM
MarkFL's Avatar
MarkFL MarkFL is offline
 
Join Date: Feb 2014
Location: St. Augustine, FL
Posts: 3,853
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

I figured out how to accomplish inserting data into a post message regardless of editor mode (that works with Firefox 29 and Chrome 35), and thought it would be good etiquette to share my findings here.

I have a textarea element with id="MathInput" whose contents I wish to insert into the post message at the current cursor location within the post message when a "Copy to Post" button is clicked. I want the cursor to be located at the end of the inserted data after the operation. This is the function that does this:

Code:
function copyMathToPost()
{
    var content = document.getElementById('MathInput').value, el = document.getElementsByClassName('cke_source')[0];
    if (el)
    {
        var pos = getCaretPosition(el);
        el.value = el.value.substr(0, pos) + content + el.value.substr(pos);
        setCaretPosition(el,pos + content.length);
        el.focus();
    }
    else
    {
        var iFrame = document.getElementsByTagName('iframe')[0];
        insertHtmlAtCursor(iFrame,content);
        moveCaret(iFrame, -1);
        moveCaret(iFrame, 1);
    }
}
Here are the supporting functions:

Code:
function getCaretPosition(el)
{ 
    if (el.selectionStart)
    { 
        return el.selectionStart; 
    }
    else if (document.selection)
    {
        el.focus(); 
        var r = document.selection.createRange(); 
        if (r == null)
        { 
            return 0; 
        } 
        var re = el.createTextRange(), rc = re.duplicate(); 
        re.moveToBookmark(r.getBookmark()); 
        rc.setEndPoint('EndToStart', re); 
        return rc.text.length; 
    }  
    return 0; 
}

function setCaretPosition(ctrl,pos)
{
    if(ctrl.setSelectionRange)
    {
        ctrl.focus();
        ctrl.setSelectionRange(pos,pos);
    }
    else if(ctrl.createTextRange)
    {
        var range = ctrl.createTextRange();
        range.collapse(true);
        range.moveEnd('character',pos);
        range.moveStart('character', pos);
        range.select();
    }
}

function insertHtmlAtCursor(iFrame,html)
{
    var sel, range, node;
    html = html.replace(/\r\n?|\n/g, '<br>');
    if (iFrame.contentWindow.getSelection && iFrame.contentWindow.getSelection().getRangeAt)
    {
        sel = iFrame.contentWindow.getSelection();
        try{range = sel.getRangeAt(0);}
        catch (e){alert("This function is not supported by your browser. Please switch editor to Source Mode.");}
        node = range.createContextualFragment(html);
        range.insertNode(node);
        range = range.cloneRange();
        range.collapse();
        sel.removeAllRanges();
        sel.addRange(range);
    }
    else if (iFrame.contentWindow.selection && iFrame.contentWindow.selection.createRange)
    {
        iFrame.contentWindow.selection.createRange().pasteHTML(html);
    }
    else
    {
        alert("This function is not supported by your browser. Please switch editor to Source Mode.");
    }
    iFrame.focus();
}

function moveCaret(win, charCount)
{
    var sel, range;
    if (win.contentWindow.getSelection)
    {
        sel = win.contentWindow.getSelection();
        if (sel.rangeCount > 0)
        {
            var textNode = sel.focusNode;
            var newOffset = sel.focusOffset + charCount;
            sel.collapse(textNode, newOffset);
        }
    }
    else if (sel = win.contentDocument.selection)
    {
        if (sel.type != "Control")
        {
            range = sel.createRange();
            range.move("character", charCount);
            range.select();
        }
    }
}
Reply With Quote
Благодарность от:
tbworld
  #3  
Old 06-27-2014, 07:59 AM
tbworld tbworld is offline
 
Join Date: Oct 2008
Posts: 2,126
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Nice work, as soon as I have time I am going to check this out in detail. Thank you so much for sharing.

I have been working on a pretty easy model by using the existing vb javascript files "vbulletin_quick_reply.js", "vbulletin_quick_edit.js", ... anyway, you already know the problem with that method -- so many different editor modes to modify. After staring at the code for awhile, I too was thinking that I should just position the data via the DOM and be done with it. Since essentially that is all that is being done in the vb JavaScript files.

Sorry, I missed your first (previous) post somehow. I must have been traveling for work or I would have answered, but it looks like you were a bit ahead of my work. I just finished "quick_reply" and "quick_editor" two days ago and still needed to verify caret positioning among the browsers.

Good work! -- I am impressed.
Reply With Quote
Благодарность от:
MarkFL
  #4  
Old 06-27-2014, 02:15 PM
MarkFL's Avatar
MarkFL MarkFL is offline
 
Join Date: Feb 2014
Location: St. Augustine, FL
Posts: 3,853
Благодарил(а): 0 раз(а)
Поблагодарили: 0 раз(а) в 0 сообщениях
Default

Because of an issue reported to me by one of my fellow administrators, who uses a different OS (I use Windows 7 and he uses Xubuntu and we both use Firefox), I have moved the focus method to the end of the moveCaret function, and this alleviates the need to make two calls to the moveCaret function (which I used previously so that Chrome did not lose the cursor).

So, the updated functions are:

Code:
function copyMathToPost()
{
    var content = document.getElementById('MathInput').value, el = document.getElementsByClassName('cke_source')[0];
    if (el)
    {
        var pos = getCaretPosition(el);
        el.value = el.value.substr(0, pos) + content + el.value.substr(pos);
        setCaretPosition(el,pos + content.length);
        el.focus();
    }
    else
    {
        var iFrame = document.getElementsByTagName('iframe')[0];
        insertHtmlAtCursor(iFrame,content);
        moveCaret(iFrame, 0);
    }
}

function insertHtmlAtCursor(iFrame,html)
{
    var sel, range, node;
    html = html.replace(/\r\n?|\n/g, '<br>');
    if (iFrame.contentWindow.getSelection && iFrame.contentWindow.getSelection().getRangeAt)
    {
        sel = iFrame.contentWindow.getSelection();
        try{range = sel.getRangeAt(0);}
        catch (e){alert("This function is not supported by your browser. Please switch editor to Source Mode.");}
        node = range.createContextualFragment(html);
        range.insertNode(node);
        range = range.cloneRange();
        range.collapse();
        sel.removeAllRanges();
        sel.addRange(range);
    }
    else if (iFrame.contentWindow.selection && iFrame.contentWindow.selection.createRange)
    {
        iFrame.contentWindow.selection.createRange().pasteHTML(html);
    }
    else
    {
        alert("This function is not supported by your browser. Please switch editor to Source Mode.");
    }
}

function moveCaret(win, charCount)
{
    var sel, range;
    if (win.contentWindow.getSelection)
    {
        sel = win.contentWindow.getSelection();
        if (sel.rangeCount > 0)
        {
            var textNode = sel.focusNode;
            var newOffset = sel.focusOffset + charCount;
            sel.collapse(textNode, newOffset);
        }
    }
    else if (sel = win.contentDocument.selection)
    {
        if (sel.type != "Control")
        {
            range = sel.createRange();
            range.move("character", charCount);
            range.select();
        }
    }
    win.focus();
}
Reply With Quote
Благодарность от:
tbworld
Reply


Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump


All times are GMT. The time now is 07:38 PM.


Powered by vBulletin® Version 3.8.12 by vBS
Copyright ©2000 - 2025, vBulletin Solutions Inc.
X vBulletin 3.8.12 by vBS Debug Information
  • Page Generation 0.03913 seconds
  • Memory Usage 2,217KB
  • Queries Executed 13 (?)
More Information
Template Usage:
  • (1)SHOWTHREAD
  • (1)ad_footer_end
  • (1)ad_footer_start
  • (1)ad_header_end
  • (1)ad_header_logo
  • (1)ad_navbar_below
  • (1)ad_showthread_beforeqr
  • (1)ad_showthread_firstpost
  • (1)ad_showthread_firstpost_sig
  • (1)ad_showthread_firstpost_start
  • (4)bbcode_code
  • (1)footer
  • (1)forumjump
  • (1)forumrules
  • (1)gobutton
  • (1)header
  • (1)headinclude
  • (1)navbar
  • (3)navbar_link
  • (120)option
  • (4)post_thanks_box
  • (4)post_thanks_box_bit
  • (4)post_thanks_button
  • (1)post_thanks_javascript
  • (1)post_thanks_navbar_search
  • (4)post_thanks_postbit
  • (4)post_thanks_postbit_info
  • (4)postbit
  • (4)postbit_onlinestatus
  • (4)postbit_wrapper
  • (1)spacer_close
  • (1)spacer_open
  • (1)tagbit_wrapper 

Phrase Groups Available:
  • global
  • inlinemod
  • postbit
  • posting
  • reputationlevel
  • showthread
Included Files:
  • ./showthread.php
  • ./global.php
  • ./includes/init.php
  • ./includes/class_core.php
  • ./includes/config.php
  • ./includes/functions.php
  • ./includes/class_hook.php
  • ./includes/modsystem_functions.php
  • ./includes/functions_bigthree.php
  • ./includes/class_postbit.php
  • ./includes/class_bbcode.php
  • ./includes/functions_reputation.php
  • ./includes/functions_post_thanks.php 

Hooks Called:
  • init_startup
  • init_startup_session_setup_start
  • init_startup_session_setup_complete
  • cache_permissions
  • fetch_postinfo_query
  • fetch_postinfo
  • fetch_threadinfo_query
  • fetch_threadinfo
  • fetch_foruminfo
  • style_fetch
  • cache_templates
  • global_start
  • parse_templates
  • global_setup_complete
  • showthread_start
  • showthread_getinfo
  • forumjump
  • showthread_post_start
  • showthread_query_postids
  • showthread_query
  • bbcode_fetch_tags
  • bbcode_create
  • showthread_postbit_create
  • postbit_factory
  • postbit_display_start
  • post_thanks_function_post_thanks_off_start
  • post_thanks_function_post_thanks_off_end
  • post_thanks_function_fetch_thanks_start
  • fetch_musername
  • post_thanks_function_fetch_thanks_end
  • post_thanks_function_thanked_already_start
  • post_thanks_function_thanked_already_end
  • post_thanks_function_fetch_thanks_bit_start
  • post_thanks_function_show_thanks_date_start
  • post_thanks_function_show_thanks_date_end
  • post_thanks_function_fetch_thanks_bit_end
  • post_thanks_function_fetch_post_thanks_template_start
  • post_thanks_function_fetch_post_thanks_template_end
  • postbit_imicons
  • bbcode_parse_start
  • bbcode_parse_complete_precache
  • bbcode_parse_complete
  • postbit_display_complete
  • post_thanks_function_can_thank_this_post_start
  • tag_fetchbit_complete
  • forumrules
  • navbits
  • navbits_complete
  • showthread_complete