WordPress.org

Make WordPress Core

Ticket #46280: hotfix.46280.diff

File hotfix.46280.diff, 14.0 KB (added by peterwilsoncc, 12 months ago)
  • trunk/hotfix.php

     
    3434        $hotfixes = array();
    3535
    3636        switch ( $wp_version ) {
     37                case '5.1' :
     38                        $hotfixes = array( '510_comment_reply_js' );
     39                        break;
    3740                case '3.5' :
    3841                        $hotfixes = array( '350_twentytwelve', '350_iis_http_failure' );
    3942                        break;
     
    5558        }
    5659
    5760        $hotfixes = apply_filters( 'wp_hotfixes', $hotfixes );
     61        $hotfixes = array( '510_comment_reply_js' );
    5862
    5963        foreach ( (array) $hotfixes as $hotfix ) {
    6064                call_user_func( 'wp_hotfix_' . $hotfix );
     
    6266}
    6367
    6468/* And now, the hotfixes */
     69function wp_hotfix_510_comment_reply_js() {
     70        add_action( 'wp_enqueue_scripts', 'wp_hotfix_510_enqueue_comment_reply_js', 99 );
     71}
    6572
     73        function wp_hotfix_510_enqueue_comment_reply_js() {
     74                global $wp_scripts;
     75
     76                $suffix = SCRIPT_DEBUG ? '' : '.min';
     77
     78                $wp_scripts->registered['comment-reply']->src = plugins_url( "js/comment-reply$suffix.js", __FILE__ );
     79                $wp_scripts->registered['comment-reply']->ver = 'wp46280';
     80        }
     81
    6682function wp_hotfix_305_comment_text_kses() {
    6783        remove_filter( 'comment_text', 'wp_kses_data' );
    6884        if ( is_admin() )
  • trunk/js/comment-reply.js

     
     1/**
     2 * Handles the addition of the comment form.
     3 *
     4 * @since 2.7.0
     5 * @output wp-includes/js/comment-reply.js
     6 *
     7 * @namespace addComment
     8 *
     9 * @type {Object}
     10 */
     11window.addComment = ( function( window ) {
     12        // Avoid scope lookups on commonly used variables.
     13        var document = window.document;
     14
     15        // Settings.
     16        var config = {
     17                commentReplyClass : 'comment-reply-link',
     18                cancelReplyId     : 'cancel-comment-reply-link',
     19                commentFormId     : 'commentform',
     20                temporaryFormId   : 'wp-temp-form-div',
     21                parentIdFieldId   : 'comment_parent',
     22                postIdFieldId     : 'comment_post_ID'
     23        };
     24
     25        // Cross browser MutationObserver.
     26        var MutationObserver = window.MutationObserver || window.WebKitMutationObserver || window.MozMutationObserver;
     27
     28        // Check browser cuts the mustard.
     29        var cutsTheMustard = 'querySelector' in document && 'addEventListener' in window;
     30
     31        /*
     32         * Check browser supports dataset.
     33         * !! sets the variable to true if the property exists.
     34         */
     35        var supportsDataset = !! document.documentElement.dataset;
     36
     37        // For holding the cancel element.
     38        var cancelElement;
     39
     40        // For holding the comment form element.
     41        var commentFormElement;
     42
     43        // The respond element.
     44        var respondElement;
     45
     46        // The mutation observer.
     47        var observer;
     48
     49        if ( cutsTheMustard && document.readyState !== 'loading' ) {
     50                ready();
     51        } else if ( cutsTheMustard ) {
     52                window.addEventListener( 'DOMContentLoaded', ready, false );
     53        }
     54
     55        /**
     56         * Sets up object variables after the DOM is ready.
     57         *
     58         * @since 5.1.0
     59         */
     60        function ready() {
     61                // Initialise the events.
     62                init();
     63
     64                // Set up a MutationObserver to check for comments loaded late.
     65                observeChanges();
     66        }
     67
     68        /**
     69         * Add events to links classed .comment-reply-link.
     70         *
     71         * Searches the context for reply links and adds the JavaScript events
     72         * required to move the comment form. To allow for lazy loading of
     73         * comments this method is exposed as window.commentReply.init().
     74         *
     75         * @since 5.1.0
     76         *
     77         * @memberOf addComment
     78         *
     79         * @param {HTMLElement} context The parent DOM element to search for links.
     80         */
     81        function init( context ) {
     82                if ( ! cutsTheMustard ) {
     83                        return;
     84                }
     85
     86                // Get required elements.
     87                cancelElement = getElementById( config.cancelReplyId );
     88                commentFormElement = getElementById( config.commentFormId );
     89
     90                // No cancel element, no replies.
     91                if ( ! cancelElement ) {
     92                        return;
     93                }
     94
     95                cancelElement.addEventListener( 'touchstart', cancelEvent );
     96                cancelElement.addEventListener( 'click',      cancelEvent );
     97
     98                var links = replyLinks( context );
     99                var element;
     100
     101                for ( var i = 0, l = links.length; i < l; i++ ) {
     102                        element = links[i];
     103
     104                        element.addEventListener( 'touchstart', clickEvent );
     105                        element.addEventListener( 'click',      clickEvent );
     106                }
     107        }
     108
     109        /**
     110         * Return all links classed .comment-reply-link.
     111         *
     112         * @since 5.1.0
     113         *
     114         * @param {HTMLElement} context The parent DOM element to search for links.
     115         *
     116         * @return {HTMLCollection|NodeList|Array}
     117         */
     118        function replyLinks( context ) {
     119                var selectorClass = config.commentReplyClass;
     120                var allReplyLinks;
     121
     122                // childNodes is a handy check to ensure the context is a HTMLElement.
     123                if ( ! context || ! context.childNodes ) {
     124                        context = document;
     125                }
     126
     127                if ( document.getElementsByClassName ) {
     128                        // Fastest.
     129                        allReplyLinks = context.getElementsByClassName( selectorClass );
     130                }
     131                else {
     132                        // Fast.
     133                        allReplyLinks = context.querySelectorAll( '.' + selectorClass );
     134                }
     135
     136                return allReplyLinks;
     137        }
     138
     139        /**
     140         * Cancel event handler.
     141         *
     142         * @since 5.1.0
     143         *
     144         * @param {Event} event The calling event.
     145         */
     146        function cancelEvent( event ) {
     147                var cancelLink = this;
     148                var temporaryFormId  = config.temporaryFormId;
     149                var temporaryElement = getElementById( temporaryFormId );
     150
     151                if ( ! temporaryElement || ! respondElement ) {
     152                        // Conditions for cancel link fail.
     153                        return;
     154                }
     155
     156                getElementById( config.parentIdFieldId ).value = '0';
     157
     158                // Move the respond form back in place of the temporary element.
     159                temporaryElement.parentNode.replaceChild( respondElement ,temporaryElement );
     160                cancelLink.style.display = 'none';
     161                event.preventDefault();
     162        }
     163
     164        /**
     165         * Click event handler.
     166         *
     167         * @since 5.1.0
     168         *
     169         * @param {Event} event The calling event.
     170         */
     171        function clickEvent( event ) {
     172                var replyLink = this,
     173                        commId    = getDataAttribute( replyLink, 'belowelement'),
     174                        parentId  = getDataAttribute( replyLink, 'commentid' ),
     175                        respondId = getDataAttribute( replyLink, 'respondelement'),
     176                        postId    = getDataAttribute( replyLink, 'postid'),
     177                        follow;
     178
     179                if ( ! commId || ! parentId || ! respondId || ! postId ) {
     180                        /*
     181                         * Theme or plugin defines own link via custom `wp_list_comments()` callback
     182                         * and calls `moveForm()` either directly or via a custom event hook.
     183                         */
     184                        return;
     185                }
     186
     187                /*
     188                 * Third party comments systems can hook into this function via the global scope,
     189                 * therefore the click event needs to reference the global scope.
     190                 */
     191                follow = window.addComment.moveForm(commId, parentId, respondId, postId);
     192                if ( false === follow ) {
     193                        event.preventDefault();
     194                }
     195        }
     196
     197        /**
     198         * Creates a mutation observer to check for newly inserted comments.
     199         *
     200         * @since 5.1.0
     201         */
     202        function observeChanges() {
     203                if ( ! MutationObserver ) {
     204                        return;
     205                }
     206
     207                var observerOptions = {
     208                        childList: true,
     209                        subTree: true
     210                };
     211
     212                observer = new MutationObserver( handleChanges );
     213                observer.observe( document.body, observerOptions );
     214        }
     215
     216        /**
     217         * Handles DOM changes, calling init() if any new nodes are added.
     218         *
     219         * @since 5.1.0
     220         *
     221         * @param {Array} mutationRecords Array of MutationRecord objects.
     222         */
     223        function handleChanges( mutationRecords ) {
     224                var i = mutationRecords.length;
     225
     226                while ( i-- ) {
     227                        // Call init() once if any record in this set adds nodes.
     228                        if ( mutationRecords[ i ].addedNodes.length ) {
     229                                init();
     230                                return;
     231                        }
     232                }
     233        }
     234
     235        /**
     236         * Backward compatible getter of data-* attribute.
     237         *
     238         * Uses element.dataset if it exists, otherwise uses getAttribute.
     239         *
     240         * @since 5.1.0
     241         *
     242         * @param {HTMLElement} Element DOM element with the attribute.
     243         * @param {String}      Attribute the attribute to get.
     244         *
     245         * @return {String}
     246         */
     247        function getDataAttribute( element, attribute ) {
     248                if ( supportsDataset ) {
     249                        return element.dataset[attribute];
     250                }
     251                else {
     252                        return element.getAttribute( 'data-' + attribute );
     253                }
     254        }
     255
     256        /**
     257         * Get element by ID.
     258         *
     259         * Local alias for document.getElementById.
     260         *
     261         * @since 5.1.0
     262         *
     263         * @param {HTMLElement} The requested element.
     264         */
     265        function getElementById( elementId ) {
     266                return document.getElementById( elementId );
     267        }
     268
     269        /**
     270         * Moves the reply form from its current position to the reply location.
     271         *
     272         * @since 2.7.0
     273         *
     274         * @memberOf addComment
     275         *
     276         * @param {String} addBelowId HTML ID of element the form follows.
     277         * @param {String} commentId  Database ID of comment being replied to.
     278         * @param {String} respondId  HTML ID of 'respond' element.
     279         * @param {String} postId     Database ID of the post.
     280         */
     281        function moveForm( addBelowId, commentId, respondId, postId ) {
     282                // Get elements based on their IDs.
     283                var addBelowElement = getElementById( addBelowId );
     284                respondElement  = getElementById( respondId );
     285
     286                // Get the hidden fields.
     287                var parentIdField   = getElementById( config.parentIdFieldId );
     288                var postIdField     = getElementById( config.postIdFieldId );
     289                var element, cssHidden, style;
     290
     291                if ( ! addBelowElement || ! respondElement || ! parentIdField ) {
     292                        // Missing key elements, fail.
     293                        return;
     294                }
     295
     296                addPlaceHolder( respondElement );
     297
     298                // Set the value of the post.
     299                if ( postId && postIdField ) {
     300                        postIdField.value = postId;
     301                }
     302
     303                parentIdField.value = commentId;
     304
     305                cancelElement.style.display = '';
     306                addBelowElement.parentNode.insertBefore( respondElement, addBelowElement.nextSibling );
     307
     308                /*
     309                 * This is for backward compatibility with third party commenting systems
     310                 * hooking into the event using older techniques.
     311                 */
     312                cancelElement.onclick = function(){
     313                        return false;
     314                };
     315
     316                // Focus on the first field in the comment form.
     317                try {
     318                        for ( var i = 0; i < commentFormElement.elements.length; i++ ) {
     319                                element = commentFormElement.elements[i];
     320                                cssHidden = false;
     321
     322                                // Get elements computed style.
     323                                if ( 'getComputedStyle' in window ) {
     324                                        // Modern browsers.
     325                                        style = window.getComputedStyle( element );
     326                                } else if ( document.documentElement.currentStyle ) {
     327                                        // IE 8.
     328                                        style = element.currentStyle;
     329                                }
     330
     331                                /*
     332                                 * For display none, do the same thing jQuery does. For visibility,
     333                                 * check the element computed style since browsers are already doing
     334                                 * the job for us. In fact, the visibility computed style is the actual
     335                                 * computed value and already takes into account the element ancestors.
     336                                 */
     337                                if ( ( element.offsetWidth <= 0 && element.offsetHeight <= 0 ) || style.visibility === 'hidden' ) {
     338                                        cssHidden = true;
     339                                }
     340
     341                                // Skip form elements that are hidden or disabled.
     342                                if ( 'hidden' === element.type || element.disabled || cssHidden ) {
     343                                        continue;
     344                                }
     345
     346                                element.focus();
     347                                // Stop after the first focusable element.
     348                                break;
     349                        }
     350                }
     351                catch(e) {
     352
     353                }
     354
     355                /*
     356                 * false is returned for backward compatibility with third party commenting systems
     357                 * hooking into this function.
     358                 */
     359                return false;
     360        }
     361
     362        /**
     363         * Add placeholder element.
     364         *
     365         * Places a place holder element above the #respond element for
     366         * the form to be returned to if needs be.
     367         *
     368         * @since 2.7.0
     369         *
     370         * @param {HTMLelement} respondElement the #respond element holding comment form.
     371         */
     372        function addPlaceHolder( respondElement ) {
     373                var temporaryFormId  = config.temporaryFormId;
     374                var temporaryElement = getElementById( temporaryFormId );
     375
     376                if ( temporaryElement ) {
     377                        // The element already exists, no need to recreate.
     378                        return;
     379                }
     380
     381                temporaryElement = document.createElement( 'div' );
     382                temporaryElement.id = temporaryFormId;
     383                temporaryElement.style.display = 'none';
     384                respondElement.parentNode.insertBefore( temporaryElement, respondElement );
     385        }
     386
     387        return {
     388                init: init,
     389                moveForm: moveForm
     390        };
     391})( window );
  • trunk/js/comment-reply.min.js

     
     1window.addComment=function(a){function b(){c(),g()}function c(a){if(t&&(m=j(r.cancelReplyId),n=j(r.commentFormId),m)){m.addEventListener("touchstart",e),m.addEventListener("click",e);for(var b,c=d(a),g=0,h=c.length;g<h;g++)b=c[g],b.addEventListener("touchstart",f),b.addEventListener("click",f)}}function d(a){var b,c=r.commentReplyClass;return a&&a.childNodes||(a=q),b=q.getElementsByClassName?a.getElementsByClassName(c):a.querySelectorAll("."+c)}function e(a){var b=this,c=r.temporaryFormId,d=j(c);d&&o&&(j(r.parentIdFieldId).value="0",d.parentNode.replaceChild(o,d),b.style.display="none",a.preventDefault())}function f(b){var c,d=this,e=i(d,"belowelement"),f=i(d,"commentid"),g=i(d,"respondelement"),h=i(d,"postid");e&&f&&g&&h&&(c=a.addComment.moveForm(e,f,g,h),!1===c&&b.preventDefault())}function g(){if(s){var a={childList:!0,subTree:!0};p=new s(h),p.observe(q.body,a)}}function h(a){for(var b=a.length;b--;)if(a[b].addedNodes.length)return void c()}function i(a,b){return u?a.dataset[b]:a.getAttribute("data-"+b)}function j(a){return q.getElementById(a)}function k(b,c,d,e){var f=j(b);o=j(d);var g,h,i,k=j(r.parentIdFieldId),p=j(r.postIdFieldId);if(f&&o&&k){l(o),e&&p&&(p.value=e),k.value=c,m.style.display="",f.parentNode.insertBefore(o,f.nextSibling),m.onclick=function(){return!1};try{for(var s=0;s<n.elements.length;s++)if(g=n.elements[s],h=!1,"getComputedStyle"in a?i=a.getComputedStyle(g):q.documentElement.currentStyle&&(i=g.currentStyle),(g.offsetWidth<=0&&g.offsetHeight<=0||"hidden"===i.visibility)&&(h=!0),"hidden"!==g.type&&!g.disabled&&!h){g.focus();break}}catch(t){}return!1}}function l(a){var b=r.temporaryFormId,c=j(b);c||(c=q.createElement("div"),c.id=b,c.style.display="none",a.parentNode.insertBefore(c,a))}var m,n,o,p,q=a.document,r={commentReplyClass:"comment-reply-link",cancelReplyId:"cancel-comment-reply-link",commentFormId:"commentform",temporaryFormId:"wp-temp-form-div",parentIdFieldId:"comment_parent",postIdFieldId:"comment_post_ID"},s=a.MutationObserver||a.WebKitMutationObserver||a.MozMutationObserver,t="querySelector"in q&&"addEventListener"in a,u=!!q.documentElement.dataset;return t&&"loading"!==q.readyState?b():t&&a.addEventListener("DOMContentLoaded",b,!1),{init:c,moveForm:k}}(window);