PluginProbe
WPSSO Core – Complete Schema Markup and Meta Tags / 22.7.0
WPSSO Core – Complete Schema Markup and Meta Tags v22.7.0
22.7.0 22.6.1 22.6.0 22.5.3 22.5.2 22.5.1 22.4.0 22.3.0 22.2.1 22.2.0 22.1.3 22.1.2 22.1.1 22.1.0 22.0.0 21.13.3 21.13.2 trunk 21.13.1
wpsso / js / com / jquery-admin-page.js

jquery-admin-page.js in WPSSO Core – Complete Schema Markup and Meta Tags 22.7.0, at js/com/jquery-admin-page.js

734 lines 17.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 /*
2 * jquery-admin-page.js
3 *
4 * Common library for admin pages.
5 *
6 * Version: 20240810
7 *
8 * Update the wp_register_script() arguments for the 'sucom-admin-page' script when updating this version number.
9 */
10 function sucomEditorUnchanged( pluginId, adminPageL10n ) {
11
12 if ( 'undefined' === typeof wp.data ) return; // Just in case.
13
14 var cfg = window[ adminPageL10n ];
15
16 if ( ! cfg[ '_ajax_actions' ][ 'metabox_postboxes' ] ) {
17
18 console.error( arguments.callee.name + ': missing _ajax_actions metabox_postboxes' );
19
20 return;
21 }
22
23 for ( var postbox_id in cfg[ '_ajax_actions' ][ 'metabox_postboxes' ] ) {
24
25 sucomDisableUnchanged( '#' + postbox_id );
26 }
27 }
28
29 function sucomEditorPostbox( pluginId, adminPageL10n, postId ) {
30
31 if ( 'undefined' === typeof wp.data ) return; // Just in case.
32
33 if ( 'undefined' === typeof postId ) postId = wp.data.select( 'core/editor' ).getCurrentPostId;
34
35 var cfg = window[ adminPageL10n ];
36
37 if ( ! cfg[ '_ajax_nonce' ] ) {
38
39 console.error( arguments.callee.name + ': missing _ajax_nonce' );
40
41 return;
42
43 } else if ( ! cfg[ '_ajax_actions' ][ 'metabox_postboxes' ] ) {
44
45 console.error( arguments.callee.name + ': missing _ajax_actions metabox_postboxes' );
46
47 return;
48 }
49
50 for ( var postbox_id in cfg[ '_ajax_actions' ][ 'metabox_postboxes' ] ) {
51
52 /*
53 * Sanitize the ajax action filter name.
54 */
55 var ajax_action_update_postbox = sucomSanitizeHookname( cfg[ '_ajax_actions' ][ 'metabox_postboxes' ][ postbox_id ] );
56
57 var ajaxData = {
58 action: ajax_action_update_postbox,
59 post_id: postId,
60 _ajax_nonce: cfg[ '_ajax_nonce' ],
61 }
62
63 jQuery.post( ajaxurl, ajaxData, function( html ) {
64
65 /*
66 * The returned HTML includes javascript to call the sucomInitMetabox() function.
67 */
68 if ( html ) {
69
70 jQuery( '#' + postbox_id + '.postbox div.inside' ).replaceWith( '<div class="inside">' + html + '</div>' );
71 }
72 } );
73 }
74 }
75
76 /*
77 * Create block-editor notices first, excluding any toolbar notice types, then update toolbar notices.
78 */
79 function sucomBlockEditorNotices( pluginId, adminPageL10n ) {
80
81 if ( 'undefined' === typeof wp.data ) return; // Just in case.
82
83 var createNotice = wp.data.dispatch( 'core/notices' ).createNotice;
84 var removeNotice = wp.data.dispatch( 'core/notices' ).removeNotice;
85 var cfg = window[ adminPageL10n ];
86
87 if ( ! cfg[ '_ajax_nonce' ] ) {
88
89 console.error( arguments.callee.name + ': missing _ajax_nonce' );
90
91 return;
92
93 } else if ( ! cfg[ '_ajax_actions' ][ 'get_notices_json' ] ) {
94
95 console.error( arguments.callee.name + ': missing _ajax_actions get_notices_json' );
96
97 return;
98 }
99
100 var ajaxData = {
101 action: cfg[ '_ajax_actions' ][ 'get_notices_json' ],
102 context: 'block_editor',
103 _ajax_nonce: cfg[ '_ajax_nonce' ],
104 _exclude_types: cfg[ '_toolbar_notice_types' ], // Exclude the toolbar notice types.
105 }
106
107 jQuery.getJSON( ajaxurl, ajaxData, function( data ) {
108
109 /*
110 * Example data:
111 *
112 * Array (
113 * [err] => Array (
114 * [post-1086-notice-missing-og-image] => Array (
115 * [notice_key] => post-1086-notice-missing-og-image
116 * [dismiss_time] =>
117 * [dismiss_diff] =>
118 * [msg_text] => <p>Text.</p>
119 * [msg_spoken] => Text.
120 * [msg_html] => <div class="sucom-notice notice notice-alt inline notice-error" id="err-post-1086-notice-missing-og-image" style="display:block;"><div class="notice-label">SSO Notice</div><div class="notice-message">Text.</div></div>
121 * )
122 * )
123 * )
124 */
125 jQuery.each( data, function( noticeType ) {
126
127 jQuery.each( data[ noticeType ], function( noticeKey ) {
128
129 var noticeObj = false;
130 var noticeStatus = false;
131 var noticeSpoken = data[ noticeType ][ noticeKey ][ 'msg_spoken' ];
132 var noticeDismissable = data[ noticeType ][ noticeKey ][ 'dismiss_time' ] ? true : false; // True, false, or seconds (0 or more).
133 var noticeHidden = data[ noticeType ][ noticeKey ][ 'hidden' ] ? true : false;
134
135 if ( noticeType == 'err' ) {
136
137 noticeStatus = 'error';
138
139 } else if ( noticeType == 'warn' ) {
140
141 noticeStatus = 'warning';
142
143 } else if ( noticeType == 'inf' ) {
144
145 noticeStatus = 'info';
146 noticeDismissable = true; // Always make info messages dismissible.
147
148 } else if ( noticeType == 'upd' ) {
149
150 noticeStatus = 'success';
151 noticeDismissable = true; // Always make success messages dismissible.
152 }
153
154 if ( noticeStatus && ! noticeHidden ) {
155
156 var noticeOptions = {
157 id: noticeKey,
158 spokenMessage: noticeSpoken,
159 isDismissible: noticeDismissable,
160 };
161
162 removeNotice( noticeKey );
163
164 /*
165 * The current version of the block editor casts the notice message as a string, so we
166 * cannot give createNotice() an html message or RawHTML element. Until such time as the
167 * block editor can handle an html notice message, we must give it the "spoken" notice
168 * message instead, which is just a plain text string.
169 *
170 * var createElement = wp.element.createElement;
171 * var RawHTML = wp.element.RawHTML;
172 * var noticeHtml = data[ noticeType ][ noticeKey ][ 'msg_html' ];
173 * var noticeHtmlElement = createElement( RawHTML, {}, noticeHtml );
174 *
175 * noticeObj = createNotice( noticeStatus, noticeHtmlElement, noticeOptions );
176 *
177 * After creating the notice, remove the notices class to fix notice-in-notice padding
178 * issues for RawHTML elements.
179 *
180 * jQuery( 'div.' + pluginId + '-notice' ).parents( 'div.components-notice' ).removeClass( 'components-notice' );
181 */
182 noticeObj = createNotice( noticeStatus, noticeSpoken, noticeOptions );
183 }
184 } );
185 } );
186
187 sucomToolbarNotices( pluginId, adminPageL10n );
188 } );
189 }
190
191 function sucomToolbarNotices( pluginId, adminPageL10n ) {
192
193 var cfg = window[ adminPageL10n ];
194
195 if ( ! cfg[ '_ajax_nonce' ] ) {
196
197 console.error( arguments.callee.name + ': missing _ajax_nonce' );
198
199 return;
200
201 } else if ( ! cfg[ '_ajax_actions' ][ 'get_notices_json' ] ) {
202
203 console.error( arguments.callee.name + ': missing _ajax_actions get_notices_json' );
204
205 return;
206
207 } else if ( ! cfg[ '_toolbar_notice_types' ] ) { // No toolbar notice types to get.
208
209 return;
210 }
211
212 var menuId = '#wp-admin-bar-' + pluginId + '-toolbar-notices';
213 var subMenuId = '#wp-admin-bar-' + pluginId + '-toolbar-notices-container';
214 var counterId = '#' + pluginId + '-toolbar-notices-count';
215 var menuItem = jQuery( menuId );
216 var ajaxData = {
217 action: cfg[ '_ajax_actions' ][ 'get_notices_json' ],
218 context: 'toolbar_notices',
219 _ajax_nonce: cfg[ '_ajax_nonce' ],
220 _notice_types: cfg[ '_toolbar_notice_types' ],
221 }
222
223 jQuery( menuItem ).show();
224
225 jQuery.getJSON( ajaxurl, ajaxData, function( data ) {
226
227 var noticeHtml = '';
228 var noticeText = '';
229 var noticeTextId = cfg[ '_notice_text_id' ];
230 var noticeStatus = '';
231 var noticeTotalCount = 0;
232 var noticeTypeCount = {};
233 var noticeTimeouts = cfg[ '_toolbar_notice_timeout' ];
234 var noNoticesHtml = cfg[ '_no_notices_html' ];
235 var copyNoticesHtml = cfg[ '_copy_notices_html' ];
236 var countMsgsTransl = cfg[ '_count_msgs_transl' ];
237
238 jQuery.each( data, function( noticeType ) {
239
240 jQuery.each( data[ noticeType ], function( noticeKey ) {
241
242 if ( ! data[ noticeType ][ noticeKey ][ 'hidden' ] ) {
243
244 noticeHtml += data[ noticeType ][ noticeKey ][ 'msg_html' ];
245
246 noticeTypeCount[ noticeType ] = ++noticeTypeCount[ noticeType ] || 1;
247
248 noticeTotalCount++;
249 }
250
251 noticeText += "\n";
252 noticeText += '[' + noticeType + '] ';
253 noticeText += data[ noticeType ][ noticeKey ][ 'notice_label' ];
254 noticeText += ': ';
255 noticeText += sucomStripHtml( data[ noticeType ][ noticeKey ][ 'msg_text' ] );
256 noticeText += "\n";
257 } );
258 } );
259
260 /*
261 * Cleanup any pre-existing notice classes.
262 */
263 jQuery( 'body.wp-admin' ).removeClass( 'has-toolbar-notices' );
264
265 menuItem.removeClass( 'has-toolbar-notices' );
266 menuItem.removeClass( 'toolbar-notices-error' );
267 menuItem.removeClass( 'toolbar-notices-warning' );
268 menuItem.removeClass( 'toolbar-notices-info' );
269 menuItem.removeClass( 'toolbar-notices-success' );
270
271 if ( noticeHtml ) {
272
273 noticeHtml = '<div style="display:none;" id="' + noticeTextId + '">' + noticeText + '</div>' + copyNoticesHtml + noticeHtml;
274
275 jQuery( subMenuId ).html( noticeHtml );
276
277 jQuery( 'body.wp-admin' ).addClass( 'has-toolbar-notices' );
278
279 menuItem.addClass( 'has-toolbar-notices' );
280
281 } else {
282
283 jQuery( subMenuId ).html( noNoticesHtml );
284 }
285
286 jQuery( counterId ).html( noticeTotalCount );
287
288 if ( noticeTotalCount ) {
289
290 var noticeStatus = '';
291 var noticeTime = -1;
292
293 if ( noticeTypeCount[ 'err' ] ) { noticeStatus = 'error'; noticeTime = noticeTimeouts[ 'err' ]; }
294 else if ( noticeTypeCount[ 'warn' ] ) { noticeStatus = 'warning'; noticeTime = noticeTimeouts[ 'warn' ]; }
295 else if ( noticeTypeCount[ 'inf' ] ) { noticeStatus = 'info'; noticeTime = noticeTimeouts[ 'inf' ]; }
296 else if ( noticeTypeCount[ 'upd' ] ) { noticeStatus = 'success'; noticeTime = noticeTimeouts[ 'upd' ]; }
297
298 menuItem.addClass( 'toolbar-notices-' + noticeStatus );
299
300 /*
301 * noticeTime = -1 to skip automatically showing notifications.
302 * noticeTime = 0 to automatically show notifications until click or hover.
303 * noticeTime = milliseconds to automatically show notifications.
304 */
305 if ( noticeTime < 0 ) {
306
307 // Nothing to do.
308
309 } else if ( noticeTime > 0 ) {
310
311 menuItem.addClass( 'show-timeout' );
312
313 jQuery( document ).on( 'click', function( event ) {
314
315 /*
316 * Remove the 'show-timeout' class if we're clicking anywhere outside the notices menu.
317 */
318 if ( ! menuItem.is( event.target ) && ! menuItem.has( event.target ).length ) {
319
320 menuItem.removeClass( 'show-timeout' );
321
322 jQuery( document ).off( 'click', arguments.callee );
323 }
324 } );
325
326 setTimeout( function() {
327
328 menuItem.removeClass( 'show-timeout' );
329
330 }, noticeTime );
331
332 } else { /* noticeTime is 0. */
333
334 menuItem.addClass( 'hover' );
335
336 jQuery( document ).on( 'click', function( event ) {
337
338 /*
339 * Remove the 'hover' class if we're clicking anywhere outside the notices menu.
340 */
341 if ( ! menuItem.is( event.target ) && ! menuItem.has( event.target ).length ) {
342
343 menuItem.removeClass( 'hover' );
344
345 jQuery( document ).off( 'click', arguments.callee );
346 }
347 } );
348 }
349 }
350 } );
351 }
352
353 function sucomToolbarValidators( pluginId, adminPageL10n, postId ) {
354
355 if ( 'undefined' === typeof postId ) postId = wp.data.select( 'core/editor' ).getCurrentPostId;
356
357 var cfg = window[ adminPageL10n ];
358
359 if ( ! cfg[ '_ajax_nonce' ] ) {
360
361 console.error( arguments.callee.name + ': missing _ajax_nonce' );
362
363 return;
364
365 } else if ( ! cfg[ '_ajax_actions' ][ 'get_validate_submenu' ] ) {
366
367 console.error( arguments.callee.name + ': missing _ajax_actions get_validate_submenu' );
368
369 return;
370 }
371
372 var subMenuId = '#wp-admin-bar-' + pluginId + '-validate ul.ab-submenu';
373
374 var ajaxData = {
375 action: cfg[ '_ajax_actions' ][ 'get_validate_submenu' ],
376 post_id: postId,
377 _ajax_nonce: cfg[ '_ajax_nonce' ],
378 }
379
380 jQuery.post( ajaxurl, ajaxData, function( html ) {
381
382 /*
383 * The returned HTML includes javascript to call the sucomInitMetabox() function.
384 */
385 if ( html ) {
386
387 jQuery( subMenuId ).replaceWith( html );
388 }
389 } );
390 }
391
392 function sucomDeleteMeta( metaType, objId, metaKey, adminPageL10n ) {
393
394 var cfg = window[ adminPageL10n ];
395
396 var delActionKey = 'delete_' + metaType + '_meta';
397
398 if ( ! cfg[ '_ajax_nonce' ] ) {
399
400 console.error( arguments.callee.name + ': missing _ajax_nonce' );
401
402 return;
403
404 } else if ( ! cfg[ '_ajax_actions' ][ delActionKey ] ) {
405
406 console.error( arguments.callee.name + ': missing _ajax_actions ' + delActionKey );
407
408 return;
409 }
410
411 var ajaxData = {
412 action: cfg[ '_ajax_actions' ][ delActionKey ],
413 obj_id: objId,
414 meta_key: metaKey,
415 _ajax_nonce: cfg[ '_ajax_nonce' ],
416 }
417
418 jQuery.post( ajaxurl, ajaxData, function( table_row_id ) {
419
420 table_row_id = table_row_id.trim(); // Just in case.
421
422 if ( table_row_id ) {
423
424 jQuery( '#' + table_row_id ).hide();
425
426 } else if ( cfg[ '_del_failed_transl' ] ) {
427
428 var failed_msg = cfg[ '_del_failed_transl' ].formatUnicorn( objId, metaKey );
429
430 alert( failed_msg );
431 }
432 } );
433 }
434
435 function sucomCopyById( cssId, adminPageL10n ) {
436
437 var cfg = window[ adminPageL10n ];
438
439 if ( ! cfg[ '_copy_clipboard_transl' ] ) {
440
441 console.error( arguments.callee.name + ': missing _copy_clipboard_transl' );
442
443 return;
444 }
445
446 try {
447
448 var copyClipboardTransl = cfg[ '_copy_clipboard_transl' ];
449
450 var elem = document.getElementById( cssId );
451
452 /*
453 * Check for input field value first, then container content.
454 */
455 var elemVal = elem.value;
456
457 if ( 'undefined' === typeof elemVal ) {
458
459 elemVal = elem.textContent;
460 }
461
462 var target = document.createElement( 'textarea' );
463
464 target.id = 'copy_target_' + cssId;
465 target.style.position = 'absolute';
466 target.style.top = '0';
467 target.style.left = '-9999px';
468
469 document.body.appendChild( target );
470
471 target.textContent = elemVal;
472
473 target.focus();
474
475 target.setSelectionRange( 0, target.value.length );
476
477 document.execCommand( 'copy' );
478
479 target.textContent = '';
480
481 alert( copyClipboardTransl );
482
483 } catch ( err ) {
484
485 alert( err );
486 }
487
488 return false; // Prevent the webpage from reloading.
489 }
490
491 /*
492 * Convert some HTML tags to spaces first, strip everything else, then convert multiple spaces to a single space.
493 */
494 function sucomStripHtml( html ) {
495
496 html = html.replace( /<(p|pre|ul|li|br\/?)( [^<>]*>|>)/gi, ' ' );
497 html = html.replace( /<[^<>]*>/gi, '' );
498 html = html.replace( /\s\s+/gi, ' ' );
499
500 return html;
501 }
502
503 function sucomEscAttr ( string ) {
504
505 var entity_map = {
506 '&': '&amp;',
507 '<': '&lt;',
508 '>': '&gt;',
509 '"': '&quot;',
510 "'": '&apos;',
511 };
512
513 return String( string ).replace( /[&<>"']/g, function ( s ) {
514
515 return entity_map[ s ];
516 } );
517 }
518
519 /*
520 * See SucomUtil::sanitize_css_id().
521 */
522 function sucomSanitizeCssId( string ) {
523
524 string = string.replace( /[^a-zA-Z0-9\-_]+/g, '-' );
525 string = string.replace( /^-+|-+$/g, '' );
526
527 return string;
528 }
529
530 /*
531 * See SucomUtil::sanitize_hookname().
532 */
533 function sucomSanitizeHookname( string ) {
534
535 string = string.replace( /[#:\/\-\. \[\]]+/g, '_' );
536 string = string.replace( /_+$/, '' ); // Only trim right side underscores to allow for '__return_false'.
537
538 return sucomSanitizeKey( string );
539 }
540
541 /*
542 * See SucomUtil::sanitize_key().
543 */
544 function sucomSanitizeKey( string, allow_upper ) {
545
546 if ( 'undefined' === typeof allow_upper ) allow_upper = false;
547
548 if ( ! allow_upper ) string = string.toLowerCase();
549
550 string = string.replace( /[^a-z0-9\-_:]/g, '' );
551
552 return string;
553 }
554
555 function sucomTextLen( containerId, adminPageL10n ) {
556
557 var cfg = window[ adminPageL10n ];
558
559 if ( 'undefined' === typeof cfg ) {
560
561 cfg = {
562 '_min_len_transl': '{0} of {1} characters minimum',
563 '_req_len_transl': '{0} of {1} characters recommended',
564 '_max_len_transl': '{0} of {1} characters maximum',
565 '_len_transl' : '{0} characters',
566 }
567 }
568
569 var container = jQuery( '#' + containerId );
570 var text_len = sucomTextLenClean( container.val() ).length;
571 var max_len = Number( container.attr( 'maxLength' ) );
572 var warn_len = Number( container.attr( 'warnLength' ) );
573 var min_len = Number( container.attr( 'minLength' ) );
574
575 if ( ! text_len ) {
576
577 text_len = sucomTextLenClean( container.attr( 'placeholder' ) ).length;
578 }
579
580 /*
581 * Sanitize the max_len, warn_len, and min_len values.
582 */
583 if ( ! max_len ) {
584
585 max_len = 0;
586 }
587
588 if ( ! warn_len ) {
589
590 if ( max_len ) {
591
592 warn_len = 0.9 * max_len; // Default to 90% of max_len.
593
594 } else {
595
596 warn_len = 0;
597 }
598 }
599
600 if ( ! min_len ) {
601
602 min_len = 0;
603 }
604
605 if ( min_len && max_len && max_len < min_len ) {
606
607 max_len = min_len;
608 }
609
610 /*
611 * Select a text string and the character limit.
612 */
613 var char_limit = max_len; // Default value.
614
615 if ( min_len ) {
616
617 if ( ! max_len ) {
618
619 char_limit = min_len;
620
621 msg_transl = cfg[ '_min_len_transl' ];
622
623 } else {
624
625 if ( max_len > min_len ) {
626
627 char_limit = String( min_len ) + '-' + String( max_len );
628 }
629
630 msg_transl = cfg[ '_req_len_transl' ];
631 }
632
633 } else if ( max_len ) {
634
635 msg_transl = cfg[ '_max_len_transl' ];
636
637 } else {
638
639 msg_transl = cfg[ '_len_transl' ];
640 }
641
642 /*
643 * Select a CSS class.
644 */
645 if ( max_len && text_len >= ( max_len - 5 ) ) { // 5 characters from the end.
646
647 css_class = 'maximum';
648
649 } else if ( warn_len && text_len >= warn_len ) { // Length is over the warning limit.
650
651 css_class = 'long';
652
653 } else if ( min_len && text_len < min_len ) { // Length is less than the minimum.
654
655 css_class = 'short';
656
657 } else {
658
659 css_class = 'good';
660 }
661
662 /*
663 * Create the container HTML.
664 */
665 var container_html = '';
666
667 if ( max_len ) {
668
669 var pct_width = Math.round( text_len * 100 / max_len );
670
671 container_html += '<div class="text-len-progress-bar">';
672 container_html += '<div class="text-len-progress ' + css_class + '" style="width:' + pct_width + '%;"></div>';
673 container_html += '</div>';
674 }
675
676 container_html += '<div class="text-len-status ' + css_class + '">';
677 container_html += msg_transl.formatUnicorn( text_len, char_limit );
678 container_html += '</div>';
679
680 /*
681 * Add the container HTML.
682 */
683 jQuery( '#' + containerId + '-text-len-wrapper' ).html( container_html );
684 }
685
686 function sucomTextLenReset( containerId ) {
687
688 jQuery( '#' + containerId + '-text-len-wrapper' ).html( '' )
689 }
690
691 function sucomTextLenClean( str ) {
692
693 if ( 'undefined' === typeof str || ! str.length ) {
694
695 return '';
696 }
697
698 try {
699
700 str = str.replace( /<\/?[^>]+>/g, '' );
701 str = str.replace( /\[(.+?)\](.+?\[\/\\1\])?/, '' )
702
703 } catch( err ) {}
704
705 return str.trim();
706 }
707
708 /*
709 * String.prototype.formatUnicorn from Stack Overflow.
710 *
711 * Replace {0}, {1}, etc. in strings.
712 */
713 String.prototype.formatUnicorn = function() {
714
715 "use strict";
716
717 var str = this.toString();
718
719 if ( arguments.length ) {
720
721 var t = typeof arguments[ 0 ];
722 var key;
723 var args = ( "string" === t || "number" === t ) ? Array.prototype.slice.call( arguments ) : arguments[ 0 ];
724
725 for ( key in args ) {
726
727 str = str.replace( new RegExp( "\\{" + key + "\\}", "gi" ), args[ key ] );
728 }
729 }
730
731 return str;
732 }
733
734