Make WordPress Core

Ticket #31590: 31590.2.diff

File 31590.2.diff, 10.3 KB (added by peterwilsoncc, 9 years ago)

unobtrusive comment-reply.js

  • src/wp-includes/comment-template.php

    diff --git a/src/wp-includes/comment-template.php b/src/wp-includes/comment-template.php
    index 7863577..e92b200 100644
    a b function get_comment_reply_link( $args = array(), $comment = null, $post = null 
    14331433                        $args['login_text']
    14341434                );
    14351435        } else {
    1436                 $onclick = sprintf( 'return addComment.moveForm( "%1$s-%2$s", "%2$s", "%3$s", "%4$s" )',
    1437                         $args['add_below'], $comment->comment_ID, $args['respond_id'], $post->ID
     1436                $data_attributes = array(
     1437                        'commentid'        => $comment->comment_ID,
     1438                        'postid'           => $post->ID,
     1439                        'belowelement' => $args['add_below'] . '-' . $comment->comment_ID,
     1440                        'respondelement'   => $args['respond_id'],
    14381441                );
    14391442
    1440                 $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' onclick='%s' aria-label='%s'>%s</a>",
    1441                         esc_url( add_query_arg( 'replytocom', $comment->comment_ID, get_permalink( $post->ID ) ) ) . "#" . $args['respond_id'],
    1442                         $onclick,
     1443                $data_attribute_string = '';
     1444
     1445                foreach ( $data_attributes as $name => $value ) {
     1446                        $data_attribute_string .= " data-${name}=\"" . esc_attr( $value ) . "\"";
     1447                }
     1448
     1449                $data_attribute_string = trim( $data_attribute_string );
     1450
     1451                $link = sprintf( "<a rel='nofollow' class='comment-reply-link' href='%s' %s aria-label='%s'>%s</a>",
     1452                        esc_url( add_query_arg( 'replytocom', $comment->comment_ID ) ) . "#" . $args['respond_id'],
     1453                        $data_attribute_string,
    14431454                        esc_attr( sprintf( $args['reply_to_text'], $comment->comment_author ) ),
    14441455                        $args['reply_text']
    14451456                );
  • 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 2f2e3b3..c478b61 100644
    a b  
    1 var addComment = {
    2         moveForm : function(commId, parentId, respondId, postId) {
    3                 var t = this, div, comm = t.I(commId), respond = t.I(respondId), cancel = t.I('cancel-comment-reply-link'), parent = t.I('comment_parent'), post = t.I('comment_post_ID');
     1var addComment;
     2addComment = (function( window, undefined ){
     3        // Avoid scope lookups on commonly used variables
     4        var document = window.document;
    45
    5                 if ( ! comm || ! respond || ! cancel || ! parent )
     6        // settings
     7        var config = {
     8                commentReplyClass : 'comment-reply-link',
     9                cancelReplyId     : 'cancel-comment-reply-link',
     10                commentFieldId    : 'comment',
     11                temporaryFormId   : 'wp-temp-form-div',
     12                parentIdFieldId   : 'comment_parent',
     13                postIdFieldId     : 'comment_post_ID'
     14        };
     15
     16        // check browser cuts the mustard
     17        var cutsTheMustard = 'querySelector' in document && 'addEventListener' in window;
     18
     19        // check browser supports dataset
     20        // !! sets the variable to truthy if the property exists.
     21        var supportsDataset = !!document.body.dataset;
     22
     23        // for holding the cancel element
     24        var cancelElement;
     25
     26        // for holding the comment field element
     27        var commentFieldElement;
     28
     29        // the respond element
     30        var respondElement;
     31
     32        // initialise the events
     33        init();
     34
     35        /**
     36         * Add events to links classed .comment-reply-link.
     37         *
     38         * Searches the context for reply links and adds the JavaScript events
     39         * required to move the comment form. To allow for lazy loading of
     40         * comments this method is exposed as PWCC.commentReply.init()
     41         *
     42         * @ticket 31590
     43         *
     44         * @param {HTMLElement} context The parent DOM element to search for links.
     45         */
     46        function init( context ) {
     47                if ( true !== cutsTheMustard ) {
    648                        return;
     49                }
     50
     51                // get required elements
     52                cancelElement = getElementById( config.cancelReplyId );
     53                commentFieldElement = getElementById( config.commentFieldId );
     54
     55                // no cancel element, no replies
     56                if ( ! cancelElement ) {
     57                        return;
     58                }
     59
     60                cancelElement.addEventListener( 'touchstart', cancelEvent );
     61                cancelElement.addEventListener( 'click',      cancelEvent );
     62
     63                var links = replyLinks( context );
     64                var i,l;
     65                var element;
     66
     67                for ( i=0, l=links.length; i<l; i++ ) {
     68                        element = links[i];
     69
     70                        element.addEventListener( 'touchstart', clickEvent );
     71                        element.addEventListener( 'click',      clickEvent );
     72                }
     73        }
     74
     75
     76        /**
     77         * Return all links classed .comment-reply-link
     78         *
     79         * @ticket 31590
     80         *
     81         * @param {HTMLElement} context The parent DOM element to search for links.
     82         *
     83         * @return {HTMLCollection|NodeList|Array}
     84         */
     85        function replyLinks( context ) {
     86                var selectorClass = config.commentReplyClass;
     87                var allReplyLinks;
     88
     89                // childNodes is a handy check to ensure the context is a HTMLElement
     90                if ( !context || !context.childNodes ) {
     91                        context = document;
     92                }
     93
     94                if ( document.getElementsByClassName ) {
     95                        // fastest
     96                        allReplyLinks = context.getElementsByClassName( selectorClass );
     97                }
     98                else {
     99                        // fast
     100                        allReplyLinks = context.querySelectorAll( '.' + selectorClass );
     101                }
     102
     103                return allReplyLinks;
     104        }
     105
     106
     107        /**
     108         * Cance event handler
     109         *
     110         * @ticket 31590
     111         *
     112         * @param {Event} event The calling event
     113         */
     114        function cancelEvent( event ) {
     115                var cancelLink = this;
     116                var temporaryFormId  = config.temporaryFormId;
     117                var temporaryElement = getElementById( temporaryFormId );
     118
     119                if ( ! temporaryElement || ! respondElement ) {
     120                        // conditions for cancel link fail
     121                        return;
     122                }
     123
     124                getElementById( config.parentIdFieldId ).value = '0';
    7125
    8                 t.respondId = respondId;
    9                 postId = postId || false;
     126                // move the respond form back in place of the tempory element
     127                temporaryElement.parentNode.replaceChild( respondElement ,temporaryElement );
     128                cancelLink.style.display = 'none';
     129                event.preventDefault();
     130        }
     131
     132
     133        /**
     134         * Click event handler
     135         *
     136         * @ticket 31590
     137         *
     138         * @param {Event} event The calling event
     139         */
     140        function clickEvent( event ) {
     141                var replyLink = this,
     142                        commId    = getDataAttribute( replyLink, 'belowelement'),
     143                        parentId  = getDataAttribute( replyLink, 'commentid' ),
     144                        respondId = getDataAttribute( replyLink, 'respondelement'),
     145                        postId    = getDataAttribute( replyLink, 'postid'),
     146                        follow    = true;
    10147
    11                 if ( ! t.I('wp-temp-form-div') ) {
    12                         div = document.createElement('div');
    13                         div.id = 'wp-temp-form-div';
    14                         div.style.display = 'none';
    15                         respond.parentNode.insertBefore(div, respond);
     148                // third party comments systems can hook into this function via the gloabl scope.
     149                // therefore the click event needs to reference the gloabl scope.
     150                follow = window.addComment.moveForm(commId, parentId, respondId, postId);
     151                if ( false === follow ) {
     152                        event.preventDefault();
    16153                }
     154        }
    17155
    18                 comm.parentNode.insertBefore(respond, comm.nextSibling);
    19                 if ( post && postId )
    20                         post.value = postId;
    21                 parent.value = parentId;
    22                 cancel.style.display = '';
    23156
    24                 cancel.onclick = function() {
    25                         var t = addComment, temp = t.I('wp-temp-form-div'), respond = t.I(t.respondId);
     157        /**
     158         * Backward compatible getter of data-* attribute
     159         *
     160         * Uses element.dataset if it exists, otherwise uses getAttribute
     161         *
     162         * @ticket 31590
     163         *
     164         * @param {HTMLElement} element DOM element with the attribute
     165         * @param {String}      attribute the attribute to get
     166         *
     167         * @return {String}
     168         */
     169        function getDataAttribute( element, attribute ) {
     170                if ( supportsDataset ) {
     171                        return element.dataset[attribute];
     172                }
     173                else {
     174                        return element.getAttribute( 'data-' + attribute );
     175                }
     176        }
     177
     178        /**
     179         * Get element by Id
     180         *
     181         * local alias for document.getElementById
     182         *
     183         * @ticket 31590
     184         *
     185         * @param {HTMLElement} The requested element
     186         */
     187        function getElementById( elementId ) {
     188                return document.getElementById( elementId );
     189        }
    26190
    27                         if ( ! temp || ! respond )
    28                                 return;
    29191
    30                         t.I('comment_parent').value = '0';
    31                         temp.parentNode.insertBefore(respond, temp);
    32                         temp.parentNode.removeChild(temp);
    33                         this.style.display = 'none';
    34                         this.onclick = null;
     192        /**
     193         * moveForm
     194         *
     195         * Moves the reply form from it's current position to the reply location
     196         *
     197         * @ticket 31590
     198         *
     199         * @param {String} addBelowId HTML ID of element the form follows
     200         * @param {String} commentId  Database ID of comment being replied to
     201         * @param {String} respondId  HTML ID of 'respond' element
     202         * @param {String} postId     Database ID of the post
     203         */
     204
     205        function moveForm( addBelowId, commentId, respondId, postId ) {
     206                // get elements based on their IDs
     207                var addBelowElement = getElementById( addBelowId );
     208                respondElement  = getElementById( respondId );
     209
     210                // get the hidden fields
     211                var parentIdField   = getElementById( config.parentIdFieldId );
     212                var postIdField     = getElementById( config.postIdFieldId );
     213
     214                if ( ! addBelowElement || ! respondElement || ! parentIdField ) {
     215                        // missing key elements, fail
     216                        return;
     217                }
     218
     219                addPlaceHolder( respondElement );
     220
     221                // set the value of the post
     222                if ( postId && postIdField ) {
     223                        postIdField.value = postId;
     224                }
     225
     226                parentIdField.value = commentId;
     227
     228                cancelElement.style.display = '';
     229                addBelowElement.parentNode.insertBefore( respondElement, addBelowElement.nextSibling );
     230
     231                // this uglyness is for backward compatibility with third party commenting systems
     232                // hooking into the event using older techniques.
     233                cancelElement.onclick = function(){
    35234                        return false;
    36235                };
    37236
    38                 try { t.I('comment').focus(); }
    39                 catch(e) {}
     237                // focus on the comment field
     238                try {
     239                        commentFieldElement.focus();
     240                }
     241                catch(e) {
     242
     243                }
    40244
     245                // false is returned for backward compatibilty with third party commenting systems
     246                // hooking into this function. Eg Jetpack Comments.
    41247                return false;
    42         },
     248        }
     249
    43250
    44         I : function(e) {
    45                 return document.getElementById(e);
     251        /**
     252         * add placeholder element
     253         *
     254         * Places a place holder element above the #respond element for
     255         * the form to be returned to if needs be.
     256         *
     257         * @param {HTMLelement} respondElement the #respond element holding comment form
     258         *
     259         * @ticket 31590
     260         */
     261        function addPlaceHolder( respondElement ) {
     262                var temporaryFormId  = config.temporaryFormId;
     263                var temporaryElement = getElementById( temporaryFormId );
     264
     265                if ( temporaryElement ) {
     266                        // the element already exists.
     267                        // no need to recreate
     268                        return;
     269                }
     270
     271                temporaryElement = document.createElement( 'div' );
     272                temporaryElement.id = temporaryFormId;
     273                temporaryElement.style.display = 'none';
     274                respondElement.parentNode.insertBefore( temporaryElement, respondElement );
     275
     276                return;
    46277        }
    47 };
     278
     279
     280        return {
     281                init: init,
     282                moveForm: moveForm
     283        };
     284
     285})( window );
     286 No newline at end of file