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.1 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 );
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.