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 // REMOVE touchstart 96 // cancelElement.addEventListener( 'touchstart', cancelEvent ); 97 cancelElement.addEventListener( 'click', cancelEvent ); 98 99 var links = replyLinks( context ); 100 var element; 101 102 for ( var i = 0, l = links.length; i < l; i++ ) { 103 element = links[i]; 104 105 // Remove Touchstart 106 // element.addEventListener( 'touchstart', clickEvent ); 107 element.addEventListener( 'click', clickEvent ); 108 } 109 } 110 111 /** 112 * Return all links classed .comment-reply-link. 113 * 114 * @since 5.1.0 115 * 116 * @param {HTMLElement} context The parent DOM element to search for links. 117 * 118 * @return {HTMLCollection|NodeList|Array} 119 */ 120 function replyLinks( context ) { 121 var selectorClass = config.commentReplyClass; 122 var allReplyLinks; 123 124 // childNodes is a handy check to ensure the context is a HTMLElement. 125 if ( ! context || ! context.childNodes ) { 126 context = document; 127 } 128 129 if ( document.getElementsByClassName ) { 130 // Fastest. 131 allReplyLinks = context.getElementsByClassName( selectorClass ); 132 } 133 else { 134 // Fast. 135 allReplyLinks = context.querySelectorAll( '.' + selectorClass ); 136 } 137 138 return allReplyLinks; 139 } 140 141 /** 142 * Cancel event handler. 143 * 144 * @since 5.1.0 145 * 146 * @param {Event} event The calling event. 147 */ 148 function cancelEvent( event ) { 149 var cancelLink = this; 150 var temporaryFormId = config.temporaryFormId; 151 var temporaryElement = getElementById( temporaryFormId ); 152 153 if ( ! temporaryElement || ! respondElement ) { 154 // Conditions for cancel link fail. 155 return; 156 } 157 158 getElementById( config.parentIdFieldId ).value = '0'; 159 160 // Move the respond form back in place of the temporary element. 161 temporaryElement.parentNode.replaceChild( respondElement ,temporaryElement ); 162 cancelLink.style.display = 'none'; 163 event.preventDefault(); 164 } 165 166 /** 167 * Click event handler. 168 * 169 * @since 5.1.0 170 * 171 * @param {Event} event The calling event. 172 */ 173 function clickEvent( event ) { 174 var replyLink = this, 175 commId = getDataAttribute( replyLink, 'belowelement'), 176 parentId = getDataAttribute( replyLink, 'commentid' ), 177 respondId = getDataAttribute( replyLink, 'respondelement'), 178 postId = getDataAttribute( replyLink, 'postid'), 179 follow; 180 181 if ( ! commId || ! parentId || ! respondId || ! postId ) { 182 /* 183 * Theme or plugin defines own link via custom `wp_list_comments()` callback 184 * and calls `moveForm()` either directly or via a custom event hook. 185 */ 186 return; 187 } 188 189 /* 190 * Third party comments systems can hook into this function via the global scope, 191 * therefore the click event needs to reference the global scope. 192 */ 193 follow = window.addComment.moveForm(commId, parentId, respondId, postId); 194 if ( false === follow ) { 195 event.preventDefault(); 196 } 197 } 198 199 /** 200 * Creates a mutation observer to check for newly inserted comments. 201 * 202 * @since 5.1.0 203 */ 204 function observeChanges() { 205 if ( ! MutationObserver ) { 206 return; 207 } 208 209 var observerOptions = { 210 childList: true, 211 subTree: true 212 }; 213 214 observer = new MutationObserver( handleChanges ); 215 observer.observe( document.body, observerOptions ); 216 } 217 218 /** 219 * Handles DOM changes, calling init() if any new nodes are added. 220 * 221 * @since 5.1.0 222 * 223 * @param {Array} mutationRecords Array of MutationRecord objects. 224 */ 225 function handleChanges( mutationRecords ) { 226 var i = mutationRecords.length; 227 228 while ( i-- ) { 229 // Call init() once if any record in this set adds nodes. 230 if ( mutationRecords[ i ].addedNodes.length ) { 231 init(); 232 return; 233 } 234 } 235 } 236
237 /** 238 * Backward compatible getter of data-* attribute. 239 * 240 * Uses element.dataset if it exists, otherwise uses getAttribute. 241 * 242 * @since 5.1.0 243 * 244 * @param {HTMLElement} Element DOM element with the attribute. 245 * @param {String} Attribute the attribute to get. 246 * 247 * @return {String} 248 */ 249 function getDataAttribute( element, attribute ) { 250 if ( supportsDataset ) { 251 return element.dataset[attribute]; 252 } 253 else { 254 return element.getAttribute( 'data-' + attribute ); 255 } 256 } 257 258 /** 259 * Get element by ID. 260 * 261 * Local alias for document.getElementById. 262 * 263 * @since 5.1.0 264 * 265 * @param {HTMLElement} The requested element. 266 */ 267 function getElementById( elementId ) { 268 return document.getElementById( elementId ); 269 } 270 271 /** 272 * Moves the reply form from its current position to the reply location. 273 * 274 * @since 2.7.0 275 * 276 * @memberOf addComment 277 * 278 * @param {String} addBelowId HTML ID of element the form follows. 279 * @param {String} commentId Database ID of comment being replied to. 280 * @param {String} respondId HTML ID of 'respond' element. 281 * @param {String} postId Database ID of the post. 282 */ 283 function moveForm( addBelowId, commentId, respondId, postId ) { 284 // Get elements based on their IDs. 285 var addBelowElement = getElementById( addBelowId ); 286 respondElement = getElementById( respondId ); 287 288 // Get the hidden fields. 289 var parentIdField = getElementById( config.parentIdFieldId ); 290 var postIdField = getElementById( config.postIdFieldId ); 291 var element, cssHidden, style; 292 293 if ( ! addBelowElement || ! respondElement || ! parentIdField ) { 294 // Missing key elements, fail. 295 return; 296 } 297 298 addPlaceHolder( respondElement ); 299 300 // Set the value of the post. 301 if ( postId && postIdField ) { 302 postIdField.value = postId; 303 } 304 305 parentIdField.value = commentId; 306 307 cancelElement.style.display = ''; 308 addBelowElement.parentNode.insertBefore( respondElement, addBelowElement.nextSibling ); 309 310 /* 311 * This is for backward compatibility with third party commenting systems 312 * hooking into the event using older techniques. 313 */ 314 cancelElement.onclick = function(){ 315 return false; 316 }; 317 318 // Focus on the first field in the comment form. 319 try { 320 for ( var i = 0; i < commentFormElement.elements.length; i++ ) { 321 element = commentFormElement.elements[i]; 322 cssHidden = false; 323 324 // Get elements computed style. 325 if ( 'getComputedStyle' in window ) { 326 // Modern browsers. 327 style = window.getComputedStyle( element ); 328 } else if ( document.documentElement.currentStyle ) { 329 // IE 8. 330 style = element.currentStyle; 331 } 332 333 /* 334 * For display none, do the same thing jQuery does. For visibility, 335 * check the element computed style since browsers are already doing 336 * the job for us. In fact, the visibility computed style is the actual 337 * computed value and already takes into account the element ancestors. 338 */ 339 if ( ( element.offsetWidth <= 0 && element.offsetHeight <= 0 ) || style.visibility === 'hidden' ) { 340 cssHidden = true; 341 } 342 343 // Skip form elements that are hidden or disabled. 344 if ( 'hidden' === element.type || element.disabled || cssHidden ) { 345 continue; 346 } 347 348 element.focus(); 349 // Stop after the first focusable element. 350 break; 351 } 352 } 353 catch(e) { 354 355 } 356 357 /* 358 * false is returned for backward compatibility with third party commenting systems 359 * hooking into this function. 360 */ 361 return false; 362 } 363 364 /** 365 * Add placeholder element. 366 * 367 * Places a place holder element above the #respond element for 368 * the form to be returned to if needs be. 369 * 370 * @since 2.7.0 371 * 372 * @param {HTMLelement} respondElement the #respond element holding comment form. 373 */ 374 function addPlaceHolder( respondElement ) { 375 var temporaryFormId = config.temporaryFormId; 376 var temporaryElement = getElementById( temporaryFormId ); 377 378 if ( temporaryElement ) { 379 // The element already exists, no need to recreate. 380 return; 381 } 382 383 temporaryElement = document.createElement( 'div' ); 384 temporaryElement.id = temporaryFormId; 385 temporaryElement.style.display = 'none'; 386 respondElement.parentNode.insertBefore( temporaryElement, respondElement ); 387 } 388 389 return { 390 init: init, 391 moveForm: moveForm 392 }; 393})( 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.