PluginProbe
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) / 2.1.3
Darkify – Dark Mode & Night Mode for Website & Admin (Dark Theme Included) v2.1.3
2.1.3 2.1.2 2.1.1 2.1.0 2.0.4 2.0.3 2.0.2 2.0.1 2.0.0 1.5.5 1.5.4 1.5.3 1.5.2 1.5.1 1.5.0 trunk 1.0.1 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 All 57 releases
← All changes | src/Frontend/Templates/header_script.php +224 -7 1.5.42.1.3 View file →
@@ -6,8 +6,33 @@
6 6 if (!defined('ABSPATH')) {
7 7 exit;
8 8 }
9 9
10 +if (!function_exists('darkify_js_string')) {
11 + /**
12 + * Emit a value as a JavaScript string literal (quotes included).
13 + *
14 + * For anything the browser parses rather than displays — CSS selectors,
15 + * above all — esc_attr() is the wrong escaper inside a <script> block: it
16 + * HTML-encodes `>`, `&` and `"`, and script bodies are raw text, so those
17 + * entities reach the JS engine verbatim and corrupt the value. JSON is the
18 + * correct escaping for a JS string; the HEX flags additionally keep `<`,
19 + * `>`, `&`, `'` and `"` out of the raw output so the literal can never
20 + * close the surrounding <script> tag.
21 + *
22 + * @param mixed $value Value to emit (cast to string).
23 + * @return string A quoted JS string literal, e.g. '"#id, #id *"'.
24 + */
25 + function darkify_js_string($value)
26 + {
27 + $json = wp_json_encode(
28 + (string) $value,
29 + JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT
30 + );
31 + return false === $json ? '""' : $json;
32 + }
33 +}
34 +
10 35 ob_start();
11 36 $options = get_option('darkify');
12 37 // Controls
13 38 $enable_default_dark_mode = isset($options['enable_default_dark_mode']) ? $options['enable_default_dark_mode'] : '';
@@ -12,8 +37,9 @@
12 37 // Controls
13 38 $enable_default_dark_mode = isset($options['enable_default_dark_mode']) ? $options['enable_default_dark_mode'] : '';
14 39 $enable_os_aware = isset($options['enable_os_aware']) ? $options['enable_os_aware'] : true;
15 40 $enable_keyboard_shortcut = isset($options['enable_keyboard_shortcut']) ? $options['enable_keyboard_shortcut'] : true;
41 +$keyboard_shortcut_keys = isset($options['keyboard_shortcut_keys']) && $options['keyboard_shortcut_keys'] ? $options['keyboard_shortcut_keys'] : 'ctrl+alt+d';
16 42 $enable_time = isset($options['enable_time']) ? $options['enable_time'] : "";
17 43 $enable_time_based_dark = isset($enable_time['enable_time_based_dark']) ? $enable_time['enable_time_based_dark'] : "";
18 44 $enable_time_fields = isset($enable_time['enable_time_fields']) ? $enable_time['enable_time_fields'] : '';
19 45 $time_based_dark_start = isset($enable_time_fields['time_based_dark_start']) ? $enable_time_fields['time_based_dark_start'] : "";
@@ -50,8 +76,43 @@
50 76 $low_image_darken_label = isset($darken_background['low_image_darken_label']) ? $darken_background['low_image_darken_label'] : '60';
51 77
52 78 $enable_invert_inline_svg = isset($options['enable_invert_inline_svg']) ? $options['enable_invert_inline_svg'] : "";
53 79
80 +/*
81 + * The override rows are printed into a <script> as raw JSON (like
82 + * darkify_allowed_btn_class below), so each value is reduced to a known-safe
83 + * shape here: a hex colour or one of the fixed scope keys. Rows missing either
84 + * colour are dropped — a half-filled repeater row is the default state of the
85 + * field and means nothing to the engine.
86 + */
87 +$darkify_color_overrides = array();
88 +if (!empty($options['color_overrides']) && is_array($options['color_overrides'])) {
89 + $darkify_override_scopes = array('all', 'text', 'icon', 'background', 'border', 'shadow');
90 + foreach ($options['color_overrides'] as $darkify_override_row) {
91 + if (!is_array($darkify_override_row)) {
92 + continue;
93 + }
94 +
95 + $darkify_light = isset($darkify_override_row['light_color']) ? DarkifyUtils::sanitize_css_color($darkify_override_row['light_color']) : '';
96 + $darkify_dark = isset($darkify_override_row['dark_color']) ? DarkifyUtils::sanitize_css_color($darkify_override_row['dark_color']) : '';
97 +
98 + if (!$darkify_light || !$darkify_dark) {
99 + continue;
100 + }
101 +
102 + $darkify_scope = isset($darkify_override_row['override_scope']) ? $darkify_override_row['override_scope'] : 'all';
103 + if (!in_array($darkify_scope, $darkify_override_scopes, true)) {
104 + $darkify_scope = 'all';
105 + }
106 +
107 + $darkify_color_overrides[] = array(
108 + 'light_color' => $darkify_light,
109 + 'dark_color' => $darkify_dark,
110 + 'override_scope' => $darkify_scope,
111 + );
112 + }
113 +}
114 +
54 115 $invert = isset($options['invert']) ? $options['invert'] : "";
55 116 $enable_invert_images = isset($invert['enable_invert_images']) ? $invert['enable_invert_images'] : "";
56 117 $invert_images_allowed_urls = !empty($invert['invert_images_allowed_urls']) ? DarkifyUtils::normalize_image_urls($invert['invert_images_allowed_urls']) : "";
57 118
@@ -86,9 +147,54 @@
86 147 } else {
87 148 $video_replacements = "[]";
88 149 }
89 150 if (!is_admin()) { ?>
90 - <script type="text/javascript" class="darkify_inline_js">(function(){var s=localStorage.darkify_last_state,t=localStorage.darkify_selected_theme||'set1';if(s==='1'){var h=document.documentElement;h.classList.add('darkify_dark_mode_enabled');h.classList.add('darkify-'+t);}}());</script>
151 + <?php
152 + /*
153 + * Release the pre-paint guard when the engine is done, not on a fixed timer.
154 + *
155 + * This used to be a flat `setTimeout(..., 800)`. On a warm reload that is
156 + * invisible — every asset is in cache, the engine's first walk lands early,
157 + * and it drops both classes itself long before the timer. On a HARD reload
158 + * it is the flicker: nothing is served from cache, so the engine script and
159 + * the stylesheets it reads are re-fetched and the first walk lands well
160 + * after 800ms. The timer fired first, un-hid `body` while the page still
161 + * carried the theme's LIGHT colours, and the walk then flipped the whole
162 + * page to dark a few hundred ms later. That flip is what the visitor sees
163 + * flickering.
164 + *
165 + * The timeout's real job is the failsafe: if the engine never runs (script
166 + * 404s, blocked by an optimiser, JS disabled mid-flight) the page must not
167 + * stay hidden. So the guard now comes off on a condition rather than a
168 + * duration:
169 + *
170 + * - engine still to paint -> keep waiting; it removes the classes itself
171 + * the moment its first walk has real colours on the page.
172 + * - parsing finished and `window.darkify_engine_loaded` still unset ->
173 + * the engine is not on this page and never will be, so release at once.
174 + * That is strictly quicker than the old fixed 800ms in the case the
175 + * timer actually existed for.
176 + * - 4000ms -> release regardless, so no failure mode can leave the page
177 + * hidden. Comfortably above the slowest measured hard reload.
178 + *
179 + * Parse state is the gate, not the presence of the engine's script tag: on
180 + * a large page the tag can sit hundreds of KB into <head> and simply not be
181 + * parsed yet at the moment we look, which reads as "no engine" on exactly
182 + * the slow load this is meant to protect.
183 + *
184 + * Only `darkify_fouc_guard` is polled. Once that is gone the engine has
185 + * demonstrably painted, so `darkify_prepaint` can be left to it; the two are
186 + * still dropped together if the failsafe ever has to fire, which preserves
187 + * the original guarantee that neither class can outlive the page load.
188 + *
189 + * No `>`/`<`/`&` anywhere in the snippet, so the ceiling is counted in
190 + * 100ms ticks (40 = 4s) and every test is an `===`/`!==`. wp_kses
191 + * entity-encodes all three characters inside script text — `n>=40` reaches
192 + * the browser as `n&gt;=40` and dies with a SyntaxError — which is also why
193 + * the gates are nested ifs rather than `&&`.
194 + */
195 + ?>
196 + <script type="text/javascript" class="darkify_inline_js">(function(){var s=localStorage.darkify_last_state,t=localStorage.darkify_selected_theme||'set1';if(s==='1'){var h=document.documentElement;h.classList.add('darkify_dark_mode_enabled');h.classList.add('darkify-'+t);h.classList.add('darkify_prepaint');h.classList.add('darkify_fouc_guard');var r=function(){h.classList.remove('darkify_prepaint');h.classList.remove('darkify_fouc_guard');};var n=0;var p=function(){if(!h.classList.contains('darkify_fouc_guard')){return;}n=n+1;if(n===40){r();return;}if(document.readyState!=='loading'){if(!window.darkify_engine_loaded){r();return;}}setTimeout(p,100);};setTimeout(p,100);}}());</script>
91 197 <style type="text/css" class="darkify_inline_css">
92 198 :root {
93 199 <?php
94 200 $dark_mode_color_palettes = [
@@ -105,8 +211,10 @@
105 211 'btn_text_color' => isset($options["dark_mode_btn_color_set1"]) ? $options["dark_mode_btn_color_set1"]['color'] : '#BEBEBE',
106 212 'btn_bg' => isset($options["dark_mode_btn_color_set1"]) ? $options["dark_mode_btn_color_set1"]['background'] : '#4A4A4A',
107 213 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set1"]) ? $options["dark_mode_btn_color_set1"]['hover_color'] : '#BEBEBE',
108 214 'btn_hover_bg' => isset($options["dark_mode_btn_color_set1"]) ? $options["dark_mode_btn_color_set1"]['hover_background'] : '#2D2D2D',
215 + 'btn_border_color' => isset($options["dark_mode_btn_color_set1"]['border']) ? $options["dark_mode_btn_color_set1"]['border'] : '#4A4A4A',
216 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set1"]['hover_border']) ? $options["dark_mode_btn_color_set1"]['hover_border'] : '#2D2D2D',
109 217 ],
110 218 'set2' => [
111 219 'bg' => isset($options["dark_mode_color_set2"]) ? $options["dark_mode_color_set2"]['background'] : '#092635',
112 220 'secondary_bg' => isset($options["dark_mode_color_set2"]) ? $options["dark_mode_color_set2"]['secondary_background'] : '#081E29',
@@ -120,8 +228,10 @@
120 228 'btn_text_color' => isset($options["dark_mode_btn_color_set2"]) ? $options["dark_mode_btn_color_set2"]['color'] : '#BEE0F1',
121 229 'btn_bg' => isset($options["dark_mode_btn_color_set2"]) ? $options["dark_mode_btn_color_set2"]['background'] : '#195979',
122 230 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set2"]) ? $options["dark_mode_btn_color_set2"]['hover_color'] : '#BEE0F1',
123 231 'btn_hover_bg' => isset($options["dark_mode_btn_color_set2"]) ? $options["dark_mode_btn_color_set2"]['hover_background'] : '#2D2D2D',
232 + 'btn_border_color' => isset($options["dark_mode_btn_color_set2"]['border']) ? $options["dark_mode_btn_color_set2"]['border'] : '#195979',
233 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set2"]['hover_border']) ? $options["dark_mode_btn_color_set2"]['hover_border'] : '#2D2D2D',
124 234 ],
125 235 'set3' => [
126 236 'bg' => isset($options["dark_mode_color_set3"]) ? $options["dark_mode_color_set3"]['background'] : '#211e3c',
127 237 'secondary_bg' => isset($options["dark_mode_color_set3"]) ? $options["dark_mode_color_set3"]['secondary_background'] : '#302C57',
@@ -135,8 +245,10 @@
135 245 'btn_text_color' => isset($options["dark_mode_btn_color_set3"]) ? $options["dark_mode_btn_color_set3"]['color'] : '#B1BBD8',
136 246 'btn_bg' => isset($options["dark_mode_btn_color_set3"]) ? $options["dark_mode_btn_color_set3"]['background'] : '#4E478D',
137 247 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set3"]) ? $options["dark_mode_btn_color_set3"]['hover_color'] : '#B1BBD8',
138 248 'btn_hover_bg' => isset($options["dark_mode_btn_color_set3"]) ? $options["dark_mode_btn_color_set3"]['hover_background'] : '#2A264D',
249 + 'btn_border_color' => isset($options["dark_mode_btn_color_set3"]['border']) ? $options["dark_mode_btn_color_set3"]['border'] : '#4E478D',
250 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set3"]['hover_border']) ? $options["dark_mode_btn_color_set3"]['hover_border'] : '#2A264D',
139 251 ],
140 252 'set4' => [
141 253 'bg' => isset($options["dark_mode_color_set4"]) ? $options["dark_mode_color_set4"]['background'] : '#1d253a',
142 254 'secondary_bg' => isset($options["dark_mode_color_set4"]) ? $options["dark_mode_color_set4"]['secondary_background'] : '#2B3655',
@@ -150,8 +262,10 @@
150 262 'btn_text_color' => isset($options["dark_mode_btn_color_set4"]) ? $options["dark_mode_btn_color_set4"]['color'] : '#B1BBD8',
151 263 'btn_bg' => isset($options["dark_mode_btn_color_set4"]) ? $options["dark_mode_btn_color_set4"]['background'] : '#46598C',
152 264 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set4"]) ? $options["dark_mode_btn_color_set4"]['hover_color'] : '#B1BBD8',
153 265 'btn_hover_bg' => isset($options["dark_mode_btn_color_set4"]) ? $options["dark_mode_btn_color_set4"]['hover_background'] : '#303D60',
266 + 'btn_border_color' => isset($options["dark_mode_btn_color_set4"]['border']) ? $options["dark_mode_btn_color_set4"]['border'] : '#46598C',
267 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set4"]['hover_border']) ? $options["dark_mode_btn_color_set4"]['hover_border'] : '#303D60',
154 268 ],
155 269 'set5' => [
156 270 'bg' => isset($options["dark_mode_color_set5"]) ? $options["dark_mode_color_set5"]['background'] : '#1b1823',
157 271 'secondary_bg' => isset($options["dark_mode_color_set5"]) ? $options["dark_mode_color_set5"]['secondary_background'] : '#352f44',
@@ -165,8 +279,10 @@
165 279 'btn_text_color' => isset($options["dark_mode_btn_color_set5"]) ? $options["dark_mode_btn_color_set5"]['color'] : '#C6C1D5',
166 280 'btn_bg' => isset($options["dark_mode_btn_color_set5"]) ? $options["dark_mode_btn_color_set5"]['background'] : '#54496f',
167 281 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set5"]) ? $options["dark_mode_btn_color_set5"]['hover_color'] : '#C6C1D5',
168 282 'btn_hover_bg' => isset($options["dark_mode_btn_color_set5"]) ? $options["dark_mode_btn_color_set5"]['hover_background'] : '#403953',
283 + 'btn_border_color' => isset($options["dark_mode_btn_color_set5"]['border']) ? $options["dark_mode_btn_color_set5"]['border'] : '#54496f',
284 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set5"]['hover_border']) ? $options["dark_mode_btn_color_set5"]['hover_border'] : '#403953',
169 285 ],
170 286 'set6' => [
171 287 'bg' => isset($options["dark_mode_color_set6"]) ? $options["dark_mode_color_set6"]['background'] : '#082032',
172 288 'secondary_bg' => isset($options["dark_mode_color_set6"]) ? $options["dark_mode_color_set6"]['secondary_background'] : '#061825',
@@ -180,8 +296,10 @@
180 296 'btn_text_color' => isset($options["dark_mode_btn_color_set6"]) ? $options["dark_mode_btn_color_set6"]['color'] : '#B5D9F3',
181 297 'btn_bg' => isset($options["dark_mode_btn_color_set6"]) ? $options["dark_mode_btn_color_set6"]['background'] : '#144E78',
182 298 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set6"]) ? $options["dark_mode_btn_color_set6"]['hover_color'] : '#B5D9F3',
183 299 'btn_hover_bg' => isset($options["dark_mode_btn_color_set6"]) ? $options["dark_mode_btn_color_set6"]['hover_background'] : '#0E3755',
300 + 'btn_border_color' => isset($options["dark_mode_btn_color_set6"]['border']) ? $options["dark_mode_btn_color_set6"]['border'] : '#144E78',
301 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set6"]['hover_border']) ? $options["dark_mode_btn_color_set6"]['hover_border'] : '#0E3755',
184 302 ],
185 303 'set7' => [
186 304 'bg' => isset($options["dark_mode_color_set7"]) ? $options["dark_mode_color_set7"]['background'] : '#07161b',
187 305 'secondary_bg' => isset($options["dark_mode_color_set7"]) ? $options["dark_mode_color_set7"]['secondary_background'] : '#0d242e',
@@ -195,8 +313,10 @@
195 313 'btn_text_color' => isset($options["dark_mode_btn_color_set7"]) ? $options["dark_mode_btn_color_set7"]['color'] : '#C5E6F0',
196 314 'btn_bg' => isset($options["dark_mode_btn_color_set7"]) ? $options["dark_mode_btn_color_set7"]['background'] : '#286F8D',
197 315 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set7"]) ? $options["dark_mode_btn_color_set7"]['hover_color'] : '#C5E6F0',
198 316 'btn_hover_bg' => isset($options["dark_mode_btn_color_set7"]) ? $options["dark_mode_btn_color_set7"]['hover_background'] : '#19495A',
317 + 'btn_border_color' => isset($options["dark_mode_btn_color_set7"]['border']) ? $options["dark_mode_btn_color_set7"]['border'] : '#286F8D',
318 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set7"]['hover_border']) ? $options["dark_mode_btn_color_set7"]['hover_border'] : '#19495A',
199 319 ],
200 320 'set8' => [
201 321 'bg' => isset($options["dark_mode_color_set8"]) ? $options["dark_mode_color_set8"]['background'] : '#15274C',
202 322 'secondary_bg' => isset($options["dark_mode_color_set8"]) ? $options["dark_mode_color_set8"]['secondary_background'] : '#112244',
@@ -210,8 +330,10 @@
210 330 'btn_text_color' => isset($options["dark_mode_btn_color_set8"]) ? $options["dark_mode_btn_color_set8"]['color'] : '#ACC1EA',
211 331 'btn_bg' => isset($options["dark_mode_btn_color_set8"]) ? $options["dark_mode_btn_color_set8"]['background'] : '#244892',
212 332 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set8"]) ? $options["dark_mode_btn_color_set8"]['hover_color'] : '#ACC1EA',
213 333 'btn_hover_bg' => isset($options["dark_mode_btn_color_set8"]) ? $options["dark_mode_btn_color_set8"]['hover_background'] : '#1a2f5c',
334 + 'btn_border_color' => isset($options["dark_mode_btn_color_set8"]['border']) ? $options["dark_mode_btn_color_set8"]['border'] : '#244892',
335 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set8"]['hover_border']) ? $options["dark_mode_btn_color_set8"]['hover_border'] : '#1a2f5c',
214 336 ],
215 337 'set9' => [
216 338 'bg' => isset($options["dark_mode_color_set9"]) ? $options["dark_mode_color_set9"]['background'] : '#04261d',
217 339 'secondary_bg' => isset($options["dark_mode_color_set9"]) ? $options["dark_mode_color_set9"]['secondary_background'] : '#021e16',
@@ -225,8 +347,10 @@
225 347 'btn_text_color' => isset($options["dark_mode_btn_color_set9"]) ? $options["dark_mode_btn_color_set9"]['color'] : '#C1D2BB',
226 348 'btn_bg' => isset($options["dark_mode_btn_color_set9"]) ? $options["dark_mode_btn_color_set9"]['background'] : '#095541',
227 349 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set9"]) ? $options["dark_mode_btn_color_set9"]['hover_color'] : '#C1D2BB',
228 350 'btn_hover_bg' => isset($options["dark_mode_btn_color_set9"]) ? $options["dark_mode_btn_color_set9"]['hover_background'] : '#073d2f',
351 + 'btn_border_color' => isset($options["dark_mode_btn_color_set9"]['border']) ? $options["dark_mode_btn_color_set9"]['border'] : '#095541',
352 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set9"]['hover_border']) ? $options["dark_mode_btn_color_set9"]['hover_border'] : '#073d2f',
229 353 ],
230 354 'set10' => [
231 355 'bg' => isset($options["dark_mode_color_set10"]) ? $options["dark_mode_color_set10"]['background'] : '#171004',
232 356 'secondary_bg' => isset($options["dark_mode_color_set10"]) ? $options["dark_mode_color_set10"]['secondary_background'] : '#211706',
@@ -240,8 +364,10 @@
240 364 'btn_text_color' => isset($options["dark_mode_btn_color_set10"]) ? $options["dark_mode_btn_color_set10"]['color'] : '#E0D2BD',
241 365 'btn_bg' => isset($options["dark_mode_btn_color_set10"]) ? $options["dark_mode_btn_color_set10"]['background'] : '#5D4010',
242 366 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set10"]) ? $options["dark_mode_btn_color_set10"]['hover_color'] : '#E0D2BD',
243 367 'btn_hover_bg' => isset($options["dark_mode_btn_color_set10"]) ? $options["dark_mode_btn_color_set10"]['hover_background'] : '#372911',
368 + 'btn_border_color' => isset($options["dark_mode_btn_color_set10"]['border']) ? $options["dark_mode_btn_color_set10"]['border'] : '#5D4010',
369 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set10"]['hover_border']) ? $options["dark_mode_btn_color_set10"]['hover_border'] : '#372911',
244 370 ],
245 371 'set11' => [
246 372 'bg' => isset($options["dark_mode_color_set11"]) ? $options["dark_mode_color_set11"]['background'] : '#19081b',
247 373 'secondary_bg' => isset($options["dark_mode_color_set11"]) ? $options["dark_mode_color_set11"]['secondary_background'] : '#210a24',
@@ -255,8 +381,10 @@
255 381 'btn_text_color' => isset($options["dark_mode_btn_color_set11"]) ? $options["dark_mode_btn_color_set11"]['color'] : '#c09dc2',
256 382 'btn_bg' => isset($options["dark_mode_btn_color_set11"]) ? $options["dark_mode_btn_color_set11"]['background'] : '#440649',
257 383 'btn_text_hover_color' => isset($options["dark_mode_btn_color_set11"]) ? $options["dark_mode_btn_color_set11"]['hover_color'] : '#c09dc2',
258 384 'btn_hover_bg' => isset($options["dark_mode_btn_color_set11"]) ? $options["dark_mode_btn_color_set11"]['hover_background'] : '#2c082f',
385 + 'btn_border_color' => isset($options["dark_mode_btn_color_set11"]['border']) ? $options["dark_mode_btn_color_set11"]['border'] : '#440649',
386 + 'btn_hover_border_color' => isset($options["dark_mode_btn_color_set11"]['hover_border']) ? $options["dark_mode_btn_color_set11"]['hover_border'] : '#2c082f',
259 387 ],
260 388 ];
261 389
262 390 $selected_set_key = isset($options['color_pallets']) ? $options['color_pallets'] : 'set1';
@@ -268,10 +396,55 @@
268 396 }
269 397 ?>
270 398 }
271 399 </style>
272 -<?php } else { ?>
273 - <script type="text/javascript" class="darkify_inline_js">(function(){var s=localStorage.darkify_admin_panel_last_state,t=localStorage.darkify_selected_theme||'set1';if(s==='1'){var h=document.documentElement;h.classList.add('darkify_dark_mode_enabled');h.classList.add('darkify-'+t);}}());</script>
400 +<?php } else {
401 + /*
402 + * `dark` on <html> is the de-facto convention a React admin themes itself
403 + * off — Tailwind's class strategy, shadcn/ui, and Darkify's own React admin
404 + * (`@custom-variant dark (&:is(.dark *))`) all key on exactly this class.
405 + *
406 + * It used to be added only on Darkify's own SPA pages, which is why a
407 + * React-based admin screen from ANOTHER plugin stayed stubbornly light while
408 + * the rest of wp-admin went dark: such an app doesn't take its colours from
409 + * the cascade at all, it reads design tokens that only switch when `dark` is
410 + * present, and that class never arrived. Mirroring Admin Panel Dark Mode
411 + * onto it here — on every admin screen, not just ours — lets any app
412 + * following the convention inherit the theme with no plugin-specific
413 + * handling on either side.
414 + *
415 + * Setting it in <head> means the very first paint is already dark; the
416 + * runtime half of the mirror lives in client_main.js so the admin-bar switch
417 + * re-themes those screens live too. The `h.classList.add('dark')` call is
418 + * emitted as a static literal in the snippet below.
419 + */
420 + /*
421 + * `d` gates this FOUC snippet on Admin Panel Dark Mode actually being ON.
422 + * It used to be implicit: with the option off this template was never
423 + * included on an admin screen. Darkify's own SPA screens now always
424 + * include it (so the admin-bar icon can toggle without a reload), so
425 + * without this check a stale `darkify_admin_panel_last_state = "1"` would
426 + * darken the screen even though the option is off.
427 + *
428 + * Nested ifs, NOT `s==='1'&&d==='1'`: this whole template is printed
429 + * through wp_kses() (see the bottom of the file), whose entity
430 + * normalization rewrites a bare `&` to `&amp;` — script content is raw
431 + * text, so `&&` would reach the browser as `&amp;&amp;` and kill the
432 + * snippet with a SyntaxError. Keep this snippet free of `&` (and `<`).
433 + */
434 + /*
435 + * Effective admin darkening for THIS screen. Block Editor Dark Mode is
436 + * independent of Admin Panel Dark Mode: the block editor darkens when Block
437 + * Editor Dark Mode is on even if Admin Panel Dark Mode is off. Reused for the
438 + * runtime gate (darkify_admin_panel_dark_enabled) below.
439 + */
440 + $darkify_screen = \function_exists('get_current_screen') ? \get_current_screen() : null;
441 + $darkify_is_block_editor = $darkify_screen && \method_exists($darkify_screen, 'is_block_editor') && $darkify_screen->is_block_editor();
442 + $darkify_block_editor_dark = !empty($options['block_editor_dark_mode']);
443 + $darkify_effective_admin_dark = (!empty($options['enable_admin_panel_dark_mode']) || ($darkify_is_block_editor && $darkify_block_editor_dark)) ? '1' : '0';
444 + $darkify_admin_dark_on = $darkify_effective_admin_dark;
445 + ?>
446 + <script type="text/javascript" class="darkify_inline_js">(function(){var s=localStorage.darkify_admin_panel_last_state,t=localStorage.darkify_selected_theme||'set1',d='<?php echo esc_attr($darkify_admin_dark_on); ?>';if(s==='1'){if(d==='1'){var h=document.documentElement;h.classList.add('darkify_dark_mode_enabled');h.classList.add('darkify-'+t);h.classList.add('dark');}}}());</script>
274 447 <style type="text/css" class="darkify_inline_css">
275 448 :root {
276 449 --darkify_dark_mode_bg: #181a1b;
277 450 --darkify_dark_mode_secondary_bg: #202324;
@@ -285,8 +458,10 @@
285 458 --darkify_dark_mode_btn_bg: #2D2D2D;
286 459 --darkify_dark_mode_btn_text_color: #BEBEBE;
287 460 --darkify_dark_mode_btn_hover_bg: #BEBEBE;
288 461 --darkify_dark_mode_btn_text_hover_color: #2D2D2D;
462 + --darkify_dark_mode_btn_border_color: #2D2D2D;
463 + --darkify_dark_mode_btn_hover_border_color: #BEBEBE;
289 464 }
290 465 </style>
291 466 <?php }
292 467 if ($enable_scrollbar_dark) {
@@ -298,11 +473,35 @@
298 473
299 474 <script type="text/javascript" class="darkify_inline_js">
300 475 var darkify_switch_unique_id = "<?php echo esc_attr($this->unique_id); ?>";
301 476 var darkify_is_this_admin_panel = "<?php echo esc_attr(is_admin() ? "1" : "0"); ?>";
477 + <?php
478 + /*
479 + * Admin Panel Dark Mode, exposed so the admin engine can refuse to darken
480 + * while the option is off. Darkify's own SPA screens load the engine even
481 + * then, so the admin-bar icon can be toggled without a reload, which means
482 + * the engine has to honour the option itself rather than relying on simply
483 + * not being enqueued.
484 + */
485 + ?>
486 + var darkify_admin_panel_dark_enabled = "<?php echo esc_attr(isset($darkify_effective_admin_dark) ? $darkify_effective_admin_dark : (!empty($options['enable_admin_panel_dark_mode']) ? '1' : '0')); ?>";
487 + <?php
488 + /*
489 + * Site-wide palette defaults for the Dark Reader admin engine, one for the
490 + * block editor and one for everything else. "auto" means "let Dark Reader
491 + * derive every colour", which is the default and the recommended value.
492 + *
493 + * These are defaults, not overrides: the editor's toolbar dropdown writes a
494 + * per-user choice to localStorage and that still wins, which is how that
495 + * control has always behaved.
496 + */
497 + ?>
498 + var darkify_admin_palette_default = "<?php echo esc_attr(!empty($options['admin_panel_palette']) ? $options['admin_panel_palette'] : 'auto'); ?>";
499 + var darkify_editor_palette_default = "<?php echo esc_attr(!empty($options['block_editor_palette']) ? $options['block_editor_palette'] : 'auto'); ?>";
302 500 var darkify_enable_default_dark_mode = "<?php echo esc_attr($enable_default_dark_mode); ?>";
303 501 var darkify_enable_os_aware = "<?php echo esc_attr($enable_os_aware); ?>";
304 502 var darkify_enable_keyboard_shortcut = "<?php echo esc_attr($enable_keyboard_shortcut); ?>";
503 + var darkify_keyboard_shortcut_keys = "<?php echo esc_attr($keyboard_shortcut_keys); ?>";
305 504 var darkify_enable_time_based_dark = "<?php echo esc_attr($enable_time_based_dark); ?>";
306 505 var darkify_time_based_dark_start = "<?php echo esc_attr($time_based_dark_start ? $time_based_dark_start : "19:00"); ?>";
307 506 var darkify_time_based_dark_stop = "<?php echo esc_attr($time_based_dark_stop ? $time_based_dark_stop : "07:00"); ?>";
308 507 var darkify_enable_switch_dragging = "<?php echo esc_attr($enable_switch_dragging); ?>";
@@ -327,17 +526,35 @@
327 526 var darkify_video_brightness_to = "<?php echo esc_attr($low_video_brightness_label); ?>";
328 527 var darkify_enable_video_grayscale = "<?php echo esc_attr($enable_video_grayscale); ?>";
329 528 var darkify_video_grayscale_to = "<?php echo esc_attr($video_grayscale_label); ?>";
330 529 var darkify_video_replacements = "<?PHP echo esc_attr($video_replacements); ?>";
331 - var darkify_allowed_elements = "<?php echo esc_attr($this->utils->generateAllowedElementsStr($options)); ?>";
332 - var darkify_allowed_elements_raw = "<?php echo esc_attr($allowed_elements); ?>";
530 + <?php
531 + /*
532 + * These four carry CSS selectors, not display text, and they are read back
533 + * by element.matches() in client_main.js. esc_attr() would HTML-encode the
534 + * selector combinators (`>` becomes `&gt;`, `&` becomes `&amp;`), and a
535 + * <script> body is raw text — the browser never decodes those back. One
536 + * encoded combinator anywhere in the list makes the whole comma-joined
537 + * selector a SyntaxError, matches() throws, and Disallowed Elements
538 + * silently stops restricting anything. Custom CSS selectors are folded into
539 + * the disallowed list automatically (see generateDisallowedElementsStr), so
540 + * a perfectly ordinary `.card > .title` rule was enough to trigger it.
541 + * darkify_js_string() emits a proper JSON string literal instead, which
542 + * keeps the selector intact and is still safe to sit inside <script>
543 + * (tags/ampersands are \u-escaped).
544 + */
545 + ?>
546 + var darkify_allowed_elements = <?php echo darkify_js_string($this->utils->generateAllowedElementsStr($options)); ?>;
547 + var darkify_allowed_elements_raw = <?php echo darkify_js_string($allowed_elements); ?>;
333 548 var darkify_allowed_elements_force_to_correct = "<?php echo esc_attr($allowed_elements_force_to_correct); ?>";
334 549
335 - var darkify_disallowed_elements = "<?php echo esc_attr($this->utils->generateDisallowedElementsStr($options, $this->external_support)); ?>";
336 - var darkify_disallowed_elements_raw = "<?php echo esc_attr($disallowed_elements); ?>";
550 + var darkify_disallowed_elements = <?php echo darkify_js_string($this->utils->generateDisallowedElementsStr($options, $this->external_support)); ?>;
551 + var darkify_disallowed_elements_raw = <?php echo darkify_js_string($disallowed_elements); ?>;
337 552 var darkify_disallowed_elements_force_to_correct = "<?php echo esc_attr($disallowed_elements_force_to_correct); ?>";
338 553
339 554 var darkify_allowed_btn_class = <?php echo json_encode($this->utils->addButtonClassByDarkify($options)); ?>;
555 +
556 + var darkify_color_overrides = <?php echo wp_json_encode($darkify_color_overrides); ?>;
340 557 </script>
341 558 <?php
342 559 $output = ob_get_clean();
343 560 $tags_allowed_in_output = array(