WordPress.org

Make WordPress Core

Ticket #31590: 31590.diff

File 31590.diff, 12.4 KB (added by peterwilsoncc, 3 years ago)
  • src/wp-includes/comment-template.php

    diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php
    index 0f8f7a39c8..3b7a46c8cb 100644
    a b function get_comment_reply_link( $args = array(), $comment = null, $post = null 
    16671667                        $args['login_text']
    16681668                );
    16691669        } else {
    1670                 $onclick = sprintf(
    1671                         'return addComment.moveForm( "%1$s-%2$s", "%2$s", "%3$s", "%4$s" )',
    1672                         $args['add_below'], $comment->comment_ID, $args['respond_id'], $post->ID
     1670                $data_attributes = array(
     1671                        'commentid'        => $comment->comment_ID,
     1672                        'postid'           => $post->ID,
     1673                        'belowelement'     => $args['add_below'] . '-' . $comment->comment_ID,
     1674                        'respondelement'   => $args['respond_id'],
    16731675                );
    16741676
     1677                $data_attribute_string = '';
     1678
     1679                foreach ( $data_attributes as $name => $value ) {
     1680                        $data_attribute_string .= " data-${name}=\"" . esc_attr( $value ) . "\"";
     1681                }
     1682
     1683                $data_attribute_string = trim( $data_attribute_string );
     1684
    16751685                $link = sprintf(
    1676                         "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s' aria-label='%s'>%s</a>",
    1677                         esc_url( add_query_arg( 'replytocom', $comment->comment_ID, get_permalink( $post->ID ) ) ) . '#' . $args['respond_id'],
    1678                         $onclick,
     1686                        "<a rel='nofollow' class='comment-reply-link' href='%s' %s aria-label='%s'>%s</a>",
     1687                        esc_url( add_query_arg( 'replytocom', $comment->comment_ID ) ) . "#" . $args['respond_id'],
     1688                        $data_attribute_string,
    16791689                        esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
    16801690                        $args['reply_text']
    16811691                );
  • src/wp-includes/js/comment-reply.js

    diff --git a/src/wp-includes/js/comment-reply.js b/src/wp-includes/js/comment-reply.js
    index 3ddf7744ce..90cd0fa64d 100644
    a b  
    55 *
    66 * @type {Object}
    77 */
    8 var addComment = {
     8var addComment;
     9addComment = ( function( window ) {
     10        // Avoid scope lookups on commonly used variables.
     11        var document = window.document;
     12
     13        // Settings.
     14        var config = {
     15                commentReplyClass : 'comment-reply-link',
     16                cancelReplyId     : 'cancel-comment-reply-link',
     17                commentFieldId    : 'comment',
     18                temporaryFormId   : 'wp-temp-form-div',
     19                parentIdFieldId   : 'comment_parent',
     20                postIdFieldId     : 'comment_post_ID'
     21        };
     22
     23        // Check browser cuts the mustard.
     24        var cutsTheMustard = 'querySelector' in document && 'addEventListener' in window;
     25
     26        /*
     27         * Check browser supports dataset.
     28         * !! sets the variable to true if the property exists.
     29         */
     30        var supportsDataset = !! document.body.dataset;
     31
     32        // For holding the cancel element.
     33        var cancelElement;
     34
     35        // For holding the comment field element.
     36        var commentFieldElement;
     37
     38        // The respond element.
     39        var respondElement;
     40
     41        // Initialise the events.
     42        init();
     43
    944        /**
    10          * @summary Retrieves the elements corresponding to the given IDs.
     45         * Add events to links classed .comment-reply-link.
     46         *
     47         * Searches the context for reply links and adds the JavaScript events
     48         * required to move the comment form. To allow for lazy loading of
     49         * comments this method is exposed as window.commentReply.init().
    1150         *
    12          * @since 2.7.0
     51         * @ticket 31590
    1352         *
    14          * @param {string} commId The comment ID.
    15          * @param {string} parentId The parent ID.
    16          * @param {string} respondId The respond ID.
    17          * @param {string} postId The post ID.
    18          * @returns {boolean} Always returns false.
     53         * @param {HTMLElement} context The parent DOM element to search for links.
    1954         */
    20         moveForm: function( commId, parentId, respondId, postId ) {
    21                 var div, element, style, cssHidden,
    22                         t           = this,
    23                         comm        = t.I( commId ),
    24                         respond     = t.I( respondId ),
    25                         cancel      = t.I( 'cancel-comment-reply-link' ),
    26                         parent      = t.I( 'comment_parent' ),
    27                         post        = t.I( 'comment_post_ID' ),
    28                         commentForm = respond.getElementsByTagName( 'form' )[0];
    29 
    30                 if ( ! comm || ! respond || ! cancel || ! parent || ! commentForm ) {
     55        function init( context ) {
     56                if ( true !== cutsTheMustard ) {
     57                        return;
     58                }
     59
     60                // Get required elements.
     61                cancelElement = getElementById( config.cancelReplyId );
     62                commentFieldElement = getElementById( config.commentFieldId );
     63
     64                // No cancel element, no replies.
     65                if ( ! cancelElement ) {
    3166                        return;
    3267                }
    3368
    34                 t.respondId = respondId;
    35                 postId = postId || false;
     69                cancelElement.addEventListener( 'touchstart', cancelEvent );
     70                cancelElement.addEventListener( 'click',      cancelEvent );
     71
     72                var links = replyLinks( context );
     73                var element;
     74
     75                for ( var i=0, l=links.length; i < l; i++ ) {
     76                        element = links[i];
     77
     78                        element.addEventListener( 'touchstart', clickEvent );
     79                        element.addEventListener( 'click',      clickEvent );
     80                }
     81        }
     82
     83
     84        /**
     85         * Return all links classed .comment-reply-link
     86         *
     87         * @ticket 31590
     88         *
     89         * @param {HTMLElement} context The parent DOM element to search for links.
     90         *
     91         * @return {HTMLCollection|NodeList|Array}
     92         */
     93        function replyLinks( context ) {
     94                var selectorClass = config.commentReplyClass;
     95                var allReplyLinks;
     96
     97                // childNodes is a handy check to ensure the context is a HTMLElement.
     98                if ( ! context || ! context.childNodes ) {
     99                        context = document;
     100                }
    36101
    37                 if ( ! t.I( 'wp-temp-form-div' ) ) {
    38                         div = document.createElement( 'div' );
    39                         div.id = 'wp-temp-form-div';
    40                         div.style.display = 'none';
    41                         respond.parentNode.insertBefore( div, respond );
     102                if ( document.getElementsByClassName ) {
     103                        // Fastest.
     104                        allReplyLinks = context.getElementsByClassName( selectorClass );
     105                }
     106                else {
     107                        // Fast.
     108                        allReplyLinks = context.querySelectorAll( '.' + selectorClass );
    42109                }
    43110
    44                 comm.parentNode.insertBefore( respond, comm.nextSibling );
    45                 if ( post && postId ) {
    46                         post.value = postId;
     111                return allReplyLinks;
     112        }
     113
     114
     115        /**
     116         * Cancel event handler.
     117         *
     118         * @ticket 31590
     119         *
     120         * @param {Event} event The calling event.
     121         */
     122        function cancelEvent( event ) {
     123                var cancelLink = this;
     124                var temporaryFormId  = config.temporaryFormId;
     125                var temporaryElement = getElementById( temporaryFormId );
     126
     127                if ( ! temporaryElement || ! respondElement ) {
     128                        // Conditions for cancel link fail.
     129                        return;
    47130                }
    48                 parent.value = parentId;
    49                 cancel.style.display = '';
    50131
    51                 /**
    52                  * @summary Puts back the comment, hides the cancel button and removes the onclick event.
    53                  *
    54                  * @returns {boolean} Always returns false.
     132                getElementById( config.parentIdFieldId ).value = '0';
     133
     134                // Move the respond form back in place of the temporary element.
     135                temporaryElement.parentNode.replaceChild( respondElement ,temporaryElement );
     136                cancelLink.style.display = 'none';
     137                event.preventDefault();
     138        }
     139
     140
     141        /**
     142         * Click event handler.
     143         *
     144         * @ticket 31590
     145         *
     146         * @param {Event} event The calling event.
     147         */
     148        function clickEvent( event ) {
     149                var replyLink = this,
     150                        commId    = getDataAttribute( replyLink, 'belowelement'),
     151                        parentId  = getDataAttribute( replyLink, 'commentid' ),
     152                        respondId = getDataAttribute( replyLink, 'respondelement'),
     153                        postId    = getDataAttribute( replyLink, 'postid'),
     154                        follow;
     155
     156                /*
     157                 * Third party comments systems can hook into this function via the global scope,
     158                 * therefore the click event needs to reference the global scope.
    55159                 */
    56                 cancel.onclick = function() {
    57                         var t       = addComment,
    58                                 temp    = t.I( 'wp-temp-form-div' ),
    59                                 respond = t.I( t.respondId );
    60 
    61                         if ( ! temp || ! respond ) {
    62                                 return;
    63                         }
    64 
    65                         t.I( 'comment_parent' ).value = '0';
    66                         temp.parentNode.insertBefore( respond, temp );
    67                         temp.parentNode.removeChild( temp );
    68                         this.style.display = 'none';
    69                         this.onclick = null;
    70                         return false;
    71                 };
     160                follow = window.addComment.moveForm(commId, parentId, respondId, postId);
     161                if ( false === follow ) {
     162                        event.preventDefault();
     163                }
     164        }
     165
     166        /**
     167         * Backward compatible getter of data-* attribute.
     168         *
     169         * Uses element.dataset if it exists, otherwise uses getAttribute.
     170         *
     171         * @ticket 31590
     172         *
     173         * @param {HTMLElement} Element DOM element with the attribute.
     174         * @param {String}      Attribute the attribute to get.
     175         *
     176         * @return {String}
     177         */
     178        function getDataAttribute( element, attribute ) {
     179                if ( supportsDataset ) {
     180                        return element.dataset[attribute];
     181                }
     182                else {
     183                        return element.getAttribute( 'data-' + attribute );
     184                }
     185        }
     186
     187        /**
     188         * Get element by ID.
     189         *
     190         * Local alias for document.getElementById.
     191         *
     192         * @ticket 31590
     193         *
     194         * @param {HTMLElement} The requested element.
     195         */
     196        function getElementById( elementId ) {
     197                return document.getElementById( elementId );
     198        }
     199
     200
     201        /**
     202         * moveForm
     203         *
     204         * Moves the reply form from it's current position to the reply location.
     205         *
     206         * @ticket 31590
     207         *
     208         * @param {String} addBelowId HTML ID of element the form follows.
     209         * @param {String} commentId  Database ID of comment being replied to.
     210         * @param {String} respondId  HTML ID of 'respond' element.
     211         * @param {String} postId     Database ID of the post.
     212         */
     213
     214        function moveForm( addBelowId, commentId, respondId, postId ) {
     215                // Get elements based on their IDs.
     216                var addBelowElement = getElementById( addBelowId );
     217                respondElement  = getElementById( respondId );
     218
     219                // Get the hidden fields.
     220                var parentIdField   = getElementById( config.parentIdFieldId );
     221                var postIdField     = getElementById( config.postIdFieldId );
     222
     223                if ( ! addBelowElement || ! respondElement || ! parentIdField ) {
     224                        // Missing key elements, fail.
     225                        return;
     226                }
     227
     228                addPlaceHolder( respondElement );
     229
     230                // Set the value of the post.
     231                if ( postId && postIdField ) {
     232                        postIdField.value = postId;
     233                }
     234
     235                parentIdField.value = commentId;
     236
     237                cancelElement.style.display = '';
     238                addBelowElement.parentNode.insertBefore( respondElement, addBelowElement.nextSibling );
    72239
    73240                /*
    74                  * Sets initial focus to the first form focusable element.
    75                  * Uses try/catch just to avoid errors in IE 7- which return visibility
    76                  * 'inherit' when the visibility value is inherited from an ancestor.
     241                 * This is for backward compatibility with third party commenting systems
     242                 * hooking into the event using older techniques.
    77243                 */
     244                cancelElement.onclick = function(){
     245                        return false;
     246                };
     247
     248                // Focus on the comment field.
    78249                try {
    79                         for ( var i = 0; i < commentForm.elements.length; i++ ) {
    80                                 element = commentForm.elements[i];
    81                                 cssHidden = false;
    82 
    83                                 // Modern browsers.
    84                                 if ( 'getComputedStyle' in window ) {
    85                                         style = window.getComputedStyle( element );
    86                                 // IE 8.
    87                                 } else if ( document.documentElement.currentStyle ) {
    88                                         style = element.currentStyle;
    89                                 }
    90 
    91                                 /*
    92                                  * For display none, do the same thing jQuery does. For visibility,
    93                                  * check the element computed style since browsers are already doing
    94                                  * the job for us. In fact, the visibility computed style is the actual
    95                                  * computed value and already takes into account the element ancestors.
    96                                  */
    97                                 if ( ( element.offsetWidth <= 0 && element.offsetHeight <= 0 ) || style.visibility === 'hidden' ) {
    98                                         cssHidden = true;
    99                                 }
    100 
    101                                 // Skip form elements that are hidden or disabled.
    102                                 if ( 'hidden' === element.type || element.disabled || cssHidden ) {
    103                                         continue;
    104                                 }
    105 
    106                                 element.focus();
    107                                 // Stop after the first focusable element.
    108                                 break;
    109                         }
    110 
    111                 } catch( er ) {}
     250                        commentFieldElement.focus();
     251                }
     252                catch(e) {
     253
     254                }
    112255
     256                /*
     257                 * false is returned for backward compatibility with third party commenting systems
     258                 * hooking into this function.
     259                 */
    113260                return false;
    114         },
     261        }
     262
    115263
    116264        /**
    117          * @summary Returns the object corresponding to the given ID.
     265         * Add placeholder element.
     266         *
     267         * Places a place holder element above the #respond element for
     268         * the form to be returned to if needs be.
    118269         *
    119          * @since 2.7.0
     270         * @param {HTMLelement} respondElement the #respond element holding comment form.
    120271         *
    121          * @param {string} id The ID.
    122          * @returns {Element} The element belonging to the ID.
     272         * @ticket 31590
    123273         */
    124         I: function( id ) {
    125                 return document.getElementById( id );
     274        function addPlaceHolder( respondElement ) {
     275                var temporaryFormId  = config.temporaryFormId;
     276                var temporaryElement = getElementById( temporaryFormId );
     277
     278                if ( temporaryElement ) {
     279                        // The element already exists, no need to recreate.
     280                        return;
     281                }
     282
     283                temporaryElement = document.createElement( 'div' );
     284                temporaryElement.id = temporaryFormId;
     285                temporaryElement.style.display = 'none';
     286                respondElement.parentNode.insertBefore( temporaryElement, respondElement );
    126287        }
    127 };
     288
     289
     290        return {
     291                init: init,
     292                moveForm: moveForm
     293        };
     294
     295})( window );