Skip to:
Content

bbPress.org

Changeset 6964


Ignore:
Timestamp:
11/19/2019 04:50:41 PM (4 years ago)
Author:
johnjamesjacoby
Message:

Replies: ensure visual editor works correctly with hierarchical replies.

This commit updates reply.js in the default theme to include a bit of element juggling that prevents TinyMCE from freezing up when it is relocated on the page.

Before this commit, clicking "Reply" while having the Visual Editor enabled would cause it to not be able to be typed inside of. Now, when clicking commit, TinyMCE is correctly reinvoked in its new location, and the page will expediently scroll to that new position, fixing a related UX bug where it was possible for the reply form to get lost inside of deep hierarchies.

Props chherbst. Fixes #2646. For 2.7, trunk.

Location:
trunk/src/templates/default
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/templates/default/css/bbpress.css

    r6963 r6964  
    859859}
    860860
     861#bbpress-forums .bbp-replies .bbp-reply-form {
     862    margin: 0 10px 0 10px;
     863}
     864
    861865/* =Edit User
    862866-------------------------------------------------------------- */
  • trunk/src/templates/default/js/reply.js

    r6096 r6964  
     1/* globals tinyMCE */
    12addReply = {
    2     moveForm : function(replyId, parentId, respondId, postId) {
    3         var t = this, div, reply = t.I(replyId), respond = t.I(respondId), cancel = t.I('bbp-cancel-reply-to-link'), parent = t.I('bbp_reply_to'), post = t.I('bbp_topic_id');
    4 
     3
     4    /**
     5     * Move the reply form when "Reply" is clicked.
     6     *
     7     * @since 2.6.2
     8     * @param {string} replyId
     9     * @param {string} parentId
     10     * @param {string} respondId
     11     * @param {string} postId
     12     * @returns {undefined|Boolean}
     13     */
     14    moveForm: function ( replyId, parentId, respondId, postId ) {
     15
     16        /* Get initial elements */
     17        var t       = this,
     18            reply   = t.getElement( replyId ),
     19            respond = t.getElement( respondId ),
     20            cancel  = t.getElement( 'bbp-cancel-reply-to-link' ),
     21            parent  = t.getElement( 'bbp_reply_to' ),
     22            post    = t.getElement( 'bbp_topic_id' );
     23
     24        /* Remove the editor, if its already been moved */
     25        t.removeEditor();
     26
     27        /* Bail to avoid errors */
    528        if ( ! reply || ! respond || ! cancel || ! parent ) {
    629            return;
     
    831
    932        t.respondId = respondId;
    10         postId = postId || false;
    11 
    12         if ( ! t.I('bbp-temp-form-div') ) {
    13             div = document.createElement('div');
    14             div.id = 'bbp-temp-form-div';
     33        postId      = postId || false;
     34
     35        /* Setup a temporary div for relocating back when clicking cancel */
     36        if ( ! t.getElement( 'bbp-temp-form-div' ) ) {
     37            var div = document.createElement( 'div' );
     38
     39            div.id            = 'bbp-temp-form-div';
    1540            div.style.display = 'none';
    16             respond.parentNode.insertBefore(div, respond);
    17         }
    18 
    19         reply.parentNode.appendChild(respond);
     41
     42            respond.parentNode.appendChild( div );
     43        }
     44
     45        /* Relocate the element */
     46        reply.parentNode.appendChild( respond );
     47
    2048        if ( post && postId ) {
    2149            post.value = postId;
    2250        }
    23         parent.value = parentId;
     51
     52        parent.value         = parentId;
    2453        cancel.style.display = '';
    2554
    26         cancel.onclick = function() {
    27             var t = addReply, temp = t.I('bbp-temp-form-div'), respond = t.I(t.respondId);
     55        /* Add the editor where it now belongs */
     56        t.addEditor();
     57
     58        /**
     59         * When cancelling a Reply.
     60         *
     61         * @since 2.6.2
     62         * @returns {void}
     63         */
     64        cancel.onclick = function () {
     65            var t       = addReply,
     66                temp    = t.getElement( 'bbp-temp-form-div' ),
     67                respond = t.getElement( t.respondId );
     68
     69            t.removeEditor();
    2870
    2971            if ( ! temp || ! respond ) {
     
    3173            }
    3274
    33             t.I('bbp_reply_to').value = '0';
    34             temp.parentNode.insertBefore(respond, temp);
    35             temp.parentNode.removeChild(temp);
     75            t.getElement( 'bbp_reply_to' ).value = '0';
     76
     77            temp.parentNode.insertBefore( respond, temp );
     78            temp.parentNode.removeChild( temp );
     79
    3680            this.style.display = 'none';
    37             this.onclick = null;
    38             return false;
     81            this.onclick       = null;
     82
     83            t.addEditor();
    3984        };
    4085
    41         try { t.I('bbp_reply_content').focus(); }
    42         catch(e) {}
     86        t.scrollToForm(t);
    4387
    4488        return false;
    4589    },
    4690
    47     I : function(e) {
     91    /**
     92     * Scrolls to the top of the page.
     93     *
     94     * @since 2.6.2
     95     * @param {HTMLElement} t The HTML element.
     96     * @return {void}
     97     */
     98    scrollToForm: function(t) {
     99
     100        /* Get initial variables to start computing boundaries */
     101        var form        = t.getElement( 'new-post' ),
     102            elemRect    = form.getBoundingClientRect(),
     103            position    = (window.pageYOffset || document.scrollTop)  - (document.clientTop || 0),
     104            destination = ( position + elemRect.top ),
     105            negative    = ( destination < position ),
     106            adminbar    = t.getElement( 'wpadminbar'),
     107            offset      = 0;
     108
     109        /* Offset by the adminbar */
     110        if ( typeof ( adminbar ) !== 'undefined' ) {
     111            offset = adminbar.scrollHeight;
     112        }
     113
     114        /* Compute the difference, depending on direction */
     115        distance = ( true === negative )
     116            ? ( position - destination )
     117            : ( destination - position );
     118
     119        /* Do some math to compute the animation steps */
     120        var vast       = ( distance > 800 ),
     121            speed_step = vast ? 30 : 20,
     122            speed      = Math.min( 12, Math.round( distance / speed_step ) ),
     123            step       = Math.round( distance / speed_step ),
     124            steps      = [],
     125            timer      = 0;
     126
     127        /* Scroll up */
     128        if ( true === negative ) {
     129            while ( position > destination ) {
     130                position -= step;
     131
     132                if ( position < destination ) {
     133                    position = destination;
     134                }
     135
     136                steps.push( position - offset );
     137
     138                setTimeout( function() {
     139                    window.scrollTo( 0, steps.shift() );
     140                }, timer * speed );
     141
     142                timer++;
     143            }
     144
     145        /* Scroll down */
     146        } else {
     147            while ( position < destination ) {
     148                position += step;
     149
     150                if ( position > destination ) {
     151                    position = destination;
     152                }
     153
     154                steps.push( position - offset );
     155
     156                setTimeout( function() {
     157                    window.scrollTo( 0, steps.shift() );
     158                }, timer * speed );
     159
     160                timer++;
     161            }
     162        }
     163    },
     164
     165    /**
     166     * Get an element by ID
     167     *
     168     * @since 2.6.2
     169     * @param {string} e
     170     * @returns {HTMLElement} Element
     171     */
     172    getElement: function (e) {
    48173        return document.getElementById(e);
     174    },
     175
     176    /**
     177     * Remove the Editor
     178     *
     179     * @since 2.6.2
     180     * @returns {void}
     181     */
     182    removeEditor: function () {
     183
     184        /* Bail to avoid error */
     185        if ( typeof (tinyMCE) === 'undefined' ) {
     186            return;
     187        }
     188
     189        var tmce = tinyMCE.get( 'bbp_reply_content' );
     190
     191        if ( tmce && ! tmce.isHidden() ) {
     192            this.mode = 'tmce';
     193            tmce.remove();
     194
     195        } else {
     196            this.mode = 'html';
     197        }
     198    },
     199
     200    /**
     201     * Add the Editor
     202     *
     203     * @since 2.6.2
     204     * @returns {void}
     205     */
     206    addEditor: function () {
     207
     208        /* Bail to avoid error */
     209        if ( typeof (tinyMCE) === 'undefined' ) {
     210            return;
     211        }
     212
     213        if ( 'tmce' === this.mode ) {
     214            switchEditors.go( 'bbp_reply_content', 'tmce' );
     215
     216        } else if ( 'html' === this.mode ) {
     217            switchEditors.go( 'bbp_reply_content', 'html' );
     218        }
    49219    }
    50220};
Note: See TracChangeset for help on using the changeset viewer.