PluginProbe
Search Atlas SEO – OTTO AI SEO Automation for WordPress / 2.7.2
Search Atlas SEO – OTTO AI SEO Automation for WordPress v2.7.2
2.7.1 2.7.2 2.7.0 2.6.26 2.6.25 2.6.24 2.6.23 2.6.22 2.6.21 2.6.20 2.6.19 2.6.18 2.6.17 2.6.16 2.6.15 2.6.14 2.6.13 2.6.12 2.6.11 2.6.10 2.6.9 2.6.8 2.6.7 2.6.6 2.6.5 All 141 releases
metasync / admin / js / metasync-classic-seo-fields.js

metasync-classic-seo-fields.js in Search Atlas SEO – OTTO AI SEO Automation for WordPress 2.7.2, at admin/js/metasync-classic-seo-fields.js

99 lines 3.6 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function () {
2 'use strict';
3
4 // All DOM lookups live inside mount(): wp-admin prints the footer SCRIPTS
5 // (admin_print_footer_scripts) before the admin_footer-{$hook} callbacks
6 // echo the wrap, and the Categories metabox is added by jQuery at
7 // DOMContentLoaded — so at execution time none of these elements exist
8 // yet. Bailing at IIFE level here would strand the select in the footer.
9 function mount() {
10 var config = window.metasyncClassicSeoFields || {};
11 var wrap = document.getElementById('metasync-primary-category-wrap');
12 var categoryDiv = document.getElementById('categorydiv');
13 if (!wrap || !categoryDiv) {
14 return;
15 }
16
17 var select = document.getElementById('metasync-primary-category-select');
18 var checklist = document.getElementById('categorychecklist');
19 if (!select || !checklist) {
20 return;
21 }
22
23 var storedPrimary = parseInt(wrap.getAttribute('data-stored') || config.storedPrimary || 0, 10) || 0;
24 var strings = config.i18n || {};
25
26 function rebuildOptions() {
27 var checked = [];
28 checklist.querySelectorAll('label.selectit').forEach(function (label) {
29 var input = label.querySelector('input[type="checkbox"]');
30 if (!input || !input.checked) {
31 return;
32 }
33
34 var termId = parseInt(input.value, 10) || 0;
35 if (!termId) {
36 return;
37 }
38
39 checked.push({
40 id: termId,
41 name: (label.textContent || '').trim(),
42 });
43 });
44
45 var previous = parseInt(select.value, 10) || 0;
46 select.replaceChildren(new Option(strings.none || '(none)', '0'));
47
48 checked.forEach(function (category) {
49 select.appendChild(new Option(category.name, String(category.id)));
50 });
51
52 // Prefer whatever the select already shows when it is still a checked
53 // option: the select's own change event bubbles up to categoryDiv and
54 // re-enters rebuildOptions, so preferring storedPrimary here would
55 // instantly revert a fresh manual pick whenever the stored term is
56 // still checked. Fall back to the stored primary, then to none.
57 var selected = checked.some(function (category) {
58 return category.id === previous;
59 }) ? previous : (checked.some(function (category) {
60 return category.id === storedPrimary;
61 }) ? storedPrimary : 0);
62 var selectionStillChecked = checked.some(function (category) {
63 return category.id === selected;
64 });
65
66 select.value = selectionStillChecked ? String(selected) : '0';
67 // storedPrimary is deliberately NOT zeroed when its term is momentarily
68 // unchecked: uncheck-then-recheck before saving must round-trip the
69 // stored value, not delete it.
70 }
71
72 // Relocate under the core Categories checklist — beside the box the user
73 // is already interacting with, not inside the SEO Suite.
74 var inside = categoryDiv.querySelector('.inside');
75 (inside || categoryDiv).appendChild(wrap);
76 wrap.style.display = '';
77 rebuildOptions();
78
79 // Ticking in either tab (All Categories or Most Used) bubbles a change
80 // event up to the metabox, so one listener covers both lists.
81 categoryDiv.addEventListener('change', rebuildOptions);
82 // The "Add New Category" flow appends a checked <li> without firing a
83 // change event; the observer covers it.
84 var observer = new MutationObserver(rebuildOptions);
85 observer.observe(checklist, {
86 childList: true,
87 subtree: true,
88 attributes: true,
89 attributeFilter: ['class'],
90 });
91 }
92
93 if (document.readyState === 'loading') {
94 document.addEventListener('DOMContentLoaded', mount);
95 } else {
96 mount();
97 }
98 })();
99