Diff: STRATO-apps/wordpress_03/app/wp-includes/js/comment-reply.js

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