Child Theme Configurator - Version 1.3.0

Version Description

  • Changed CSS preview to retrieve directly from WordPress Admin instead of remote http GET to prevent caching issues.
  • Added loading icon for CSS preview.
  • Fixed JS type error on backup toggle.
  • Improved extensibility throughout.
Download this release

Release Info

Developer lilaeamedia
Plugin Icon 128x128 Child Theme Configurator
Version 1.3.0
Comparing to
See all releases

Code changes from version 1.2.3 to 1.3.0

child-theme-configurator.php CHANGED
@@ -6,7 +6,7 @@ if ( !defined('ABSPATH')) exit;
6
  Plugin Name: Child Theme Configurator
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Create a Child Theme from any installed Theme. Each CSS selector, rule and value can then be searched, previewed and modified.
9
- Version: 1.2.3
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
@@ -16,10 +16,13 @@ if ( !defined('ABSPATH')) exit;
16
  */
17
 
18
  defined('LF') or define('LF', "\n");
 
19
 
20
- require_once( 'includes/class-ctc.php' );
21
- global $chld_thm_cfg;
22
- $chld_thm_cfg = new Child_Theme_Configurator( __FILE__ );
 
 
23
 
24
  register_uninstall_hook( __FILE__ , 'child_theme_configurator_delete_plugin');
25
  function child_theme_configurator_delete_plugin() {
6
  Plugin Name: Child Theme Configurator
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Create a Child Theme from any installed Theme. Each CSS selector, rule and value can then be searched, previewed and modified.
9
+ Version: 1.3.0
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
16
  */
17
 
18
  defined('LF') or define('LF', "\n");
19
+ define('CHLD_THM_CFG_VERSION', '1.3.0');
20
 
21
+ if (is_admin()):
22
+ include_once( 'includes/class-ctc.php' );
23
+ global $chld_thm_cfg;
24
+ $chld_thm_cfg = new Child_Theme_Configurator( __FILE__ );
25
+ endif;
26
 
27
  register_uninstall_hook( __FILE__ , 'child_theme_configurator_delete_plugin');
28
  function child_theme_configurator_delete_plugin() {
css/chld-thm-cfg.css CHANGED
@@ -180,7 +180,9 @@
180
  .ctc-child-input-cell input[type="text"] {
181
  /*width:60px;*/
182
  }
183
-
 
 
184
  .ctc-child-input-cell input[type="text"].ctc-input-wide {
185
  width: 200px;
186
  }
180
  .ctc-child-input-cell input[type="text"] {
181
  /*width:60px;*/
182
  }
183
+ .ctc-select {
184
+ max-width:100%;
185
+ }
186
  .ctc-child-input-cell input[type="text"].ctc-input-wide {
187
  width: 200px;
188
  }
includes/class-ctc-css.php CHANGED
@@ -6,7 +6,7 @@ if ( !defined('ABSPATH')) exit;
6
  Class: Child_Theme_Configurator_CSS
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Handles all CSS output, parsing, normalization
9
- Version: 1.2.3
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
@@ -37,13 +37,14 @@ class Child_Theme_Configurator_CSS {
37
  var $updates; // temporary update cache
38
  var $child; // child theme slug
39
  var $parnt; // parent theme slug
 
40
  var $child_name; // child theme name
41
  var $child_author; // stylesheet author
42
  var $child_version; // stylesheet version
43
 
44
  function __construct() {
45
  // scalars
46
- $this->version = '1.2.3';
47
  $this->querykey = 0;
48
  $this->selkey = 0;
49
  $this->qskey = 0;
@@ -51,6 +52,7 @@ class Child_Theme_Configurator_CSS {
51
  $this->valkey = 0;
52
  $this->child = '';
53
  $this->parnt = '';
 
54
  $this->child_name = '';
55
  $this->child_author = 'Child Theme Configurator by Lilaea Media';
56
  $this->child_version = '1.0';
@@ -68,20 +70,10 @@ class Child_Theme_Configurator_CSS {
68
  }
69
 
70
  /*
71
- * set_property
72
- * Setter interface (scalar values only)
73
- */
74
- function set_property($prop, $value) {
75
- if (is_scalar($this->{$prop}))
76
- $this->{$prop} = $value;
77
- else return false;
78
- }
79
-
80
- /*
81
- * get_property
82
  * Getter interface (data sliced different ways depending on objname)
83
  */
84
- function get_property($objname, $params = null) {
85
  switch ($objname):
86
  case 'updates':
87
  return $this->obj_to_utf8($this->updates);
@@ -105,206 +97,60 @@ class Child_Theme_Configurator_CSS {
105
  return $this->child;
106
  case 'parnt':
107
  return $this->parnt;
 
 
108
  case 'child_name':
109
  return $this->child_name;
110
  case 'author':
111
  return $this->child_author;
112
  case 'version':
113
  return $this->child_version;
 
 
 
114
  endswitch;
115
  return false;
116
  }
117
 
118
  /*
119
- * obj_to_utf8
120
- * sets object data to UTF8
121
- * and stringifies NULLs
122
  */
123
- function obj_to_utf8($data) {
124
-
125
- if (is_object($data)) {
126
- $data = get_object_vars($data);
127
- }
128
- if (is_array($data)) {
129
- return array_map(array(&$this, __FUNCTION__), $data);
130
- }
131
- else {
132
- return is_null( $data ) ? '' : utf8_encode($data);
133
- }
134
  }
135
-
136
- /*
137
- * normalize_background
138
- * parses background shorthand value and returns
139
- * normalized rule/value pairs for each property
140
- */
141
- function normalize_background($value, &$rules, &$values){
142
- if (false !== strpos($value, 'gradient')):
143
- // only supporting linear syntax
144
- if (preg_match('#(linear\-|Microsoft\.)#', $value)):
145
- $values[] = $value;
146
- $rules[] = 'background-image';
147
- endif;
148
- else:
149
- $regex = '#(url *\([^\)]+\))#';
150
- if (preg_match($regex, $value, $matches)) $url = $matches[1];
151
- $parts = preg_split($regex, $value);
152
-
153
- if (count($parts) == 1):
154
- // this is a named color or single hex color or none
155
- $part = str_replace(' ', '', $parts[0]);
156
- $rules[] = 'none' == $part ? 'background' : 'background-color';
157
- $values[] = $part;
158
- else:
159
- $rules[] = 'background-image';
160
- $values[] = $url;
161
- if (!empty($parts[0]) && '' !== $parts[0]):
162
- $rules[] = 'background-color';
163
- $values[] = trim($parts[0]);
164
- endif;
165
- $position = array();
166
- foreach(preg_split('/ +/', trim($parts[1])) as $part):
167
- if ('' === $part) continue; // empty($part) ||
168
- if (false === strpos($part, 'repeat')):
169
- $position[] = $part;
170
- else:
171
- $rules[] = 'background-repeat';
172
- $values[] = $part;
173
- endif;
174
- endforeach;
175
- if (count($position)):
176
- $rules[] = 'background-position';
177
- $values[] = implode(' ', $position);
178
- endif;
179
  endif;
 
180
  endif;
181
  }
182
-
183
- /*
184
- * normalize_font
185
- * parses font shorthand value and returns
186
- * normalized rule/value pairs for each property
187
- */
188
- function normalize_font($value, &$rules, &$values) {
189
- $regex = '#^((\d+|bold|normal) )?((italic|normal) )?(([\d\.]+(px|r?em|%))[\/ ])?(([\d\.]+(px|r?em|%)?) )?(.+)$#is';
190
- preg_match($regex, $value, $parts);
191
- if (!empty($parts[2])):
192
- $rules[] = 'font-weight';
193
- $values[] = $parts[2];
194
- endif;
195
- if (!empty($parts[4])):
196
- $rules[] = 'font-style';
197
- $values[] = $parts[4];
198
- endif;
199
- if (!empty($parts[6])):
200
- $rules[] = 'font-size';
201
- $values[] = $parts[6];
202
- endif;
203
- if (!empty($parts[9])):
204
- $rules[] = 'line-height';
205
- $values[] = $parts[9];
206
- endif;
207
- if (!empty($parts[11])):
208
- $rules[] = 'font-family';
209
- $values[] = $parts[11];
210
- endif;
211
- }
212
-
213
- /*
214
- * normalize_margin_padding
215
- * parses margin or padding shorthand value and returns
216
- * normalized rule/value pairs for each property
217
- * TODO: reassemble into shorthand when writing CSS file
218
- */
219
- function normalize_margin_padding($rule, $value, &$rules, &$values) {
220
- $parts = preg_split("/ +/", trim($value));
221
- if (!isset($parts[1])) $parts[1] = $parts[0];
222
- if (!isset($parts[2])) $parts[2] = $parts[0];
223
- if (!isset($parts[3])) $parts[3] = $parts[1];
224
- $rules[0] = $rule . '-top';
225
- $values[0] = $parts[0];
226
- $rules[1] = $rule . '-right';
227
- $values[1] = $parts[1];
228
- $rules[2] = $rule . '-bottom';
229
- $values[2] = $parts[2];
230
- $rules[3] = $rule . '-left';
231
- $values[3] = $parts[3];
232
- }
233
-
234
- function encode_shorthand($shorthand) {
235
- $rules = '';
236
- $importantstr = ' !important';
237
- foreach (array_keys($shorthand) as $key):
238
- $important = array();
239
- $rule = array();
240
- $importantct = 0;
241
- // which sides do we have and are they important?
242
- foreach($shorthand[$key] as $side => $val):
243
- $ict = 0;
244
- $rule[$side] = trim(preg_replace('/'.$importantstr.'/', '', $val, 1, $ict));
245
- $important[$side] = $ict;
246
- $importantct += $ict;
247
- endforeach;
248
- // shorthand must have 4 explicit values and all must have same priority
249
- if (4 == count($rule) && (0 == $importantct || 4 == $importantct )):
250
- // let's try to condense the values into as few as possible, starting with the top value
251
- $parts = array();
252
- $parts[0] = $rule['top'];
253
- // if left is not the same as right, we must use all 4 values
254
- if ($rule['left'] !== $rule['right']):
255
- $parts[3] = $rule['left'];
256
- $parts[2] = $rule['bottom'];
257
- $parts[1] = $rule['right'];
258
- endif;
259
- // if top is not the same as bottom, we must use at least 3 values
260
- if ($rule['bottom'] !== $rule['top']):
261
- $parts[2] = $rule['bottom'];
262
- $parts[1] = $rule['right'];
263
- endif;
264
- // if top is not the same as right, we must use at least 2 values
265
- if ($rule['right'] !== $rule['top']):
266
- $parts[1] = $rule['right'];
267
- endif;
268
- // the order of the sides is critical: top right bottom left
269
- ksort($parts);
270
- $shorthandstr = implode(' ', $parts);
271
- // if important counter is > 0, it must be == 4, add flag
272
- $rules .= ' ' . $key . ': ' . $shorthandstr . ($importantct ? ' ' . $importantstr : '') . ';' . LF;
273
- else:
274
- // otherwise return separate rule for each side
275
- foreach ($rule as $side => $value):
276
- $rules .= ' ' . $key . '-' . $side . ': ' . $value . ($important[$side] ? $importantstr : '') . ';' . LF;
277
- endforeach;
278
- endif;
279
- endforeach;
280
- return $rules;
281
- }
282
- /*
283
- * parse_css_file
284
- * reads stylesheet to get WordPress meta data and passes rest to parse_css
285
- */
286
- function parse_css_file($template) {
287
- if (empty($this->{$template}) || !is_scalar($this->{$template})) return false;
288
- $stylesheet = get_theme_root() . '/' . $this->{$template} . '/style.css';
289
- // read parnt stylesheet
290
- if (!is_file($stylesheet)) return false;
291
- $styles = file_get_contents($stylesheet);
292
- // get theme name
293
- $regex = '#Theme Name:\s*(.+?)\n#i';
294
- preg_match($regex, $styles, $matches);
295
- if (empty($matches[1])) return false;
296
- if ('child' == $template && empty($this->child_name)) $this->set_property('child_name', $matches[1]);
297
- $this->parse_css($template, $styles);
298
  }
299
-
300
- /*
301
- * reset_updates
302
- * clears temporary update cache
303
- */
304
- function reset_updates() {
305
- $this->updates = array();
306
  }
307
-
308
  /*
309
  * update_arrays
310
  * accepts CSS properties as raw strings and normilizes into
@@ -374,6 +220,143 @@ class Child_Theme_Configurator_CSS {
374
  endif;
375
  }
376
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
377
  /*
378
  * parse_css
379
  * accepts raw CSS as text and parses into separate properties
@@ -457,12 +440,7 @@ class Child_Theme_Configurator_CSS {
457
  endforeach;
458
  endforeach;
459
  }
460
- function to_ascii($matches) {
461
- return ord($matches[0]);
462
- }
463
- function from_ascii($matches) {
464
- return chr($matches[0]);
465
- }
466
  /*
467
  * write_css
468
  * converts normalized CSS object data into stylesheet.
@@ -471,31 +449,11 @@ class Child_Theme_Configurator_CSS {
471
  * New selectors are appended to the end of each media query block.
472
  */
473
  function write_css($backup = false) {
474
- // verify write permissions
475
- $themedir = get_theme_root();
476
- if (! is_writable($themedir)) return false;
477
- $childdir = $themedir . '/' . $this->child;
478
-
479
- if (!is_dir($childdir)):
480
- if (!mkdir($childdir, 0755)) return false;
481
- endif;
482
- // add functions.php file
483
- if ($backup && !file_exists($childdir . '/functions.php')):
484
- if (false === file_put_contents($childdir . '/functions.php',
485
- "<?php\n// Exit if accessed directly\nif ( !defined('ABSPATH')) exit;\n\n/* Add custom functions below */")) return false;
486
- endif;
487
  // write new stylesheet
488
- $output = '/*' . LF;
489
- $output .= 'Theme Name: ' . $this->child_name . LF;
490
- $output .= 'Template: ' . $this->parnt . LF;
491
- $output .= 'Author: ' . $this->child_author . LF;
492
- $output .= 'Version: 1.0' . LF;
493
- $output .= 'Updated: ' . current_time('mysql') . LF;
494
- $output .= '*/' . LF . LF;
495
- $output .= '@charset "UTF-8";' . LF;
496
- $output .= '@import url(\'../' . $this->parnt . '/style.css\');' . LF;
497
- if (!empty($this->imports['child'])):
498
- foreach ($this->imports['child'] as $import):
499
  $output .= $import . ';' . LF;
500
  endforeach;
501
  endif;
@@ -537,7 +495,7 @@ class Child_Theme_Configurator_CSS {
537
  if ('base' != $query) $sel_output .= '}' . LF;
538
  if ($has_selector) $output .= $sel_output;
539
  endforeach;
540
- $stylesheet = $childdir . '/style.css';
541
  // backup current stylesheet
542
  if ($backup && is_file($stylesheet)):
543
  $timestamp = date('YmdHis', current_time('timestamp'));
@@ -548,7 +506,7 @@ class Child_Theme_Configurator_CSS {
548
  if (false === file_put_contents($stylesheet, $output)) return false;
549
  return true;
550
  }
551
-
552
  /*
553
  * add_vendor_rules
554
  * Applies vendor prefixes to rules/values
@@ -586,28 +544,175 @@ class Child_Theme_Configurator_CSS {
586
  endforeach;
587
  $org = 'to ' . implode(' ', $dirs);
588
  endif;
589
- $rules .= ' background-image: linear-gradient(' . $org . ', '
590
- . $gradient['color1'] . ', ' . $gradient['color2'] . ')' . $importantstr . ';' . LF;
591
-
592
- // legacy webkit gradient - we'll add if there is demand
593
- // '-webkit-gradient(linear,' .$origin . ', ' . $color1 . ', '. $color2 . ')';
594
-
595
- // MS filter gradient
596
- $type = (in_array($gradient['origin'], array('left', 'right', '0deg', '180deg')) ? 1 : 0);
597
- $color1 = preg_replace("/^#/", '#00', $gradient['color1']);
598
- $rules .= ' filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' . $type . ', StartColorStr="'
599
- . strtoupper($color1) . '", EndColorStr="' . strtoupper($gradient['color2']) . '")' . $importantstr . ';' . LF;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
600
  else:
601
- // url or other value
602
- $rules .= ' ' . $rule . ': ' . $value . $importantstr . ';' . LF;
 
 
603
  endif;
604
- else:
605
- $rule = preg_replace_callback("/\d+/", array($this, 'from_ascii'), $rule);
606
- $rules .= ' ' . $rule . ': ' . $value . $importantstr . ';' . LF;
607
- endif;
608
  return $rules;
609
  }
610
-
611
  /*
612
  * encode_gradient
613
  * Normalize linear gradients from a bazillion formats into standard CTC syntax:
@@ -685,159 +790,6 @@ class Child_Theme_Configurator_CSS {
685
  return false;
686
  }
687
 
688
- /*
689
- * parse_css_input
690
- * Normalize raw user CSS input so that the parser can read it.
691
- * TODO: this is a stub for future use
692
- */
693
- function parse_css_input($styles) {
694
- return $styles;
695
- }
696
-
697
- /*
698
- * parse_post_data
699
- * Parse user form input into separate properties and pass to update_arrays
700
- */
701
- function parse_post_data() {
702
- if (isset($_POST['ctc_new_selectors'])):
703
-
704
- $this->parse_css('child', LF . $this->parse_css_input($_POST['ctc_new_selectors']),
705
- (isset($_POST['ctc_sel_ovrd_query'])?trim($_POST['ctc_sel_ovrd_query']):null), false);
706
- elseif (isset($_POST['ctc_child_imports'])):
707
- $this->parse_css('child', $_POST['ctc_child_imports']);
708
- else:
709
- $newselector = isset($_POST['ctc_rewrite_selector']) ? sanitize_text_field(stripslashes($_POST['ctc_rewrite_selector'])) : NULL;
710
- // set the custom sequence value
711
- foreach (preg_grep('#^ctc_ovrd_child_seq_#', array_keys($_POST)) as $post_key):
712
- if (preg_match('#^ctc_ovrd_child_seq_(\d+)$#', $post_key, $matches)):
713
- $qsid = $matches[1];
714
- $this->dict_seq[$qsid] = intval($_POST[$post_key]);
715
- endif;
716
- endforeach;
717
- $parts = array();
718
- foreach (preg_grep('#^ctc_(ovrd|\d+)_child#', array_keys($_POST)) as $post_key):
719
- if (preg_match('#^ctc_(ovrd|\d+)_child_([\w\-]+?)_(\d+?)(_(.+))?$#', $post_key, $matches)):
720
- $valid = $matches[1];
721
- $rule = $matches[2];
722
- if (null == $rule || !isset($this->dict_rule[$rule])) continue;
723
- $ruleid = $this->dict_rule[$rule];
724
- $qsid = $matches[3];
725
- $value = sanitize_text_field(stripslashes($_POST[$post_key]));
726
- $important = $this->is_important($value);
727
- if (!empty($_POST['ctc_' . $valid . '_child_' . $rule . '_i_' . $qsid])) $important = 1;
728
-
729
- $selarr = $this->denorm_query_sel($qsid);
730
- if (!empty($matches[5])):
731
- $parts[$qsid][$rule][$matches[5]] = $value;
732
- $parts[$qsid][$rule]['important'] = $important;
733
- $parts[$qsid][$rule]['query'] = $selarr['query'];
734
- $parts[$qsid][$rule]['selector'] = $selarr['selector'];
735
- else:
736
- if ($newselector && $newselector != $selarr['selector']):
737
- // If this is a renamed selector, add new selector to array
738
- // and clear original child selector values.
739
- // Passing the sequence in the last argument serves two purposes:
740
- // 1. sets sequence for new renamed selector.
741
- // 2. tells the update_arrays function to flag this as a
742
- // renamed selector to pass back in result array.
743
- $this->update_arrays('child', $selarr['query'], $newselector,
744
- $rule, trim($value), $important, $this->dict_seq[$qsid]);
745
- $this->update_arrays('child', $selarr['query'], $selarr['selector'], $rule, '');
746
- else:
747
- // Otherwise, just update with the new values:
748
- $this->update_arrays('child', $selarr['query'], $selarr['selector'],
749
- $rule, trim($value), $important);
750
- endif;
751
- endif;
752
- endif;
753
- endforeach;
754
- foreach ($parts as $qsid => $rule_arr):
755
- foreach ($rule_arr as $rule => $rule_part):
756
- if ('background' == $rule):
757
- $value = $rule_part['background_url'];
758
- elseif ('background-image' == $rule):
759
- if (empty($rule_part['background_url'])):
760
- if (empty($rule_part['background_color2'])):
761
- $value = '';
762
- else:
763
- $value = implode(':', array(
764
- $rule_part['background_origin'],
765
- $rule_part['background_color1'], '0%',
766
- $rule_part['background_color2'], '100%'
767
- ));
768
- endif;
769
- else:
770
- $value = $rule_part['background_url'];
771
- endif;
772
- elseif (preg_match('#^border(\-(top|right|bottom|left))?$#', $rule)):
773
- $value = implode(' ', array(
774
- $rule_part['border_width'],
775
- $rule_part['border_style'],
776
- $rule_part['border_color']
777
- ));
778
- else:
779
- $value = '';
780
- endif;
781
- if ($newselector && $newselector != $rule_part['selector']):
782
- $this->update_arrays('child', $rule_part['query'], $newselector,
783
- $rule, trim($value), $rule_part['important'], $this->dict_seq[$qsid]);
784
- $this->update_arrays('child', $rule_part['query'], $rule_part['selector'], $rule, '');
785
- else:
786
- $this->update_arrays('child', $rule_part['query'], $rule_part['selector'],
787
- $rule, trim($value), $rule_part['important']);
788
- endif;
789
- endforeach;
790
- endforeach;
791
- endif;
792
- }
793
-
794
- /*
795
- * is_important
796
- * Strip important flag from value ref and return boolean
797
- * Value is updated because it is a ref
798
- */
799
- function is_important(&$value) {
800
- $important = 0;
801
- $value = trim(str_ireplace('!important', '', $value, $important));
802
- return $important;
803
- }
804
-
805
- /*
806
- * sort_queries
807
- * De-normalize query data and return array sorted as follows:
808
- * base
809
- * @media max-width queries in descending order
810
- * other @media queries in no particular order
811
- * @media min-width queries in ascending order
812
- */
813
- function sort_queries() {
814
- $queries = array();
815
- $queryarr = array_flip($this->dict_query);
816
- foreach (array_keys($this->sel_ndx) as $queryid):
817
- $query = $queryarr[$queryid];
818
- if ('base' == $query):
819
- $queries['base'] = -999999;
820
- continue;
821
- endif;
822
- if (preg_match("/((min|max)(\-device)?\-width)\s*:\s*(\d+)/", $query, $matches)):
823
- $queries[$query] = 'min-width' == $matches[1] ? $matches[4] : -$matches[4];
824
- else:
825
- $queries[$query] = $queryid - 10000;
826
- endif;
827
- endforeach;
828
- asort($queries);
829
- return $queries;
830
- }
831
-
832
- // sort selectors based on dict_seq if exists, otherwise qsid
833
- function cmp_seq($a, $b) {
834
- $cmpa = isset($this->dict_seq[$a])?$this->dict_seq[$a]:$a;
835
- $cmpb = isset($this->dict_seq[$b])?$this->dict_seq[$b]:$b;
836
- if ($cmpa == $cmpb) return 0;
837
- return ($cmpa < $cmpb) ? -1 : 1;
838
- }
839
-
840
-
841
  /*
842
  * denorm_rule_val
843
  * Return array of unique values corresponding to specific rule
@@ -933,5 +885,77 @@ class Child_Theme_Configurator_CSS {
933
  endforeach;
934
  return empty($query) ? $sel_ndx_norm : $sel_ndx_norm[$query];
935
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
936
  }
937
  ?>
6
  Class: Child_Theme_Configurator_CSS
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Handles all CSS output, parsing, normalization
9
+ Version: 1.3.0
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
37
  var $updates; // temporary update cache
38
  var $child; // child theme slug
39
  var $parnt; // parent theme slug
40
+ var $configtype; // theme or plugin extension
41
  var $child_name; // child theme name
42
  var $child_author; // stylesheet author
43
  var $child_version; // stylesheet version
44
 
45
  function __construct() {
46
  // scalars
47
+ $this->version = '1.3.0';
48
  $this->querykey = 0;
49
  $this->selkey = 0;
50
  $this->qskey = 0;
52
  $this->valkey = 0;
53
  $this->child = '';
54
  $this->parnt = '';
55
+ $this->configtype = 'theme';
56
  $this->child_name = '';
57
  $this->child_author = 'Child Theme Configurator by Lilaea Media';
58
  $this->child_version = '1.0';
70
  }
71
 
72
  /*
73
+ * get_prop
 
 
 
 
 
 
 
 
 
 
74
  * Getter interface (data sliced different ways depending on objname)
75
  */
76
+ function get_prop($objname, $params = null) {
77
  switch ($objname):
78
  case 'updates':
79
  return $this->obj_to_utf8($this->updates);
97
  return $this->child;
98
  case 'parnt':
99
  return $this->parnt;
100
+ case 'configtype':
101
+ return $this->configtype;
102
  case 'child_name':
103
  return $this->child_name;
104
  case 'author':
105
  return $this->child_author;
106
  case 'version':
107
  return $this->child_version;
108
+ case 'preview':
109
+ $template = (empty($params['key']) || 'child' == $params['key']) ? 'child' : 'parnt';
110
+ return $this->get_raw_css($template);
111
  endswitch;
112
  return false;
113
  }
114
 
115
  /*
116
+ * set_prop
117
+ * Setter interface (scalar values only)
 
118
  */
119
+ function set_prop($prop, $value) {
120
+ if (is_scalar($this->{$prop}))
121
+ $this->{$prop} = $value;
122
+ else return false;
 
 
 
 
 
 
 
123
  }
124
+
125
+ function get_raw_css($template = 'child') {
126
+ if ($styles = $this->read_stylesheet($template)):
127
+ if (preg_match("/\}[\w\#\.]/", $styles)): // prettify compressed CSS
128
+ $styles = preg_replace("/\*\/\s*/s", "*/\n", $styles); // end comment
129
+ $styles = preg_replace("/\{\s*/s", " {\n ", $styles); // open brace
130
+ $styles = preg_replace("/;\s*/s", ";\n ", $styles); // semicolon
131
+ $styles = preg_replace("/\s*\}\s*/s", "\n}\n", $styles); // close brace
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
132
  endif;
133
+ return $styles;
134
  endif;
135
  }
136
+
137
+ function get_css_header() {
138
+ $parnt = $this->get_prop('parnt');
139
+ return '/*' . LF
140
+ . 'Theme Name: ' . $this->get_prop('child_name') . LF
141
+ . 'Template: ' . $parnt . LF
142
+ . 'Author: ' . $this->get_prop('author'). LF
143
+ . 'Version: ' . $this->get_prop('version') . LF
144
+ . 'Updated: ' . current_time('mysql') . LF
145
+ . '*/' . LF . LF
146
+ . '@charset "UTF-8";' . LF
147
+ . '@import url(\'../' . $parnt . '/style.css\');' . LF;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  }
149
+
150
+ function get_child_target($file = 'style.css') {
151
+ return get_theme_root() . '/' . $this->get_prop('child') . '/' . $file;
 
 
 
 
152
  }
153
+
154
  /*
155
  * update_arrays
156
  * accepts CSS properties as raw strings and normilizes into
220
  endif;
221
  }
222
 
223
+ /*
224
+ * reset_updates
225
+ * clears temporary update cache
226
+ */
227
+ function reset_updates() {
228
+ $this->updates = array();
229
+ }
230
+
231
+ function read_stylesheet($template = 'child') {
232
+ $source = $this->get_prop($template);
233
+ if (empty($source) || !is_scalar($source)) return false;
234
+ $stylesheet = apply_filters('chld_thm_cfg_' . $template, get_theme_root() . '/' . $source . '/style.css', $this);
235
+ // read stylesheet
236
+ if (!is_file($stylesheet)) return false;
237
+ return @file_get_contents($stylesheet);
238
+ }
239
+
240
+ /*
241
+ * parse_post_data
242
+ * Parse user form input into separate properties and pass to update_arrays
243
+ */
244
+ function parse_post_data() {
245
+ if (isset($_POST['ctc_new_selectors'])):
246
+
247
+ $this->parse_css('child', LF . $this->parse_css_input($_POST['ctc_new_selectors']),
248
+ (isset($_POST['ctc_sel_ovrd_query'])?trim($_POST['ctc_sel_ovrd_query']):null), false);
249
+ elseif (isset($_POST['ctc_child_imports'])):
250
+ $this->parse_css('child', $_POST['ctc_child_imports']);
251
+ else:
252
+ $newselector = isset($_POST['ctc_rewrite_selector']) ? sanitize_text_field(stripslashes($_POST['ctc_rewrite_selector'])) : NULL;
253
+ // set the custom sequence value
254
+ foreach (preg_grep('#^ctc_ovrd_child_seq_#', array_keys($_POST)) as $post_key):
255
+ if (preg_match('#^ctc_ovrd_child_seq_(\d+)$#', $post_key, $matches)):
256
+ $qsid = $matches[1];
257
+ $this->dict_seq[$qsid] = intval($_POST[$post_key]);
258
+ endif;
259
+ endforeach;
260
+ $parts = array();
261
+ foreach (preg_grep('#^ctc_(ovrd|\d+)_child#', array_keys($_POST)) as $post_key):
262
+ if (preg_match('#^ctc_(ovrd|\d+)_child_([\w\-]+?)_(\d+?)(_(.+))?$#', $post_key, $matches)):
263
+ $valid = $matches[1];
264
+ $rule = $matches[2];
265
+ if (null == $rule || !isset($this->dict_rule[$rule])) continue;
266
+ $ruleid = $this->dict_rule[$rule];
267
+ $qsid = $matches[3];
268
+ $value = sanitize_text_field(stripslashes($_POST[$post_key]));
269
+ $important = $this->is_important($value);
270
+ if (!empty($_POST['ctc_' . $valid . '_child_' . $rule . '_i_' . $qsid])) $important = 1;
271
+
272
+ $selarr = $this->denorm_query_sel($qsid);
273
+ if (!empty($matches[5])):
274
+ $parts[$qsid][$rule][$matches[5]] = $value;
275
+ $parts[$qsid][$rule]['important'] = $important;
276
+ $parts[$qsid][$rule]['query'] = $selarr['query'];
277
+ $parts[$qsid][$rule]['selector'] = $selarr['selector'];
278
+ else:
279
+ if ($newselector && $newselector != $selarr['selector']):
280
+ // If this is a renamed selector, add new selector to array
281
+ // and clear original child selector values.
282
+ // Passing the sequence in the last argument serves two purposes:
283
+ // 1. sets sequence for new renamed selector.
284
+ // 2. tells the update_arrays function to flag this as a
285
+ // renamed selector to pass back in result array.
286
+ $this->update_arrays('child', $selarr['query'], $newselector,
287
+ $rule, trim($value), $important, $this->dict_seq[$qsid]);
288
+ $this->update_arrays('child', $selarr['query'], $selarr['selector'], $rule, '');
289
+ else:
290
+ // Otherwise, just update with the new values:
291
+ $this->update_arrays('child', $selarr['query'], $selarr['selector'],
292
+ $rule, trim($value), $important);
293
+ endif;
294
+ endif;
295
+ endif;
296
+ endforeach;
297
+ foreach ($parts as $qsid => $rule_arr):
298
+ foreach ($rule_arr as $rule => $rule_part):
299
+ if ('background' == $rule):
300
+ $value = $rule_part['background_url'];
301
+ elseif ('background-image' == $rule):
302
+ if (empty($rule_part['background_url'])):
303
+ if (empty($rule_part['background_color2'])):
304
+ $value = '';
305
+ else:
306
+ $value = implode(':', array(
307
+ $rule_part['background_origin'],
308
+ $rule_part['background_color1'], '0%',
309
+ $rule_part['background_color2'], '100%'
310
+ ));
311
+ endif;
312
+ else:
313
+ $value = $rule_part['background_url'];
314
+ endif;
315
+ elseif (preg_match('#^border(\-(top|right|bottom|left))?$#', $rule)):
316
+ $value = implode(' ', array(
317
+ $rule_part['border_width'],
318
+ $rule_part['border_style'],
319
+ $rule_part['border_color']
320
+ ));
321
+ else:
322
+ $value = '';
323
+ endif;
324
+ if ($newselector && $newselector != $rule_part['selector']):
325
+ $this->update_arrays('child', $rule_part['query'], $newselector,
326
+ $rule, trim($value), $rule_part['important'], $this->dict_seq[$qsid]);
327
+ $this->update_arrays('child', $rule_part['query'], $rule_part['selector'], $rule, '');
328
+ else:
329
+ $this->update_arrays('child', $rule_part['query'], $rule_part['selector'],
330
+ $rule, trim($value), $rule_part['important']);
331
+ endif;
332
+ endforeach;
333
+ endforeach;
334
+ endif;
335
+ }
336
+
337
+ /*
338
+ * parse_css_input
339
+ * Normalize raw user CSS input so that the parser can read it.
340
+ * TODO: this is a stub for future use
341
+ */
342
+ function parse_css_input($styles) {
343
+ return $styles;
344
+ }
345
+
346
+ /*
347
+ * parse_css_file
348
+ * reads stylesheet to get WordPress meta data and passes rest to parse_css
349
+ */
350
+ function parse_css_file($template) {
351
+ $styles = $this->read_stylesheet($template);
352
+ // get theme name
353
+ $regex = '#Theme Name:\s*(.+?)\n#i';
354
+ preg_match($regex, $styles, $matches);
355
+ $child_name = $this->get_prop('child_name');
356
+ if (!empty($matches[1]) && 'child' == $template && empty($child_name)) $this->set_prop('child_name', $matches[1]);
357
+ $this->parse_css($template, $styles);
358
+ }
359
+
360
  /*
361
  * parse_css
362
  * accepts raw CSS as text and parses into separate properties
440
  endforeach;
441
  endforeach;
442
  }
443
+
 
 
 
 
 
444
  /*
445
  * write_css
446
  * converts normalized CSS object data into stylesheet.
449
  * New selectors are appended to the end of each media query block.
450
  */
451
  function write_css($backup = false) {
 
 
 
 
 
 
 
 
 
 
 
 
 
452
  // write new stylesheet
453
+ $output = apply_filters('chld_thm_cfg_css_header', $this->get_css_header(), $this);
454
+ $imports = $this->get_prop('imports');
455
+ if (!empty($imports)):
456
+ foreach ($imports as $import):
 
 
 
 
 
 
 
457
  $output .= $import . ';' . LF;
458
  endforeach;
459
  endif;
495
  if ('base' != $query) $sel_output .= '}' . LF;
496
  if ($has_selector) $output .= $sel_output;
497
  endforeach;
498
+ $stylesheet = apply_filters('chld_thm_cfg_target', $this->get_child_target(), $this);
499
  // backup current stylesheet
500
  if ($backup && is_file($stylesheet)):
501
  $timestamp = date('YmdHis', current_time('timestamp'));
506
  if (false === file_put_contents($stylesheet, $output)) return false;
507
  return true;
508
  }
509
+
510
  /*
511
  * add_vendor_rules
512
  * Applies vendor prefixes to rules/values
544
  endforeach;
545
  $org = 'to ' . implode(' ', $dirs);
546
  endif;
547
+ $rules .= ' background-image: linear-gradient(' . $org . ', '
548
+ . $gradient['color1'] . ', ' . $gradient['color2'] . ')' . $importantstr . ';' . LF;
549
+
550
+ // legacy webkit gradient - we'll add if there is demand
551
+ // '-webkit-gradient(linear,' .$origin . ', ' . $color1 . ', '. $color2 . ')';
552
+
553
+ // MS filter gradient
554
+ $type = (in_array($gradient['origin'], array('left', 'right', '0deg', '180deg')) ? 1 : 0);
555
+ $color1 = preg_replace("/^#/", '#00', $gradient['color1']);
556
+ $rules .= ' filter: progid:DXImageTransform.Microsoft.Gradient(GradientType=' . $type . ', StartColorStr="'
557
+ . strtoupper($color1) . '", EndColorStr="' . strtoupper($gradient['color2']) . '")' . $importantstr . ';' . LF;
558
+ else:
559
+ // url or other value
560
+ $rules .= ' ' . $rule . ': ' . $value . $importantstr . ';' . LF;
561
+ endif;
562
+ else:
563
+ $rule = preg_replace_callback("/\d+/", array($this, 'from_ascii'), $rule);
564
+ $rules .= ' ' . $rule . ': ' . $value . $importantstr . ';' . LF;
565
+ endif;
566
+ return $rules;
567
+ }
568
+
569
+ /*
570
+ * normalize_background
571
+ * parses background shorthand value and returns
572
+ * normalized rule/value pairs for each property
573
+ */
574
+ function normalize_background($value, &$rules, &$values){
575
+ if (false !== strpos($value, 'gradient')):
576
+ // only supporting linear syntax
577
+ if (preg_match('#(linear\-|Microsoft\.)#', $value)):
578
+ $values[] = $value;
579
+ $rules[] = 'background-image';
580
+ endif;
581
+ else:
582
+ $regex = '#(url *\([^\)]+\))#';
583
+ if (preg_match($regex, $value, $matches)) $url = $matches[1];
584
+ $parts = preg_split($regex, $value);
585
+
586
+ if (count($parts) == 1):
587
+ // this is a named color or single hex color or none
588
+ $part = str_replace(' ', '', $parts[0]);
589
+ $rules[] = 'none' == $part ? 'background' : 'background-color';
590
+ $values[] = $part;
591
+ else:
592
+ $rules[] = 'background-image';
593
+ $values[] = $url;
594
+ if (!empty($parts[0]) && '' !== $parts[0]):
595
+ $rules[] = 'background-color';
596
+ $values[] = trim($parts[0]);
597
+ endif;
598
+ $position = array();
599
+ foreach(preg_split('/ +/', trim($parts[1])) as $part):
600
+ if ('' === $part) continue; // empty($part) ||
601
+ if (false === strpos($part, 'repeat')):
602
+ $position[] = $part;
603
+ else:
604
+ $rules[] = 'background-repeat';
605
+ $values[] = $part;
606
+ endif;
607
+ endforeach;
608
+ if (count($position)):
609
+ $rules[] = 'background-position';
610
+ $values[] = implode(' ', $position);
611
+ endif;
612
+ endif;
613
+ endif;
614
+ }
615
+
616
+ /*
617
+ * normalize_font
618
+ * parses font shorthand value and returns
619
+ * normalized rule/value pairs for each property
620
+ */
621
+ function normalize_font($value, &$rules, &$values) {
622
+ $regex = '#^((\d+|bold|normal) )?((italic|normal) )?(([\d\.]+(px|r?em|%))[\/ ])?(([\d\.]+(px|r?em|%)?) )?(.+)$#is';
623
+ preg_match($regex, $value, $parts);
624
+ if (!empty($parts[2])):
625
+ $rules[] = 'font-weight';
626
+ $values[] = $parts[2];
627
+ endif;
628
+ if (!empty($parts[4])):
629
+ $rules[] = 'font-style';
630
+ $values[] = $parts[4];
631
+ endif;
632
+ if (!empty($parts[6])):
633
+ $rules[] = 'font-size';
634
+ $values[] = $parts[6];
635
+ endif;
636
+ if (!empty($parts[9])):
637
+ $rules[] = 'line-height';
638
+ $values[] = $parts[9];
639
+ endif;
640
+ if (!empty($parts[11])):
641
+ $rules[] = 'font-family';
642
+ $values[] = $parts[11];
643
+ endif;
644
+ }
645
+
646
+ /*
647
+ * normalize_margin_padding
648
+ * parses margin or padding shorthand value and returns
649
+ * normalized rule/value pairs for each property
650
+ * TODO: reassemble into shorthand when writing CSS file
651
+ */
652
+ function normalize_margin_padding($rule, $value, &$rules, &$values) {
653
+ $parts = preg_split("/ +/", trim($value));
654
+ if (!isset($parts[1])) $parts[1] = $parts[0];
655
+ if (!isset($parts[2])) $parts[2] = $parts[0];
656
+ if (!isset($parts[3])) $parts[3] = $parts[1];
657
+ $rules[0] = $rule . '-top';
658
+ $values[0] = $parts[0];
659
+ $rules[1] = $rule . '-right';
660
+ $values[1] = $parts[1];
661
+ $rules[2] = $rule . '-bottom';
662
+ $values[2] = $parts[2];
663
+ $rules[3] = $rule . '-left';
664
+ $values[3] = $parts[3];
665
+ }
666
+
667
+ function encode_shorthand($shorthand) {
668
+ $rules = '';
669
+ $importantstr = ' !important';
670
+ foreach (array_keys($shorthand) as $key):
671
+ $important = array();
672
+ $rule = array();
673
+ $importantct = 0;
674
+ // which sides do we have and are they important?
675
+ foreach($shorthand[$key] as $side => $val):
676
+ $ict = 0;
677
+ $rule[$side] = trim(preg_replace('/'.$importantstr.'/', '', $val, 1, $ict));
678
+ $important[$side] = $ict;
679
+ $importantct += $ict;
680
+ endforeach;
681
+ // shorthand must have 4 explicit values and all must have same priority
682
+ if (4 == count($rule) && (0 == $importantct || 4 == $importantct )):
683
+ // let's try to condense the values into as few as possible, starting with the top value
684
+ $parts = array();
685
+ $parts[0] = $rule['top'];
686
+ // if left is not the same as right, we must use all 4 values
687
+ if ($rule['left'] !== $rule['right']):
688
+ $parts[3] = $rule['left'];
689
+ $parts[2] = $rule['bottom'];
690
+ $parts[1] = $rule['right'];
691
+ endif;
692
+ // if top is not the same as bottom, we must use at least 3 values
693
+ if ($rule['bottom'] !== $rule['top']):
694
+ $parts[2] = $rule['bottom'];
695
+ $parts[1] = $rule['right'];
696
+ endif;
697
+ // if top is not the same as right, we must use at least 2 values
698
+ if ($rule['right'] !== $rule['top']):
699
+ $parts[1] = $rule['right'];
700
+ endif;
701
+ // the order of the sides is critical: top right bottom left
702
+ ksort($parts);
703
+ $shorthandstr = implode(' ', $parts);
704
+ // if important counter is > 0, it must be == 4, add flag
705
+ $rules .= ' ' . $key . ': ' . $shorthandstr . ($importantct ? ' ' . $importantstr : '') . ';' . LF;
706
  else:
707
+ // otherwise return separate rule for each side
708
+ foreach ($rule as $side => $value):
709
+ $rules .= ' ' . $key . '-' . $side . ': ' . $value . ($important[$side] ? $importantstr : '') . ';' . LF;
710
+ endforeach;
711
  endif;
712
+ endforeach;
 
 
 
713
  return $rules;
714
  }
715
+
716
  /*
717
  * encode_gradient
718
  * Normalize linear gradients from a bazillion formats into standard CTC syntax:
790
  return false;
791
  }
792
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
793
  /*
794
  * denorm_rule_val
795
  * Return array of unique values corresponding to specific rule
885
  endforeach;
886
  return empty($query) ? $sel_ndx_norm : $sel_ndx_norm[$query];
887
  }
888
+
889
+ /*
890
+ * is_important
891
+ * Strip important flag from value ref and return boolean
892
+ * Value is updated because it is a ref
893
+ */
894
+ function is_important(&$value) {
895
+ $important = 0;
896
+ $value = trim(str_ireplace('!important', '', $value, $important));
897
+ return $important;
898
+ }
899
+
900
+ /*
901
+ * sort_queries
902
+ * De-normalize query data and return array sorted as follows:
903
+ * base
904
+ * @media max-width queries in descending order
905
+ * other @media queries in no particular order
906
+ * @media min-width queries in ascending order
907
+ */
908
+ function sort_queries() {
909
+ $queries = array();
910
+ $queryarr = array_flip($this->dict_query);
911
+ foreach (array_keys($this->sel_ndx) as $queryid):
912
+ $query = $queryarr[$queryid];
913
+ if ('base' == $query):
914
+ $queries['base'] = -999999;
915
+ continue;
916
+ endif;
917
+ if (preg_match("/((min|max)(\-device)?\-width)\s*:\s*(\d+)/", $query, $matches)):
918
+ $queries[$query] = 'min-width' == $matches[1] ? $matches[4] : -$matches[4];
919
+ else:
920
+ $queries[$query] = $queryid - 10000;
921
+ endif;
922
+ endforeach;
923
+ asort($queries);
924
+ return $queries;
925
+ }
926
+
927
+ // sort selectors based on dict_seq if exists, otherwise qsid
928
+ function cmp_seq($a, $b) {
929
+ $cmpa = isset($this->dict_seq[$a])?$this->dict_seq[$a]:$a;
930
+ $cmpb = isset($this->dict_seq[$b])?$this->dict_seq[$b]:$b;
931
+ if ($cmpa == $cmpb) return 0;
932
+ return ($cmpa < $cmpb) ? -1 : 1;
933
+ }
934
+
935
+ /*
936
+ * obj_to_utf8
937
+ * sets object data to UTF8
938
+ * and stringifies NULLs
939
+ */
940
+ function obj_to_utf8($data) {
941
+
942
+ if (is_object($data)) {
943
+ $data = get_object_vars($data);
944
+ }
945
+ if (is_array($data)) {
946
+ return array_map(array(&$this, __FUNCTION__), $data);
947
+ }
948
+ else {
949
+ return is_null( $data ) ? '' : utf8_encode($data);
950
+ }
951
+ }
952
+
953
+ function to_ascii($matches) {
954
+ return ord($matches[0]);
955
+ }
956
+
957
+ function from_ascii($matches) {
958
+ return chr($matches[0]);
959
+ }
960
  }
961
  ?>
includes/class-ctc-ui.php CHANGED
@@ -5,7 +5,7 @@ if ( !defined('ABSPATH')) exit;
5
  Class: Child_Theme_Configurator_UI
6
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
7
  Description: Handles the plugin User Interface
8
- Version: 1.2.3
9
  Author: Lilaea Media
10
  Author URI: http://www.lilaeamedia.com/
11
  Text Domain: chld_thm_cfg
@@ -25,10 +25,11 @@ class Child_Theme_Configurator_UI {
25
  global $chld_thm_cfg;
26
  $css = $chld_thm_cfg->css;
27
  $themes = $chld_thm_cfg->themes;
28
- $parent = $css->get_property('parnt');
29
- $child = $css->get_property('child');
 
30
  $hidechild = (count($themes['child']) ? '' : 'style="display:none"');
31
- $imports = $css->get_property('imports');
32
  $id = 0;
33
  ?>
34
 
@@ -57,9 +58,9 @@ class Child_Theme_Configurator_UI {
57
  class="nav-tab<?php echo 'view_child_options' == $active_tab ? ' nav-tab-active' : ''; ?>" <?php echo $hidechild; ?>>
58
  <?php _e('View Child CSS', 'chld_thm_cfg'); ?>
59
  </a> <a id="view_parnt_options" href="?page=<?php echo $chld_thm_cfg->menuName; ?>&amp;tab=view_parnt_options"
60
- class="nav-tab<?php echo 'view_parnt_options' == $active_tab ? ' nav-tab-active' : ''; ?>">
61
  <?php _e('View Parent CSS', 'chld_thm_cfg'); ?>
62
- </a> </h2>
63
  <div class="ctc-option-panel-container">
64
  <div id="parent_child_options_panel" class="ctc-option-panel<?php echo 'parent_child_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>">
65
  <form id="ctc_load_form" method="post" action="">
@@ -103,7 +104,7 @@ class Child_Theme_Configurator_UI {
103
  <label>&nbsp;</label>
104
  </div>
105
  <div class="ctc-input-cell" >
106
- <input class="ctc_text" id="ctc_child_template" name="ctc_child_template" type="text" placeholder="theme slug" autocomplete="off"/>
107
  </div>
108
  <div class="ctc-input-cell">
109
  <select class="ctc-select" id="ctc_theme_child" name="ctc_theme_child" <?php echo $hidechild; ?>>
@@ -119,9 +120,10 @@ class Child_Theme_Configurator_UI {
119
  </div>
120
  <div class="ctc-input-cell">
121
  <input class="ctc_text" id="ctc_child_name" name="ctc_child_name" type="text"
122
- value="<?php echo esc_attr($css->get_property('child_name')); ?>" placeholder="theme name" autocomplete="off" />
123
  </div>
124
  </div>
 
125
  <div class="ctc-input-row clearfix" id="input_row_child_template">
126
  <div class="ctc-input-cell">
127
  <label>
@@ -130,7 +132,7 @@ class Child_Theme_Configurator_UI {
130
  </div>
131
  <div class="ctc-input-cell">
132
  <input class="ctc_text" id="ctc_child_author" name="ctc_child_author" type="text"
133
- value="<?php echo esc_attr($css->get_property('author')); ?>" placeholder="author" autocomplete="off" />
134
  </div>
135
  </div>
136
  <div class="ctc-input-row clearfix" id="input_row_child_template">
@@ -141,7 +143,7 @@ class Child_Theme_Configurator_UI {
141
  </div>
142
  <div class="ctc-input-cell">
143
  <input class="ctc_text" id="ctc_child_version" name="ctc_child_version" type="text"
144
- value="<?php echo esc_attr($css->get_property('version')); ?>" placeholder="version" autocomplete="off" />
145
  </div>
146
  </div>
147
  <div class="ctc-input-row clearfix" id="input_row_child_template">
@@ -161,7 +163,7 @@ class Child_Theme_Configurator_UI {
161
  </div>
162
  <div class="ctc-input-cell">
163
  <input class="ctc_submit button button-primary" id="ctc_load_styles" name="ctc_load_styles" type="submit"
164
- value="<?php _e('Generate Child Theme', 'chld_thm_cfg'); ?>" disabled />
165
  </div>
166
  </div>
167
  </form>
@@ -309,7 +311,9 @@ class Child_Theme_Configurator_UI {
309
  </div>
310
  <div id="view_child_options_panel"
311
  class="ctc-option-panel<?php echo 'view_child_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>" <?php echo $hidechild; ?>> </div>
312
- <div id="view_parnt_options_panel" class="ctc-option-panel<?php echo 'view_parnt_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>"> </div>
 
 
313
  </div>
314
  </div>
315
  <style type="text/css">
@@ -345,8 +349,8 @@ class Child_Theme_Configurator_UI {
345
  echo '</ul></div>' . LF;
346
  elseif (isset($_GET['updated'])):
347
  echo '<div class="updated"><p>' . LF
348
- . sprintf(__('Child Theme <strong>%s</strong> has been generated successfully.', 'chld_thm_cfg'),
349
- $chld_thm_cfg->css->get_property('child_name')) . LF
350
  . '</p></div>' . LF;
351
  endif;
352
  }
5
  Class: Child_Theme_Configurator_UI
6
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
7
  Description: Handles the plugin User Interface
8
+ Version: 1.3.0
9
  Author: Lilaea Media
10
  Author URI: http://www.lilaeamedia.com/
11
  Text Domain: chld_thm_cfg
25
  global $chld_thm_cfg;
26
  $css = $chld_thm_cfg->css;
27
  $themes = $chld_thm_cfg->themes;
28
+ $parent = $css->get_prop('parnt');
29
+ $child = $css->get_prop('child');
30
+ $configtype = $css->get_prop('configtype');
31
  $hidechild = (count($themes['child']) ? '' : 'style="display:none"');
32
+ $imports = $css->get_prop('imports');
33
  $id = 0;
34
  ?>
35
 
58
  class="nav-tab<?php echo 'view_child_options' == $active_tab ? ' nav-tab-active' : ''; ?>" <?php echo $hidechild; ?>>
59
  <?php _e('View Child CSS', 'chld_thm_cfg'); ?>
60
  </a> <a id="view_parnt_options" href="?page=<?php echo $chld_thm_cfg->menuName; ?>&amp;tab=view_parnt_options"
61
+ class="nav-tab<?php echo 'view_parnt_options' == $active_tab ? ' nav-tab-active' : ''; ?>" <?php echo $hidechild; ?>>
62
  <?php _e('View Parent CSS', 'chld_thm_cfg'); ?>
63
+ </a><?php do_action('chld_thm_cfg_tabs', $chld_thm_cfg, $active_tab, $hidechild);?> <i id="ctc_status_preview"></i></h2>
64
  <div class="ctc-option-panel-container">
65
  <div id="parent_child_options_panel" class="ctc-option-panel<?php echo 'parent_child_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>">
66
  <form id="ctc_load_form" method="post" action="">
104
  <label>&nbsp;</label>
105
  </div>
106
  <div class="ctc-input-cell" >
107
+ <input class="ctc_text" id="ctc_child_template" name="ctc_child_template" type="text" placeholder="<?php _e('Theme Slug', 'chld_thm_cfg'); ?>" autocomplete="off"/>
108
  </div>
109
  <div class="ctc-input-cell">
110
  <select class="ctc-select" id="ctc_theme_child" name="ctc_theme_child" <?php echo $hidechild; ?>>
120
  </div>
121
  <div class="ctc-input-cell">
122
  <input class="ctc_text" id="ctc_child_name" name="ctc_child_name" type="text"
123
+ value="<?php echo esc_attr($css->get_prop('child_name')); ?>" placeholder="<?php _e('Theme Name', 'chld_thm_cfg'); ?>" autocomplete="off" />
124
  </div>
125
  </div>
126
+ <?php if ('' == $hidechild) do_action('chld_thm_cfg_controls', $chld_thm_cfg); ?>
127
  <div class="ctc-input-row clearfix" id="input_row_child_template">
128
  <div class="ctc-input-cell">
129
  <label>
132
  </div>
133
  <div class="ctc-input-cell">
134
  <input class="ctc_text" id="ctc_child_author" name="ctc_child_author" type="text"
135
+ value="<?php echo esc_attr($css->get_prop('author')); ?>" placeholder="<?php _e('Author', 'chld_thm_cfg'); ?>" autocomplete="off" />
136
  </div>
137
  </div>
138
  <div class="ctc-input-row clearfix" id="input_row_child_template">
143
  </div>
144
  <div class="ctc-input-cell">
145
  <input class="ctc_text" id="ctc_child_version" name="ctc_child_version" type="text"
146
+ value="<?php echo esc_attr($css->get_prop('version')); ?>" placeholder="<?php _e('Version', 'chld_thm_cfg'); ?>" autocomplete="off" />
147
  </div>
148
  </div>
149
  <div class="ctc-input-row clearfix" id="input_row_child_template">
163
  </div>
164
  <div class="ctc-input-cell">
165
  <input class="ctc_submit button button-primary" id="ctc_load_styles" name="ctc_load_styles" type="submit"
166
+ value="<?php _e('Generate Child Theme Files', 'chld_thm_cfg'); ?>" disabled />
167
  </div>
168
  </div>
169
  </form>
311
  </div>
312
  <div id="view_child_options_panel"
313
  class="ctc-option-panel<?php echo 'view_child_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>" <?php echo $hidechild; ?>> </div>
314
+ <div id="view_parnt_options_panel"
315
+ class="ctc-option-panel<?php echo 'view_parnt_options' == $active_tab ? ' ctc-option-panel-active' : ''; ?>" <?php echo $hidechild; ?>> </div>
316
+ <?php do_action('chld_thm_cfg_panels', $chld_thm_cfg, $active_tab, $hidechild); ?>
317
  </div>
318
  </div>
319
  <style type="text/css">
349
  echo '</ul></div>' . LF;
350
  elseif (isset($_GET['updated'])):
351
  echo '<div class="updated"><p>' . LF
352
+ . apply_filters('chld_thm_cfg_update_msg', sprintf(__('Child Theme <strong>%s</strong> has been generated successfully.', 'chld_thm_cfg'),
353
+ $chld_thm_cfg->css->get_prop('child_name')), $chld_thm_cfg) . LF
354
  . '</p></div>' . LF;
355
  endif;
356
  }
includes/class-ctc.php CHANGED
@@ -6,7 +6,7 @@ if ( !defined('ABSPATH')) exit;
6
  Class: Child_Theme_Configurator
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Main Controller Class
9
- Version: 1.2.3
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
@@ -18,7 +18,6 @@ require_once('class-ctc-ui.php');
18
  require_once('class-ctc-css.php');
19
  class Child_Theme_Configurator {
20
 
21
- var $version = '1.2.3';
22
  var $css;
23
  var $optionsName;
24
  var $menuName;
@@ -46,10 +45,11 @@ class Child_Theme_Configurator {
46
  $this->pluginURL = plugin_dir_url($file);
47
 
48
  // setup plugin hooks
49
- add_action('admin_menu', array(&$this, 'admin_menu'));
50
- add_action('admin_enqueue_scripts', array(&$this, 'enqueue_scripts'));
51
- add_action('wp_ajax_ctc_update', array(&$this, 'ajax_save_postdata' ));
52
- add_action('wp_ajax_ctc_query', array(&$this, 'ajax_query_css' ));
 
53
  //add_action('update_option_' . $this->optionsName, array(&$this, 'update_redirect'), 10);
54
  }
55
 
@@ -68,15 +68,19 @@ class Child_Theme_Configurator {
68
  wp_enqueue_script('chld-thm-cfg-admin', $this->pluginURL . 'js/chld-thm-cfg.min.js',
69
  array('jquery-ui-autocomplete'), '1.0', true);
70
  wp_localize_script( 'chld-thm-cfg-admin', 'ctcAjax',
71
- apply_filters('ctc_localize_script', array(
72
  'ajaxurl' => admin_url( 'admin-ajax.php' ),
73
  'theme_uri' => get_theme_root_uri(),
74
  'themes' => $this->themes,
75
- 'parnt' => $this->css->get_property('parnt'),
76
- 'child' => $this->css->get_property('child'),
77
- 'imports' => $this->css->get_property('imports'),
78
- 'rule' => $this->css->get_property('rule'),
79
- 'sel_ndx' => $this->css->get_property('sel_ndx'),
 
 
 
 
80
  'val_qry' => array(),
81
  'rule_val' => array(),
82
  'sel_val' => array(),
@@ -113,8 +117,9 @@ class Child_Theme_Configurator {
113
 
114
  function ctc_page_init () {
115
  $this->get_themes();
116
- $this->load_css();
117
- $this->generate_stylesheet();
 
118
  $this->ui = new Child_Theme_Configurator_UI();
119
  $this->ui->render_help_tabs();
120
  }
@@ -133,29 +138,29 @@ class Child_Theme_Configurator {
133
  endforeach;
134
  }
135
 
136
- function load_css() {
137
  if (!($this->css = get_option($this->optionsName))
138
  || !is_object($this->css)
139
  // upgrade to v.1.1.1
140
- || !($version = $this->css->get_property('version'))
141
  )
142
 
143
  $this->css = new Child_Theme_Configurator_CSS();
144
  }
145
 
146
- function validate_post() {
147
  return ('POST' == $_SERVER['REQUEST_METHOD']
148
  && current_user_can('edit_theme_options')
149
- && ($this->is_ajax ? check_ajax_referer( 'ctc_update', '_wpnonce', false ) : check_admin_referer( 'ctc_update', '_wpnonce', false )));
150
  }
151
 
152
  function ajax_save_postdata() {
153
  $this->is_ajax = true;
154
  if ($this->validate_post()):
155
- $this->load_css();
156
  $this->css->parse_post_data();
157
  $this->css->write_css();
158
- $result = $this->css->get_property('updates');
159
  // clear updates so they aren't saved in options object
160
  $this->css->reset_updates();
161
  update_option($this->optionsName, $this->css);
@@ -169,7 +174,7 @@ class Child_Theme_Configurator {
169
  function ajax_query_css() {
170
  $this->is_ajax = true;
171
  if ($this->validate_post()):
172
- $this->load_css();
173
  $regex = "/^ctc_query_/";
174
  foreach(preg_grep($regex, array_keys($_POST)) as $key):
175
  $name = preg_replace($regex, '', $key);
@@ -180,7 +185,7 @@ class Child_Theme_Configurator {
180
  array(
181
  'key' => isset($param['key'])?$param['key']:'',
182
  'obj' => $param['obj'],
183
- 'data' => $this->css->get_property($param['obj'], $param),
184
  ),
185
  );
186
  die(json_encode($result));
@@ -189,15 +194,16 @@ class Child_Theme_Configurator {
189
  die(0);
190
  }
191
 
192
- function generate_stylesheet() {
193
- if (empty($_POST['ctc_load_styles'])) return;
194
  $this->errors = array();
195
  if (current_user_can('install_themes') && $this->validate_post()):
196
  foreach (array(
197
  'ctc_theme_parnt',
198
  'ctc_child_type',
199
  'ctc_theme_child',
200
- 'ctc_child_name',
 
201
  'ctc_child_template',
202
  'ctc_child_author',
203
  'ctc_child_version') as $postfield):
@@ -213,6 +219,7 @@ class Child_Theme_Configurator {
213
  $this->errors[] = __('Please select a valid Parent Theme', 'chld_thm_cfg');
214
  endif;
215
  if ('new' == $type):
 
216
  $child = strtolower(preg_replace("%[^\w\-]%", '', $template));
217
  if ($this->check_theme_exists($child)):
218
  $this->errors[] = sprintf(__('<strong>%s</strong> exists. Please enter a different Child Theme template name', 'chld_thm_cfg'), $child);
@@ -224,29 +231,33 @@ class Child_Theme_Configurator {
224
  if (empty($name)):
225
  $this->errors[] = __('Please enter a valid Child Theme name', 'chld_thm_cfg');
226
  endif;
 
 
 
227
  else:
228
  $this->errors[] = __('You do not have permission to configure child themes.', 'chld_thm_cfg');
229
  endif;
230
  if (empty($this->errors)):
231
  $this->css = new Child_Theme_Configurator_CSS();
232
- $this->css->set_property('parnt', $parnt);
233
- $this->css->set_property('child', $child);
234
- $this->css->set_property('child_name', $name);
235
- $this->css->set_property('child_author', $author);
236
- $this->css->set_property('child_version', $version);
 
 
237
  $this->css->parse_css_file('parnt');
238
  $this->css->parse_css_file('child');
239
- if (!$this->css->write_css(isset($_POST['ctc_backup']))): // true backs up current stylesheet
240
- $this->errors[] = __('Your theme directory is not writable. Please adjust permissions and try again.', 'chld_thm_cfg');
241
  return false;
242
- endif;
243
  $this->css->reset_updates();
244
- if (update_option($this->optionsName, $this->css)):
245
- $this->update_redirect();
246
- else:
247
- $this->errors[] = sprintf(__('Child Theme %s was unchanged.', 'chld_thm_cfg'), $name, $this->optionsName);
248
- endif;
249
  endif;
 
250
  }
251
 
252
  function render_menu($template = 'child', $selected = null) {
@@ -269,10 +280,33 @@ class Child_Theme_Configurator {
269
  return $input;
270
  }
271
 
272
- function update_redirect() {
273
  if (empty($this->is_ajax)):
274
- wp_safe_redirect(admin_url('tools.php?page=' . $this->menuName . '&updated=true'));
275
  die();
276
  endif;
277
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
278
  }
6
  Class: Child_Theme_Configurator
7
  Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
8
  Description: Main Controller Class
9
+ Version: 1.3.0
10
  Author: Lilaea Media
11
  Author URI: http://www.lilaeamedia.com/
12
  Text Domain: chld_thm_cfg
18
  require_once('class-ctc-css.php');
19
  class Child_Theme_Configurator {
20
 
 
21
  var $css;
22
  var $optionsName;
23
  var $menuName;
45
  $this->pluginURL = plugin_dir_url($file);
46
 
47
  // setup plugin hooks
48
+ add_action('admin_menu', array(&$this, 'admin_menu'));
49
+ add_action('admin_enqueue_scripts', array(&$this, 'enqueue_scripts'));
50
+ add_action('wp_ajax_ctc_update', array(&$this, 'ajax_save_postdata' ));
51
+ add_action('wp_ajax_ctc_query', array(&$this, 'ajax_query_css' ));
52
+ add_action('chld_thm_cfg_addl_files', array(&$this, 'add_functions_file'), 10, 2);
53
  //add_action('update_option_' . $this->optionsName, array(&$this, 'update_redirect'), 10);
54
  }
55
 
68
  wp_enqueue_script('chld-thm-cfg-admin', $this->pluginURL . 'js/chld-thm-cfg.min.js',
69
  array('jquery-ui-autocomplete'), '1.0', true);
70
  wp_localize_script( 'chld-thm-cfg-admin', 'ctcAjax',
71
+ apply_filters('chld_thm_cfg_localize_script', array(
72
  'ajaxurl' => admin_url( 'admin-ajax.php' ),
73
  'theme_uri' => get_theme_root_uri(),
74
  'themes' => $this->themes,
75
+ 'source' => apply_filters('chld_thm_cfg_source_uri', get_theme_root_uri() . '/'
76
+ . $this->css->get_prop('parnt') . '/style.css', $this->css),
77
+ 'target' => apply_filters('chld_thm_cfg_target_uri', get_theme_root_uri() . '/'
78
+ . $this->css->get_prop('child') . '/style.css', $this->css),
79
+ 'parnt' => $this->css->get_prop('parnt'),
80
+ 'child' => $this->css->get_prop('child'),
81
+ 'imports' => $this->css->get_prop('imports'),
82
+ 'rule' => $this->css->get_prop('rule'),
83
+ 'sel_ndx' => $this->css->get_prop('sel_ndx'),
84
  'val_qry' => array(),
85
  'rule_val' => array(),
86
  'sel_val' => array(),
117
 
118
  function ctc_page_init () {
119
  $this->get_themes();
120
+ $this->load_config();
121
+ do_action('chld_thm_cfg_forms', $this); // hook for custom forms
122
+ $this->write_config();
123
  $this->ui = new Child_Theme_Configurator_UI();
124
  $this->ui->render_help_tabs();
125
  }
138
  endforeach;
139
  }
140
 
141
+ function load_config() {
142
  if (!($this->css = get_option($this->optionsName))
143
  || !is_object($this->css)
144
  // upgrade to v.1.1.1
145
+ || !($version = $this->css->get_prop('version'))
146
  )
147
 
148
  $this->css = new Child_Theme_Configurator_CSS();
149
  }
150
 
151
+ function validate_post($action = 'ctc_update', $noncefield = '_wpnonce') {
152
  return ('POST' == $_SERVER['REQUEST_METHOD']
153
  && current_user_can('edit_theme_options')
154
+ && ($this->is_ajax ? check_ajax_referer( $action, $noncefield, false ) : check_admin_referer($action, $noncefield, false )));
155
  }
156
 
157
  function ajax_save_postdata() {
158
  $this->is_ajax = true;
159
  if ($this->validate_post()):
160
+ $this->load_config();
161
  $this->css->parse_post_data();
162
  $this->css->write_css();
163
+ $result = $this->css->get_prop('updates');
164
  // clear updates so they aren't saved in options object
165
  $this->css->reset_updates();
166
  update_option($this->optionsName, $this->css);
174
  function ajax_query_css() {
175
  $this->is_ajax = true;
176
  if ($this->validate_post()):
177
+ $this->load_config();
178
  $regex = "/^ctc_query_/";
179
  foreach(preg_grep($regex, array_keys($_POST)) as $key):
180
  $name = preg_replace($regex, '', $key);
185
  array(
186
  'key' => isset($param['key'])?$param['key']:'',
187
  'obj' => $param['obj'],
188
+ 'data' => $this->css->get_prop($param['obj'], $param),
189
  ),
190
  );
191
  die(json_encode($result));
194
  die(0);
195
  }
196
 
197
+ function write_config() {
198
+ if (!isset($_POST['ctc_load_styles'])) return false;
199
  $this->errors = array();
200
  if (current_user_can('install_themes') && $this->validate_post()):
201
  foreach (array(
202
  'ctc_theme_parnt',
203
  'ctc_child_type',
204
  'ctc_theme_child',
205
+ 'ctc_child_name',
206
+ 'ctc_configtype',
207
  'ctc_child_template',
208
  'ctc_child_author',
209
  'ctc_child_version') as $postfield):
219
  $this->errors[] = __('Please select a valid Parent Theme', 'chld_thm_cfg');
220
  endif;
221
  if ('new' == $type):
222
+ $configtype = 'theme'; // no custom stylesheets until style.css exists!
223
  $child = strtolower(preg_replace("%[^\w\-]%", '', $template));
224
  if ($this->check_theme_exists($child)):
225
  $this->errors[] = sprintf(__('<strong>%s</strong> exists. Please enter a different Child Theme template name', 'chld_thm_cfg'), $child);
231
  if (empty($name)):
232
  $this->errors[] = __('Please enter a valid Child Theme name', 'chld_thm_cfg');
233
  endif;
234
+ if (false === $this->verify_child_theme($child)):
235
+ $this->errors[] = __('Your theme directories are not writable. Please adjust permissions and try again.', 'chld_thm_cfg');
236
+ endif;
237
  else:
238
  $this->errors[] = __('You do not have permission to configure child themes.', 'chld_thm_cfg');
239
  endif;
240
  if (empty($this->errors)):
241
  $this->css = new Child_Theme_Configurator_CSS();
242
+ $this->css->set_prop('parnt', $parnt);
243
+ $this->css->set_prop('child', $child);
244
+ $this->css->set_prop('child_name', $name);
245
+ $this->css->set_prop('child_author', $author);
246
+ $this->css->set_prop('child_version', $version);
247
+ $this->css->set_prop('configtype', $configtype);
248
+ do_action('chld_thm_cfg_addl_files', $this); // hook for add'l plugin files and subdirectories
249
  $this->css->parse_css_file('parnt');
250
  $this->css->parse_css_file('child');
251
+ if (false === $this->css->write_css(isset($_POST['ctc_backup']))):
252
+ $this->errors[] = __('Your stylesheet is not writable. Please adjust permissions and try again.', 'chld_thm_cfg');
253
  return false;
254
+ endif;
255
  $this->css->reset_updates();
256
+ update_option($this->optionsName, $this->css);
257
+ do_action('chld_thm_cfg_addl_options', $this); // hook for add'l plugin options
258
+ $this->update_redirect();
 
 
259
  endif;
260
+ //$this->errors[] = sprintf(__('Child Theme %s was unchanged.', 'chld_thm_cfg'), $name, $this->optionsName);
261
  }
262
 
263
  function render_menu($template = 'child', $selected = null) {
280
  return $input;
281
  }
282
 
283
+ function update_redirect($msg = 1) {
284
  if (empty($this->is_ajax)):
285
+ wp_safe_redirect(admin_url('tools.php?page=' . $this->menuName . '&updated=' . $msg));
286
  die();
287
  endif;
288
  }
289
+
290
+ function verify_child_theme($child) {
291
+ $themedir = get_theme_root();
292
+ if (! is_writable($themedir)) return false;
293
+ $childdir = $themedir . '/' . $child;
294
+
295
+ if (! is_dir($childdir)):
296
+ if (! mkdir($childdir, 0755)):
297
+ return false;
298
+ endif;
299
+ elseif (! is_writable($childdir)):
300
+ return false;
301
+ endif;
302
+ }
303
+
304
+ function add_functions_file($obj){
305
+ // add functions.php file
306
+ $file = $obj->css->get_child_target('functions.php');
307
+ if (!file_exists($file)):
308
+ if (false === file_put_contents($file,
309
+ "<?php\n// Exit if accessed directly\nif ( !defined('ABSPATH')) exit;\n\n/* Add custom functions below */")) return false;
310
+ endif;
311
+ }
312
  }
js/chld-thm-cfg.js CHANGED
@@ -2,7 +2,7 @@
2
  * Script: chld-thm-cfg.js
3
  * Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
4
  * Description: Handles jQuery, AJAX and other UI
5
- * Version: 1.2.3
6
  * Author: Lilaea Media
7
  * Author URI: http://www.lilaeamedia.com/
8
  * License: GPLv2
@@ -37,8 +37,8 @@ jQuery(document).ready(function($){
37
  var regex = /^(ctc_(ovrd|\d+)_(parent|child)_([0-9a-z\-]+)_(\d+))(_\w+)?$/,
38
  $container = $(obj).parents('.ctc-selector-row, .ctc-parent-row').first(),
39
  $swatch = $container.find('.ctc-swatch').first(),
40
- cssrules = { 'parent': {}, 'child': {} },
41
- gradient = {
42
  'parent': {
43
  'origin': '',
44
  'start': '',
@@ -51,7 +51,7 @@ jQuery(document).ready(function($){
51
  }
52
  },
53
  has_gradient = { 'child': false, 'parent': false },
54
- postdata = {};
55
  // set up objects for all neighboring inputs
56
  $container.find('.ctc-parent-value, .ctc-child-value').each(function(){
57
  var inputid = $(this).attr('id'),
@@ -131,7 +131,7 @@ jQuery(document).ready(function($){
131
  }
132
  });
133
  // update swatch
134
- if ('undefined' != typeof $swatch) {
135
  $($swatch).removeAttr('style');
136
  if (has_gradient.parent) { $($swatch).ctcgrad(gradient.parent.origin, [gradient.parent.start, gradient.parent.end]); }
137
  $($swatch).css(cssrules.parent);
@@ -342,7 +342,6 @@ jQuery(document).ready(function($){
342
  }
343
  return html;
344
  },
345
-
346
  ctc_render_selector_inputs = function(qsid) {
347
  if (1 === loading.sel_val) {
348
  return false;
@@ -378,7 +377,25 @@ jQuery(document).ready(function($){
378
  }
379
  }
380
  }
381
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
382
  ctc_render_rule_value_inputs = function(ruleid) {
383
  if (1 === loading.rule_val) return false;
384
 
@@ -472,16 +489,25 @@ jQuery(document).ready(function($){
472
  postdata,
473
  //on success function
474
  function(response){
 
475
  // hide spinner
476
  loading[obj] = 2;
477
  $('.ctc-status-icon').removeClass('spinner');
478
  // show check mark
479
  if (ctc_is_empty(response)) {
480
  $('.ctc-status-icon').addClass('failure');
 
 
 
 
481
  } else {
482
  $('.ctc-status-icon').addClass('success');
483
- // update data objects
484
- ctc_update_cache(response);
 
 
 
 
485
  if ('function' === typeof callback) {
486
  callback(key);
487
  }
@@ -489,11 +515,18 @@ jQuery(document).ready(function($){
489
  }
490
  },'json'
491
  ).fail(function(){
492
- loading[obj] = 0;
493
  // hide spinner
494
  $('.ctc-status-icon').removeClass('spinner');
495
  // show check mark
496
  $('.ctc-status-icon').addClass('failure');
 
 
 
 
 
 
 
 
497
  });
498
  return false;
499
  },
@@ -546,7 +579,7 @@ jQuery(document).ready(function($){
546
  postdata,
547
  //on success function
548
  function(response){
549
- console.log(response);
550
  // release button
551
  $(obj).prop('disabled', false);
552
  // hide spinner
@@ -577,66 +610,6 @@ jQuery(document).ready(function($){
577
  });
578
  return false;
579
  },
580
- /* stub for future ajax loader
581
- ctc_load_css = function(e) {
582
-
583
-
584
- var postdata = $(this).serializeArray();
585
- // disable the button until ajax returns
586
- $('#ctc_load_styles').prop('disabled', true);
587
- // clear previous success/fail icons
588
- $('.ctc-status-icon').remove();
589
- // show spinner
590
- $('#ctc_load_styles').parent('.ctc-input-cell').append('<span class="ctc-status-icon spinner"></span>');
591
- $('.spinner').show();
592
- return true;
593
-
594
- // ajax post input data
595
- $.post(
596
- // get ajax url from localized object
597
- ctcAjax.ajaxurl,
598
- //Data
599
- postdata,
600
- //on success function
601
- function(response){
602
- // release button
603
- $('#ctc_load_styles').prop('disabled', false);
604
- // hide spinner
605
- $('.ctc-status-icon').removeClass('spinner');
606
- // show check mark
607
- if (ctc_is_empty(response.updated)) {
608
- $('.ctc-status-icon').addClass('failure');
609
- // update notice
610
- if (false === ctc_is_empty(response.error)) {
611
- ctc_set_notice({'error': response.error});
612
- }
613
- } else {
614
- $('.ctc-status-icon').addClass('success');
615
- // update notice
616
- if (false === ctc_is_empty(response.updated)) {
617
- ctc_set_notice({'updated': response.updated});
618
- }
619
- if (false === ctc_is_empty(response.themes)) {
620
- ctcAjax.themes = response.themes;
621
- }
622
- if (false === ctc_is_empty(response.menu)) {
623
- $('#ctc_theme_child').html(response.menu);
624
- }
625
- $('.nav-tab, .ctc-option-panel, .ctc-radio, .ctc-select, label').fadeIn('fast');
626
- }
627
- return false;
628
- },
629
- 'json'
630
- ).fail(function(){
631
- // release button
632
- $('#ctc_load_styles').prop('disabled', false);
633
- // hide spinner
634
- $('.ctc-status-icon').removeClass('spinner');
635
- // show check mark
636
- $('.ctc-status-icon').addClass('failure');
637
- });
638
- return false;
639
- },*/
640
  ctc_decode_value = function(rule, value) {
641
  value = ('undefined' == typeof value ? '' : value);
642
  var obj = { 'orig': value };
@@ -906,7 +879,8 @@ jQuery(document).ready(function($){
906
  'sel_ndx': 2,
907
  'val_qry': 0,
908
  'rule_val': 0,
909
- 'sel_val': 0
 
910
  },
911
 
912
  ctc_selectors = [],
@@ -946,24 +920,12 @@ jQuery(document).ready(function($){
946
  $('.nav-tab').on('click', function(e){
947
  e.preventDefault();
948
  // clear the notice box
949
- ctc_set_notice('')
 
950
  var id = '#' + $(this).attr('id');
951
  ctc_focus_panel(id);
952
  });
953
- $('#view_child_options,#view_parnt_options').on('click', function(e){
954
- ctc_set_notice('')
955
- var stamp = new Date().getTime(),
956
- theme = $(this).attr('id').toString().match(/(child|parnt)/)[1],
957
- css_uri = ctcAjax.theme_uri + '/' + ctcAjax[theme] + '/style.css?' + stamp;
958
- $.get(
959
- css_uri,
960
- function(response){
961
- $('#view_'+theme+'_options_panel').text(response);
962
- }
963
- ).fail(function(){
964
- $('#view_'+theme+'_options_panel').text(ctcAjax.css_fail_txt);
965
- });
966
- });
967
  $('#ctc_load_form').on('submit', function() {
968
  return (ctc_validate() && confirm(ctcAjax.load_txt) ) ;
969
  });
2
  * Script: chld-thm-cfg.js
3
  * Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
4
  * Description: Handles jQuery, AJAX and other UI
5
+ * Version: 1.3.0
6
  * Author: Lilaea Media
7
  * Author URI: http://www.lilaeamedia.com/
8
  * License: GPLv2
37
  var regex = /^(ctc_(ovrd|\d+)_(parent|child)_([0-9a-z\-]+)_(\d+))(_\w+)?$/,
38
  $container = $(obj).parents('.ctc-selector-row, .ctc-parent-row').first(),
39
  $swatch = $container.find('.ctc-swatch').first(),
40
+ cssrules = { 'parent': {}, 'child': {} },
41
+ gradient = {
42
  'parent': {
43
  'origin': '',
44
  'start': '',
51
  }
52
  },
53
  has_gradient = { 'child': false, 'parent': false },
54
+ postdata = {};
55
  // set up objects for all neighboring inputs
56
  $container.find('.ctc-parent-value, .ctc-child-value').each(function(){
57
  var inputid = $(this).attr('id'),
131
  }
132
  });
133
  // update swatch
134
+ if ('undefined' != typeof $swatch && false === ctc_is_empty($swatch.attr('id'))) {
135
  $($swatch).removeAttr('style');
136
  if (has_gradient.parent) { $($swatch).ctcgrad(gradient.parent.origin, [gradient.parent.start, gradient.parent.end]); }
137
  $($swatch).css(cssrules.parent);
342
  }
343
  return html;
344
  },
 
345
  ctc_render_selector_inputs = function(qsid) {
346
  if (1 === loading.sel_val) {
347
  return false;
377
  }
378
  }
379
  }
380
+ ctc_render_css_preview = function(theme) {
381
+ if (1 === loading.preview) {
382
+ return false;
383
+ }
384
+ if (0 == loading.preview) {
385
+ loading.preview = 1;
386
+ var theme;
387
+ if (!(theme = $(this).attr('id').toString().match(/(child|parnt)/)[1])) {
388
+ theme = 'child';
389
+ }
390
+ ctc_set_notice('')
391
+ ctc_query_css('preview', theme, ctc_render_css_preview);
392
+ return false;
393
+ }
394
+ if (2 == loading.preview) {
395
+ $('#view_'+theme+'_options_panel').text(ctcAjax.previewResponse);
396
+ loading.preview = 0;
397
+ }
398
+ },
399
  ctc_render_rule_value_inputs = function(ruleid) {
400
  if (1 === loading.rule_val) return false;
401
 
489
  postdata,
490
  //on success function
491
  function(response){
492
+ // console.log(response);
493
  // hide spinner
494
  loading[obj] = 2;
495
  $('.ctc-status-icon').removeClass('spinner');
496
  // show check mark
497
  if (ctc_is_empty(response)) {
498
  $('.ctc-status-icon').addClass('failure');
499
+ if ('preview' == obj) {
500
+ ctcAjax.previewResponse = ctcAjax.css_fail_txt;
501
+ callback(key);
502
+ }
503
  } else {
504
  $('.ctc-status-icon').addClass('success');
505
+ if ('preview' == obj) {
506
+ ctcAjax.previewResponse = response.shift().data;
507
+ } else {
508
+ // update data objects
509
+ ctc_update_cache(response);
510
+ }
511
  if ('function' === typeof callback) {
512
  callback(key);
513
  }
515
  }
516
  },'json'
517
  ).fail(function(){
 
518
  // hide spinner
519
  $('.ctc-status-icon').removeClass('spinner');
520
  // show check mark
521
  $('.ctc-status-icon').addClass('failure');
522
+ if ('preview' == obj) {
523
+ ctcAjax.previewResponse = ctcAjax.css_fail_txt;
524
+ loading[obj] = 2;
525
+ callback(key);
526
+ } else {
527
+ loading[obj] = 0;
528
+ }
529
+
530
  });
531
  return false;
532
  },
579
  postdata,
580
  //on success function
581
  function(response){
582
+ // console.log(response);
583
  // release button
584
  $(obj).prop('disabled', false);
585
  // hide spinner
610
  });
611
  return false;
612
  },
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
613
  ctc_decode_value = function(rule, value) {
614
  value = ('undefined' == typeof value ? '' : value);
615
  var obj = { 'orig': value };
879
  'sel_ndx': 2,
880
  'val_qry': 0,
881
  'rule_val': 0,
882
+ 'sel_val': 0,
883
+ 'preview': 0
884
  },
885
 
886
  ctc_selectors = [],
920
  $('.nav-tab').on('click', function(e){
921
  e.preventDefault();
922
  // clear the notice box
923
+ ctc_set_notice('');
924
+ $('.ctc-status-icon').remove();
925
  var id = '#' + $(this).attr('id');
926
  ctc_focus_panel(id);
927
  });
928
+ $('#view_child_options,#view_parnt_options').on('click', ctc_render_css_preview);
 
 
 
 
 
 
 
 
 
 
 
 
 
929
  $('#ctc_load_form').on('submit', function() {
930
  return (ctc_validate() && confirm(ctcAjax.load_txt) ) ;
931
  });
js/chld-thm-cfg.min.js CHANGED
@@ -2,10 +2,10 @@
2
  * Script: chld-thm-cfg.js
3
  * Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
4
  * Description: Handles jQuery, AJAX and other UI
5
- * Version: 1.2.3
6
  * Author: Lilaea Media
7
  * Author URI: http://www.lilaeamedia.com/
8
  * License: GPLv2
9
  * Copyright (C) 2013 Lilaea Media
10
  */
11
- ;jQuery(document).ready(function(c){var l="\n",s="base",h,b={},p,q,k=function(t){c(t).iris({change:function(){f(t)}})},e=function(v){var t=parseInt(v),u=String.fromCharCode(t);return u},m=function(u){var t=u.charCodeAt(0);return t},f=function(z){var v=/^(ctc_(ovrd|\d+)_(parent|child)_([0-9a-z\-]+)_(\d+))(_\w+)?$/,A=c(z).parents(".ctc-selector-row, .ctc-parent-row").first(),y=A.find(".ctc-swatch").first(),x={parent:{},child:{}},w={parent:{origin:"",start:"",end:""},child:{origin:"",start:"",end:""}},u={child:false,parent:false},t={};A.find(".ctc-parent-value, .ctc-child-value").each(function(){var I=c(this).attr("id"),B=I.toString().match(v),J=B[2],C=B[3],L=("undefined"==typeof B[4]?"":B[4]),H=B[5],G=("undefined"==typeof B[6]?"":B[6]),K=("parent"==C?c(this).text():c(this).val()),D="ctc_"+J+"_child_"+L+"_i_"+H,F,E;if("child"==C){t[I]=K;t[D]=(c("#"+D).is(":checked"))?1:0}if(false===r(G)){switch(G){case"_border_width":x[C][L+"-width"]=K;break;case"_border_style":x[C][L+"-style"]=K;break;case"_border_color":x[C][L+"-color"]=K;break;case"_background_url":x[C]["background-image"]=i(C,K);break;case"_background_color":x[C]["background-color"]=z.value;break;case"_background_color1":w[C].start=K;u[C]=true;break;case"_background_color2":w[C].end=K;u[C]=true;break;case"_background_origin":w[C].origin=K;u[C]=true;break}}else{if(F=L.toString().match(/^border(\-(top|right|bottom|left))?$/)&&!K.match(/none/)){E=K.toString().split(/ +/);x[C][L+"-width"]="undefined"==typeof E[0]?"":E[0];x[C][L+"-style"]="undefined"==typeof E[1]?"":E[1];x[C][L+"-color"]="undefined"==typeof E[2]?"":E[2]}else{if("background-image"==L){if(K.toString().match(/url\(/)){x[C]["background-image"]=i(C,K)}else{E=K.toString().split(/ +/);if(E.length>2){w[C].origin="undefined"==typeof E[0]?"top":E[0];w[C].start="undefined"==typeof E[1]?"transparent":E[1];w[C].end="undefined"==typeof E[2]?"transparent":E[2];u[C]=true}else{x[C]["background-image"]=K}}}else{x[C][L]=K}}}});if("undefined"!=typeof y){c(y).removeAttr("style");if(u.parent){c(y).ctcgrad(w.parent.origin,[w.parent.start,w.parent.end])}c(y).css(x.parent);if(!(y.attr("id").toString().match(/parent/))){if(u.child){c(y).ctcgrad(w.child.origin,[w.child.start,w.child.end])}c(y).css(x.child)}}return t},n=function(u){var t,v,w;c(u).each(function(){switch(this.obj){case"imports":ctcAjax.imports=this.data;break;case"rule_val":ctcAjax.rule_val[this.key]=this.data;w=this.key;break;case"val_qry":ctcAjax.val_qry[this.key]=this.data;break;case"rule":ctcAjax.rule=this.data;break;case"sel_ndx":if(r(this.key)){ctcAjax.sel_ndx=this.data}else{if("qsid"==this.key){if(r(ctcAjax.sel_ndx[this.data.query])){ctcAjax.sel_ndx[this.data.query]={}}ctcAjax.sel_ndx[this.data.query][this.data.selector]=this.data.qsid}else{ctcAjax.sel_ndx[this.key]=this.data;t=this.key}}break;case"sel_val":ctcAjax.sel_val[this.key]=this.data;v=this.key;break;case"rewrite":p=this.key;q=this.data;break}})},i=function(x,u){var w=u.toString().match(/url\([" ]*(.+?)[" ]*\)/),v=r(w)?null:w[1],t=ctcAjax.theme_uri+"/"+("parent"==x?ctcAjax.parnt:ctcAjax.child)+"/",y;if(!v){return false}else{if(v.toString().match(/^(https?:|\/)/)){y=u}else{y="url("+t+v+")"}}return y},r=function(u){if("undefined"==typeof u||false===u||null===u||""===u){return true}if(true===u||"string"===typeof u||"number"===typeof u){return false}if("object"===typeof u){for(var t in u){if(u.hasOwnProperty(t)){return false}}return true}return false},a=function(){var t=[];if(1===loading.sel_ndx){return t}if(0===loading.sel_ndx){loading.sel_ndx=1;ctc_query_css("sel_ndx",null,ctc_setup_query_menu);return t}if(false===r(ctcAjax.sel_ndx)){c.each(ctcAjax.sel_ndx,function(u,v){var w={label:u,value:u};t.push(w)})}return t},o=function(u){var t=[];if(1===loading.sel_ndx){return t}if(0===loading.sel_ndx){loading.sel_ndx=1;ctc_query_css("sel_ndx",u,ctc_setup_selector_menu);return t}if(false===r(ctcAjax.sel_ndx[u])){c.each(ctcAjax.sel_ndx[u],function(v,w){var x={label:v,value:w};t.push(x)})}return t},d=function(){var t=[];if(1===loading.rule){return t}if(0===loading.rule){loading.rule=1;ctc_query_css("rule",null,ctc_setup_rule_menu);return t}if(false===r(ctcAjax.rule)){c.each(ctcAjax.rule,function(u,v){var w={label:v.replace(/\d+/g,e),value:u};t.push(w)})}return t.sort(function(v,u){if(v.label>u.label){return 1}if(v.label<u.label){return -1}return 0})},j=function(x,z,C){var v="",A=(r(ctcAjax.sel_val[x])||r(ctcAjax.sel_val[x].value)||r(ctcAjax.sel_val[x].value[z])?"":ctcAjax.sel_val[x].value[z]),u=ctc_decode_value(z,("undefined"==typeof A?"":A.parnt)),y=(false===r(A.i_parnt)&&A.i_parnt)?ctcAjax.important_label:"",w=ctc_decode_value(z,("undefined"==typeof A?"":A.child)),t=(false===r(A.i_child)&&A.i_child)?1:0,B="ctc_"+C+"_child_"+z+"_i_"+x;if(false===r(ctcAjax.sel_val[x])){v+='<div class="ctc-'+("ovrd"==C?"input":"selector")+'-row clearfix">'+l;v+='<div class="ctc-input-cell">'+("ovrd"==C?z.replace(/\d+/g,e):ctcAjax.sel_val[x].selector+'<br/><a href="#" class="ctc-selector-edit" id="ctc_selector_edit_'+x+'" >'+ctcAjax.edit_txt+"</a> "+(r(u.orig)?ctcAjax.child_only_txt:""))+"</div>"+l;if("ovrd"==C){v+='<div class="ctc-parent-value ctc-input-cell" id="ctc_'+C+"_parent_"+z+"_"+x+'">'+(r(u.orig)?"[no value]":u.orig+y)+"</div>"+l}v+='<div class="ctc-input-cell">'+l;if(false===r(u.names)){c.each(u.names,function(D,E){E=(r(E)?"":E);v+='<div class="ctc-child-input-cell">'+l;var G="ctc_"+C+"_child_"+z+"_"+x+E,F;if(false===(F=w.values.shift())){F=""}v+=(r(E)?"":ctcAjax.field_labels[E]+":<br/>")+'<input type="text" id="'+G+'" name="'+G+'" class="ctc-child-value'+((E+z).toString().match(/color/)?" color-picker":"")+((E).toString().match(/url/)?" ctc-input-wide":"")+'" value="'+F+'" />'+l;v+="</div>"+l});v+='<label for="'+B+'"><input type="checkbox" id="'+B+'" name="'+B+'" value="1" '+(1===t?"checked":"")+" />"+ctcAjax.important_label+"</label>"+l}v+="</div>"+l;v+=("ovrd"==C?"":'<div class="ctc-swatch ctc-specific" id="ctc_child_'+z+"_"+x+'_swatch">'+ctcAjax.swatch_txt+"</div>"+l+'<div class="ctc-child-input-cell ctc-button-cell" id="ctc_save_'+z+"_"+x+'_cell">'+l+'<input type="button" class="button ctc-save-input" id="ctc_save_'+z+"_"+x+'" name="ctc_save_'+z+"_"+x+'" value="Save" /></div>'+l);v+="</div><!-- end input row -->"+l}return v},g=function(t){if(1===loading.sel_val){return false}if(0==loading.sel_val){loading.sel_val=1;ctc_query_css("sel_val",t,g);return false}var w,u,v;if(r(ctcAjax.sel_val[t])){c("#ctc_sel_ovrd_rule_inputs").html("")}else{if(r(ctcAjax.sel_val[t].seq)){c("#ctc_child_load_order_container").html("")}else{w="ctc_ovrd_child_seq_"+t;v=parseInt(ctcAjax.sel_val[t].seq);u='<input type="text" id="'+w+'" name="'+w+'" class="ctc-child-value" value="'+v+'" />';c("#ctc_child_load_order_container").html(u)}if(r(ctcAjax.sel_val[t].value)){c("#ctc_sel_ovrd_rule_inputs").html("")}else{u="";c.each(ctcAjax.sel_val[t].value,function(y,x){u+=j(t,y,"ovrd")});c("#ctc_sel_ovrd_rule_inputs").html(u).find(".color-picker").each(function(){k(this)});f("#ctc_child_all_0_swatch")}}};ctc_render_rule_value_inputs=function(u){if(1===loading.rule_val){return false}if(0==loading.rule_val){loading.rule_val=1;ctc_query_css("rule_val",u,ctc_render_rule_value_inputs);return false}var v=ctcAjax.rule[u],t='<div class="ctc-input-row clearfix" id="ctc_rule_row_'+v+'">'+l;if(false===r(ctcAjax.rule_val[u])){c.each(ctcAjax.rule_val[u],function(x,y){var w=ctc_decode_value(v,y);t+='<div class="ctc-parent-row clearfix" id="ctc_rule_row_'+v+"_"+x+'">'+l;t+='<div class="ctc-input-cell ctc-parent-value" id="ctc_'+x+"_parent_"+v+"_"+x+'">'+w.orig+"</div>"+l;t+='<div class="ctc-input-cell">'+l;t+='<div class="ctc-swatch ctc-specific" id="ctc_'+x+"_parent_"+v+"_"+x+'_swatch">'+ctcAjax.swatch_txt+"</div></div>"+l;t+='<div class="ctc-input-cell"><a href="#" class="ctc-selector-handle" id="ctc_selector_'+v+"_"+x+'">'+ctcAjax.selector_txt+"</a></div>"+l;t+='<div id="ctc_selector_'+v+"_"+x+'_container" class="ctc-selector-container clearfix">'+l;t+='<a href="#" id="ctc_selector_'+v+"_"+x+'_close" class="ctc-selector-handle" style="float:right">'+ctcAjax.close_txt+'</a><div id="ctc_status_val_qry_'+x+'"></div>'+l;t+='<div id="ctc_selector_'+v+"_"+x+'_rows"></div>'+l;t+="</div></div>"+l});t+="</div>"+l}c("#ctc_rule_value_inputs").html(t).find(".ctc-swatch").each(function(){f(this)})},ctc_render_selector_value_inputs=function(w){if(1==loading.val_qry){return false}var y,u,x=c("#ctc_rule_menu_selected").text().replace(/[^\w\-]/g,m),t,v="";if(0===loading.val_qry){loading.val_qry=1;y={rule:x};ctc_query_css("val_qry",w,ctc_render_selector_value_inputs,y);return false}if(false===r(ctcAjax.val_qry[w])){c.each(ctcAjax.val_qry[w],function(A,z){page_rule=A;c.each(z,function(C,B){v+='<h4 class="ctc-query-heading">'+C+"</h4>"+l;if(false===r(B)){c.each(B,function(D,E){ctcAjax.sel_val[D]=E;v+=j(D,A,w)})}})})}t="#ctc_selector_"+x+"_"+w+"_rows";c(t).html(v).find(".color-picker").each(function(){k(this)});c(t).find(".ctc-swatch").each(function(){f(this)})},ctc_query_css=function(v,u,y,w){var t={ctc_query_obj:v,ctc_query_key:u},x="#ctc_status_"+v+("val_qry"==v?"_"+u:"");if("object"===typeof w){c.each(w,function(z,A){t["ctc_query_"+z]=A})}c(".ctc-status-icon").remove();c(x).append('<span class="ctc-status-icon spinner"></span>');c(".spinner").show();t.action="ctc_query";t._wpnonce=c("#_wpnonce").val();c.post(ctcAjax.ajaxurl,t,function(z){loading[v]=2;c(".ctc-status-icon").removeClass("spinner");if(r(z)){c(".ctc-status-icon").addClass("failure")}else{c(".ctc-status-icon").addClass("success");n(z);if("function"===typeof y){y(u)}return false}},"json").fail(function(){loading[v]=0;c(".ctc-status-icon").removeClass("spinner");c(".ctc-status-icon").addClass("failure")});return false},ctc_save=function(y){var w={},z,v,t,u,A=c(y).attr("id"),x;if(r(b[A])){b[A]=0}b[A]++;c(y).prop("disabled",true);c(".ctc-status-icon").remove();c(y).parent(".ctc-textarea-button-cell, .ctc-button-cell").append('<span class="ctc-status-icon spinner"></span>');c(".spinner").show();if((z=c("#ctc_new_selectors"))&&"ctc_save_new_selectors"==c(y).attr("id")){w.ctc_new_selectors=z.val();if(v=c("#ctc_sel_ovrd_query_selected")){w.ctc_sel_ovrd_query=v.text()}}else{if((t=c("#ctc_child_imports"))&&"ctc_save_imports"==c(y).attr("id")){w.ctc_child_imports=t.val()}else{w=f(y)}}c("#ctc_sel_ovrd_selector_selected").find("#ctc_rewrite_selector").each(function(){x=c("#ctc_rewrite_selector").val(),origsel=c("#ctc_rewrite_selector_orig").val();if(r(x)||!x.toString().match(/\w/)){x=origsel}else{w.ctc_rewrite_selector=x}c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_sel_ovrd_selector_selected").html(x)});w.action="ctc_update";w._wpnonce=c("#_wpnonce").val();c.post(ctcAjax.ajaxurl,w,function(B){console.log(B);c(y).prop("disabled",false);c(".ctc-status-icon").removeClass("spinner");if(r(B)){c(".ctc-status-icon").addClass("failure")}else{c(".ctc-status-icon").addClass("success");c("#ctc_new_selectors").val("");n(B);ctc_setup_menus();if(false===r(p)){ctc_set_selector(p,q);p=q=null}}return false},"json").fail(function(){c(y).prop("disabled",false);c(".ctc-status-icon").removeClass("spinner");c(".ctc-status-icon").addClass("failure")});return false},ctc_decode_value=function(v,t){t=("undefined"==typeof t?"":t);var u={orig:t};if(v.toString().match(/^border(\-(top|right|bottom|left))?$/)){var w=t.toString().split(/ +/);u.names=["_border_width","_border_style","_border_color"];u.values=[("undefined"==typeof w[0]?"":w[0]),("undefined"==typeof w[1]?"":w[1]),("undefined"==typeof w[2]?"":w[2])]}else{if(v.toString().match(/^background\-image/)){u.names=["_background_url","_background_origin","_background_color1","_background_color2"];u.values=["","","",""];if(false===(r(t))&&!(t.toString().match(/url/))){var w=t.toString().split(/:/);u.values[1]=("undefined"==typeof w[0]?"":w[0]);u.values[2]=("undefined"==typeof w[1]?"":w[1]);u.values[3]=("undefined"==typeof w[3]?"":w[3]);u.orig=[u.values[1],u.values[2],u.values[3]].join(" ")}else{u.values[0]=t}}else{u.names=[""];u.values=[t]}}return u},ctc_set_query=function(t){s=t;c("#ctc_sel_ovrd_query").val("");c("#ctc_sel_ovrd_query_selected").text(t);c("#ctc_sel_ovrd_selector").val("");c("#ctc_sel_ovrd_selector_selected").html("&nbsp;");c("#ctc_sel_ovrd_rule_inputs").html("");ctc_setup_selector_menu(t);f("#ctc_child_all_0_swatch");c("#ctc_new_selector_row").show()},ctc_set_selector=function(u,t){c("#ctc_sel_ovrd_selector").val("");c("#ctc_sel_ovrd_selector_selected").text(t);c("#ctc_sel_ovrd_qsid").val(u);h=u;if(1!=loading.sel_val){loading.sel_val=0}g(u);c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_sel_ovrd_new_rule, #ctc_sel_ovrd_rule_header,#ctc_sel_ovrd_rule_inputs_container,#ctc_sel_ovrd_rule_inputs,.ctc-rewrite-toggle").show()},ctc_set_rule=function(u,t){c("#ctc_rule_menu").val("");c("#ctc_rule_menu_selected").text(t);if(1!=loading.rule_val){loading.rule_val=0}ctc_render_rule_value_inputs(u);c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_rule_value_inputs,#ctc_input_row_rule_header").show()},ctc_setup_query_menu=function(){ctc_queries=a();c("#ctc_sel_ovrd_query").autocomplete({source:ctc_queries,minLength:0,selectFirst:true,autoFocus:true,select:function(u,t){ctc_set_query(t.item.value);return false},focus:function(t){t.preventDefault()}})},ctc_setup_selector_menu=function(t){ctc_selectors=o(t);c("#ctc_sel_ovrd_selector").autocomplete({source:ctc_selectors,selectFirst:true,autoFocus:true,select:function(v,u){ctc_set_selector(u.item.value,u.item.label);return false},focus:function(u){u.preventDefault()}})},ctc_setup_rule_menu=function(){ctc_rules=d();c("#ctc_rule_menu").autocomplete({source:ctc_rules,selectFirst:true,autoFocus:true,select:function(u,t){ctc_set_rule(t.item.value,t.item.label);return false},focus:function(t){t.preventDefault()}})},ctc_filtered_rules=function(w,u){var t=[],v=(r(ctcAjax.sel_val[h]))||(r(ctcAjax.sel_val[h].value));if(r(ctc_rules)){ctc_rules=d()}c.each(ctc_rules,function(x,A){var y=false,z=new RegExp(c.ui.autocomplete.escapeRegex(w.term),"i");if(z.test(A.label)){if(false===v){c.each(ctcAjax.sel_val[h].value,function(C,B){if(A.label==C.replace(/\d+/g,e)){y=true;return false}});if(y){return}}t.push(A)}});u(t)},ctc_setup_new_rule_menu=function(){c("#ctc_new_rule_menu").autocomplete({source:ctc_filtered_rules,selectFirst:true,autoFocus:true,select:function(u,t){u.preventDefault();var v=c(j(h,t.item.label.replace(/[^\w\-]/g,m),"ovrd"));c("#ctc_sel_ovrd_rule_inputs").append(v);c("#ctc_new_rule_menu").val("");if(r(ctcAjax.sel_val[h].value)){ctcAjax.sel_val[h]["value"]={}}ctcAjax.sel_val[h].value[t.item.label]={child:""};v.find('input[type="text"]').each(function(w,x){if(c(x).hasClass("color-picker")){k(x)}c(x).focus()});return false},focus:function(t){t.preventDefault()}})},ctc_setup_menus=function(){ctc_setup_query_menu();ctc_setup_selector_menu(s);ctc_setup_rule_menu();ctc_setup_new_rule_menu()},ctc_theme_exists=function(t,u){var v=false;c.each(ctcAjax.themes,function(w,x){c.each(x,function(y,z){if(y==t&&("parnt"==w||"new"==u)){v=true;return false}});if(v){return false}});return v},ctc_set_notice=function(t){var u="";if(false===r(t)){c.each(t,function(v,w){u+='<div class="'+v+'"><ul>'+l;c(w).each(function(x,y){u+="<li>"+y.toString()+"</li>"+l});u+="</ul></div>"})}c("#ctc_error_notice").html(u)},ctc_validate=function(){var w=/[^\w\-]/,u=c("#ctc_child_template").val().toString().replace(w).toLowerCase(),t=c("#ctc_theme_child").val().toString().replace(w).toLowerCase(),v=c("input[name=ctc_child_type]:checked").val(),x=[];if("new"==v){t=u}if(ctc_theme_exists(t,v)){x.push(ctcAjax.theme_exists_txt.toString().replace(/%s/,t))}if(""===t){x.push(ctcAjax.inval_theme_txt)}if(""===c("#ctc_child_name").val()){x.push(ctcAjax.inval_name_txt)}if(x.length){ctc_set_notice({error:x});return false}return true},ctc_set_theme_menu=function(u){var t=c("#ctc_theme_child").val();if(false===r(ctcAjax.themes.child[t])){c("#ctc_child_name").val(ctcAjax.themes.child[t].Name);c("#ctc_child_author").val(ctcAjax.themes.child[t].Author);c("#ctc_child_version").val(ctcAjax.themes.child[t].Version)}},fade_update_notice=function(){c(".updated, .error").slideUp("slow",function(){c(".updated").remove()})},ctc_focus_panel=function(u){var t=u+"_panel";c(".nav-tab").removeClass("nav-tab-active");c(".ctc-option-panel").removeClass("ctc-option-panel-active");c(".ctc-selector-container").hide();c(u).addClass("nav-tab-active");c(".ctc-option-panel-container").scrollTop(0);c(t).addClass("ctc-option-panel-active")},ctc_selector_edit=function(w){var t=c(w).attr("id").match(/_(\d+)$/)[1],v=ctcAjax.sel_val[t].query,u=ctcAjax.sel_val[t].selector,x="#query_selector_options";ctc_set_query(v);ctc_set_selector(t,u);ctc_focus_panel(x)},ctc_selector_input_toggle=function(u){var t;if(c("#ctc_rewrite_selector").length){t=c("#ctc_rewrite_selector_orig").val();c("#ctc_sel_ovrd_selector_selected").text(t);c(u).text(ctcAjax.rename_txt)}else{t=c("#ctc_sel_ovrd_selector_selected").text();c("#ctc_sel_ovrd_selector_selected").html('<input id="ctc_rewrite_selector" name="ctc_rewrite_selector" type="text" value="'+t+'" autocomplete="off" /><input id="ctc_rewrite_selector_orig" name="ctc_rewrite_selector_orig" type="hidden" value="'+t+'"/>');c(u).text(ctcAjax.cancel_txt)}};loading={rule:2,sel_ndx:2,val_qry:0,rule_val:0,sel_val:0},ctc_selectors=[],ctc_queries=[],ctc_rules=[];c(".color-picker").each(function(){k(this)});c(".ctc-option-panel-container").on("focus",".color-picker",function(){ctc_set_notice("");c(this).iris("toggle");c(".iris-picker").css({position:"absolute","z-index":10})});c(".ctc-option-panel-container").on("focus","input",function(){ctc_set_notice("");c(".color-picker").not(this).iris("hide")});c(".ctc-option-panel-container").on("change",".ctc-child-value, input[type=checkbox]",function(){f(this)});c(".ctc-option-panel-container").on("click",".ctc-selector-handle",function(u){u.preventDefault();ctc_set_notice("");var v=c(this).attr("id").toString().replace("_close",""),t=v.toString().match(/_(\d+)$/)[1];if(c("#"+v+"_container").is(":hidden")){if(1!=loading.val_qry){loading.val_qry=0}ctc_render_selector_value_inputs(t)}c("#"+v+"_container").fadeToggle("fast");c(".ctc-selector-container").not("#"+v+"_container").fadeOut("fast")});c(".nav-tab").on("click",function(t){t.preventDefault();ctc_set_notice("");var u="#"+c(this).attr("id");ctc_focus_panel(u)});c("#view_child_options,#view_parnt_options").on("click",function(w){ctc_set_notice("");var t=new Date().getTime(),v=c(this).attr("id").toString().match(/(child|parnt)/)[1],u=ctcAjax.theme_uri+"/"+ctcAjax[v]+"/style.css?"+t;c.get(u,function(x){c("#view_"+v+"_options_panel").text(x)}).fail(function(){c("#view_"+v+"_options_panel").text(ctcAjax.css_fail_txt)})});c("#ctc_load_form").on("submit",function(){return(ctc_validate()&&confirm(ctcAjax.load_txt))});c("#parent_child_options_panel").on("change","#ctc_theme_child",ctc_set_theme_menu);c(document).on("click",".ctc-save-input",function(t){ctc_save(this)});c(document).on("click",".ctc-selector-edit",function(t){ctc_selector_edit(this)});c(document).on("click",".ctc-rewrite-toggle",function(t){t.preventDefault();ctc_selector_input_toggle(this)});ctc_setup_menus();ctc_set_query(s);c("input[type=submit],input[type=button]").prop("disabled",false);setTimeout(fade_update_notice,6000)});
2
  * Script: chld-thm-cfg.js
3
  * Plugin URI: http://www.lilaeamedia.com/plugins/child-theme-configurator/
4
  * Description: Handles jQuery, AJAX and other UI
5
+ * Version: 1.3.0
6
  * Author: Lilaea Media
7
  * Author URI: http://www.lilaeamedia.com/
8
  * License: GPLv2
9
  * Copyright (C) 2013 Lilaea Media
10
  */
11
+ ;jQuery(document).ready(function(c){var l="\n",s="base",h,b={},p,q,k=function(t){c(t).iris({change:function(){f(t)}})},e=function(v){var t=parseInt(v),u=String.fromCharCode(t);return u},m=function(u){var t=u.charCodeAt(0);return t},f=function(z){var v=/^(ctc_(ovrd|\d+)_(parent|child)_([0-9a-z\-]+)_(\d+))(_\w+)?$/,A=c(z).parents(".ctc-selector-row, .ctc-parent-row").first(),y=A.find(".ctc-swatch").first(),x={parent:{},child:{}},w={parent:{origin:"",start:"",end:""},child:{origin:"",start:"",end:""}},u={child:false,parent:false},t={};A.find(".ctc-parent-value, .ctc-child-value").each(function(){var I=c(this).attr("id"),B=I.toString().match(v),J=B[2],C=B[3],L=("undefined"==typeof B[4]?"":B[4]),H=B[5],G=("undefined"==typeof B[6]?"":B[6]),K=("parent"==C?c(this).text():c(this).val()),D="ctc_"+J+"_child_"+L+"_i_"+H,F,E;if("child"==C){t[I]=K;t[D]=(c("#"+D).is(":checked"))?1:0}if(false===r(G)){switch(G){case"_border_width":x[C][L+"-width"]=K;break;case"_border_style":x[C][L+"-style"]=K;break;case"_border_color":x[C][L+"-color"]=K;break;case"_background_url":x[C]["background-image"]=i(C,K);break;case"_background_color":x[C]["background-color"]=z.value;break;case"_background_color1":w[C].start=K;u[C]=true;break;case"_background_color2":w[C].end=K;u[C]=true;break;case"_background_origin":w[C].origin=K;u[C]=true;break}}else{if(F=L.toString().match(/^border(\-(top|right|bottom|left))?$/)&&!K.match(/none/)){E=K.toString().split(/ +/);x[C][L+"-width"]="undefined"==typeof E[0]?"":E[0];x[C][L+"-style"]="undefined"==typeof E[1]?"":E[1];x[C][L+"-color"]="undefined"==typeof E[2]?"":E[2]}else{if("background-image"==L){if(K.toString().match(/url\(/)){x[C]["background-image"]=i(C,K)}else{E=K.toString().split(/ +/);if(E.length>2){w[C].origin="undefined"==typeof E[0]?"top":E[0];w[C].start="undefined"==typeof E[1]?"transparent":E[1];w[C].end="undefined"==typeof E[2]?"transparent":E[2];u[C]=true}else{x[C]["background-image"]=K}}}else{x[C][L]=K}}}});if("undefined"!=typeof y&&false===r(y.attr("id"))){c(y).removeAttr("style");if(u.parent){c(y).ctcgrad(w.parent.origin,[w.parent.start,w.parent.end])}c(y).css(x.parent);if(!(y.attr("id").toString().match(/parent/))){if(u.child){c(y).ctcgrad(w.child.origin,[w.child.start,w.child.end])}c(y).css(x.child)}}return t},n=function(u){var t,v,w;c(u).each(function(){switch(this.obj){case"imports":ctcAjax.imports=this.data;break;case"rule_val":ctcAjax.rule_val[this.key]=this.data;w=this.key;break;case"val_qry":ctcAjax.val_qry[this.key]=this.data;break;case"rule":ctcAjax.rule=this.data;break;case"sel_ndx":if(r(this.key)){ctcAjax.sel_ndx=this.data}else{if("qsid"==this.key){if(r(ctcAjax.sel_ndx[this.data.query])){ctcAjax.sel_ndx[this.data.query]={}}ctcAjax.sel_ndx[this.data.query][this.data.selector]=this.data.qsid}else{ctcAjax.sel_ndx[this.key]=this.data;t=this.key}}break;case"sel_val":ctcAjax.sel_val[this.key]=this.data;v=this.key;break;case"rewrite":p=this.key;q=this.data;break}})},i=function(x,u){var w=u.toString().match(/url\([" ]*(.+?)[" ]*\)/),v=r(w)?null:w[1],t=ctcAjax.theme_uri+"/"+("parent"==x?ctcAjax.parnt:ctcAjax.child)+"/",y;if(!v){return false}else{if(v.toString().match(/^(https?:|\/)/)){y=u}else{y="url("+t+v+")"}}return y},r=function(u){if("undefined"==typeof u||false===u||null===u||""===u){return true}if(true===u||"string"===typeof u||"number"===typeof u){return false}if("object"===typeof u){for(var t in u){if(u.hasOwnProperty(t)){return false}}return true}return false},a=function(){var t=[];if(1===loading.sel_ndx){return t}if(0===loading.sel_ndx){loading.sel_ndx=1;ctc_query_css("sel_ndx",null,ctc_setup_query_menu);return t}if(false===r(ctcAjax.sel_ndx)){c.each(ctcAjax.sel_ndx,function(u,v){var w={label:u,value:u};t.push(w)})}return t},o=function(u){var t=[];if(1===loading.sel_ndx){return t}if(0===loading.sel_ndx){loading.sel_ndx=1;ctc_query_css("sel_ndx",u,ctc_setup_selector_menu);return t}if(false===r(ctcAjax.sel_ndx[u])){c.each(ctcAjax.sel_ndx[u],function(v,w){var x={label:v,value:w};t.push(x)})}return t},d=function(){var t=[];if(1===loading.rule){return t}if(0===loading.rule){loading.rule=1;ctc_query_css("rule",null,ctc_setup_rule_menu);return t}if(false===r(ctcAjax.rule)){c.each(ctcAjax.rule,function(u,v){var w={label:v.replace(/\d+/g,e),value:u};t.push(w)})}return t.sort(function(v,u){if(v.label>u.label){return 1}if(v.label<u.label){return -1}return 0})},j=function(x,z,C){var v="",A=(r(ctcAjax.sel_val[x])||r(ctcAjax.sel_val[x].value)||r(ctcAjax.sel_val[x].value[z])?"":ctcAjax.sel_val[x].value[z]),u=ctc_decode_value(z,("undefined"==typeof A?"":A.parnt)),y=(false===r(A.i_parnt)&&A.i_parnt)?ctcAjax.important_label:"",w=ctc_decode_value(z,("undefined"==typeof A?"":A.child)),t=(false===r(A.i_child)&&A.i_child)?1:0,B="ctc_"+C+"_child_"+z+"_i_"+x;if(false===r(ctcAjax.sel_val[x])){v+='<div class="ctc-'+("ovrd"==C?"input":"selector")+'-row clearfix">'+l;v+='<div class="ctc-input-cell">'+("ovrd"==C?z.replace(/\d+/g,e):ctcAjax.sel_val[x].selector+'<br/><a href="#" class="ctc-selector-edit" id="ctc_selector_edit_'+x+'" >'+ctcAjax.edit_txt+"</a> "+(r(u.orig)?ctcAjax.child_only_txt:""))+"</div>"+l;if("ovrd"==C){v+='<div class="ctc-parent-value ctc-input-cell" id="ctc_'+C+"_parent_"+z+"_"+x+'">'+(r(u.orig)?"[no value]":u.orig+y)+"</div>"+l}v+='<div class="ctc-input-cell">'+l;if(false===r(u.names)){c.each(u.names,function(D,E){E=(r(E)?"":E);v+='<div class="ctc-child-input-cell">'+l;var G="ctc_"+C+"_child_"+z+"_"+x+E,F;if(false===(F=w.values.shift())){F=""}v+=(r(E)?"":ctcAjax.field_labels[E]+":<br/>")+'<input type="text" id="'+G+'" name="'+G+'" class="ctc-child-value'+((E+z).toString().match(/color/)?" color-picker":"")+((E).toString().match(/url/)?" ctc-input-wide":"")+'" value="'+F+'" />'+l;v+="</div>"+l});v+='<label for="'+B+'"><input type="checkbox" id="'+B+'" name="'+B+'" value="1" '+(1===t?"checked":"")+" />"+ctcAjax.important_label+"</label>"+l}v+="</div>"+l;v+=("ovrd"==C?"":'<div class="ctc-swatch ctc-specific" id="ctc_child_'+z+"_"+x+'_swatch">'+ctcAjax.swatch_txt+"</div>"+l+'<div class="ctc-child-input-cell ctc-button-cell" id="ctc_save_'+z+"_"+x+'_cell">'+l+'<input type="button" class="button ctc-save-input" id="ctc_save_'+z+"_"+x+'" name="ctc_save_'+z+"_"+x+'" value="Save" /></div>'+l);v+="</div><!-- end input row -->"+l}return v},g=function(t){if(1===loading.sel_val){return false}if(0==loading.sel_val){loading.sel_val=1;ctc_query_css("sel_val",t,g);return false}var w,u,v;if(r(ctcAjax.sel_val[t])){c("#ctc_sel_ovrd_rule_inputs").html("")}else{if(r(ctcAjax.sel_val[t].seq)){c("#ctc_child_load_order_container").html("")}else{w="ctc_ovrd_child_seq_"+t;v=parseInt(ctcAjax.sel_val[t].seq);u='<input type="text" id="'+w+'" name="'+w+'" class="ctc-child-value" value="'+v+'" />';c("#ctc_child_load_order_container").html(u)}if(r(ctcAjax.sel_val[t].value)){c("#ctc_sel_ovrd_rule_inputs").html("")}else{u="";c.each(ctcAjax.sel_val[t].value,function(y,x){u+=j(t,y,"ovrd")});c("#ctc_sel_ovrd_rule_inputs").html(u).find(".color-picker").each(function(){k(this)});f("#ctc_child_all_0_swatch")}}};ctc_render_css_preview=function(t){if(1===loading.preview){return false}if(0==loading.preview){loading.preview=1;var t;if(!(t=c(this).attr("id").toString().match(/(child|parnt)/)[1])){t="child"}ctc_set_notice("");ctc_query_css("preview",t,ctc_render_css_preview);return false}if(2==loading.preview){c("#view_"+t+"_options_panel").text(ctcAjax.previewResponse);loading.preview=0}},ctc_render_rule_value_inputs=function(u){if(1===loading.rule_val){return false}if(0==loading.rule_val){loading.rule_val=1;ctc_query_css("rule_val",u,ctc_render_rule_value_inputs);return false}var v=ctcAjax.rule[u],t='<div class="ctc-input-row clearfix" id="ctc_rule_row_'+v+'">'+l;if(false===r(ctcAjax.rule_val[u])){c.each(ctcAjax.rule_val[u],function(x,y){var w=ctc_decode_value(v,y);t+='<div class="ctc-parent-row clearfix" id="ctc_rule_row_'+v+"_"+x+'">'+l;t+='<div class="ctc-input-cell ctc-parent-value" id="ctc_'+x+"_parent_"+v+"_"+x+'">'+w.orig+"</div>"+l;t+='<div class="ctc-input-cell">'+l;t+='<div class="ctc-swatch ctc-specific" id="ctc_'+x+"_parent_"+v+"_"+x+'_swatch">'+ctcAjax.swatch_txt+"</div></div>"+l;t+='<div class="ctc-input-cell"><a href="#" class="ctc-selector-handle" id="ctc_selector_'+v+"_"+x+'">'+ctcAjax.selector_txt+"</a></div>"+l;t+='<div id="ctc_selector_'+v+"_"+x+'_container" class="ctc-selector-container clearfix">'+l;t+='<a href="#" id="ctc_selector_'+v+"_"+x+'_close" class="ctc-selector-handle" style="float:right">'+ctcAjax.close_txt+'</a><div id="ctc_status_val_qry_'+x+'"></div>'+l;t+='<div id="ctc_selector_'+v+"_"+x+'_rows"></div>'+l;t+="</div></div>"+l});t+="</div>"+l}c("#ctc_rule_value_inputs").html(t).find(".ctc-swatch").each(function(){f(this)})},ctc_render_selector_value_inputs=function(w){if(1==loading.val_qry){return false}var y,u,x=c("#ctc_rule_menu_selected").text().replace(/[^\w\-]/g,m),t,v="";if(0===loading.val_qry){loading.val_qry=1;y={rule:x};ctc_query_css("val_qry",w,ctc_render_selector_value_inputs,y);return false}if(false===r(ctcAjax.val_qry[w])){c.each(ctcAjax.val_qry[w],function(A,z){page_rule=A;c.each(z,function(C,B){v+='<h4 class="ctc-query-heading">'+C+"</h4>"+l;if(false===r(B)){c.each(B,function(D,E){ctcAjax.sel_val[D]=E;v+=j(D,A,w)})}})})}t="#ctc_selector_"+x+"_"+w+"_rows";c(t).html(v).find(".color-picker").each(function(){k(this)});c(t).find(".ctc-swatch").each(function(){f(this)})},ctc_query_css=function(v,u,y,w){var t={ctc_query_obj:v,ctc_query_key:u},x="#ctc_status_"+v+("val_qry"==v?"_"+u:"");if("object"===typeof w){c.each(w,function(z,A){t["ctc_query_"+z]=A})}c(".ctc-status-icon").remove();c(x).append('<span class="ctc-status-icon spinner"></span>');c(".spinner").show();t.action="ctc_query";t._wpnonce=c("#_wpnonce").val();c.post(ctcAjax.ajaxurl,t,function(z){loading[v]=2;c(".ctc-status-icon").removeClass("spinner");if(r(z)){c(".ctc-status-icon").addClass("failure");if("preview"==v){ctcAjax.previewResponse=ctcAjax.css_fail_txt;y(u)}}else{c(".ctc-status-icon").addClass("success");if("preview"==v){ctcAjax.previewResponse=z.shift().data}else{n(z)}if("function"===typeof y){y(u)}return false}},"json").fail(function(){c(".ctc-status-icon").removeClass("spinner");c(".ctc-status-icon").addClass("failure");if("preview"==v){ctcAjax.previewResponse=ctcAjax.css_fail_txt;loading[v]=2;y(u)}else{loading[v]=0}});return false},ctc_save=function(y){var w={},z,v,t,u,A=c(y).attr("id"),x;if(r(b[A])){b[A]=0}b[A]++;c(y).prop("disabled",true);c(".ctc-status-icon").remove();c(y).parent(".ctc-textarea-button-cell, .ctc-button-cell").append('<span class="ctc-status-icon spinner"></span>');c(".spinner").show();if((z=c("#ctc_new_selectors"))&&"ctc_save_new_selectors"==c(y).attr("id")){w.ctc_new_selectors=z.val();if(v=c("#ctc_sel_ovrd_query_selected")){w.ctc_sel_ovrd_query=v.text()}}else{if((t=c("#ctc_child_imports"))&&"ctc_save_imports"==c(y).attr("id")){w.ctc_child_imports=t.val()}else{w=f(y)}}c("#ctc_sel_ovrd_selector_selected").find("#ctc_rewrite_selector").each(function(){x=c("#ctc_rewrite_selector").val(),origsel=c("#ctc_rewrite_selector_orig").val();if(r(x)||!x.toString().match(/\w/)){x=origsel}else{w.ctc_rewrite_selector=x}c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_sel_ovrd_selector_selected").html(x)});w.action="ctc_update";w._wpnonce=c("#_wpnonce").val();c.post(ctcAjax.ajaxurl,w,function(B){c(y).prop("disabled",false);c(".ctc-status-icon").removeClass("spinner");if(r(B)){c(".ctc-status-icon").addClass("failure")}else{c(".ctc-status-icon").addClass("success");c("#ctc_new_selectors").val("");n(B);ctc_setup_menus();if(false===r(p)){ctc_set_selector(p,q);p=q=null}}return false},"json").fail(function(){c(y).prop("disabled",false);c(".ctc-status-icon").removeClass("spinner");c(".ctc-status-icon").addClass("failure")});return false},ctc_decode_value=function(v,t){t=("undefined"==typeof t?"":t);var u={orig:t};if(v.toString().match(/^border(\-(top|right|bottom|left))?$/)){var w=t.toString().split(/ +/);u.names=["_border_width","_border_style","_border_color"];u.values=[("undefined"==typeof w[0]?"":w[0]),("undefined"==typeof w[1]?"":w[1]),("undefined"==typeof w[2]?"":w[2])]}else{if(v.toString().match(/^background\-image/)){u.names=["_background_url","_background_origin","_background_color1","_background_color2"];u.values=["","","",""];if(false===(r(t))&&!(t.toString().match(/url/))){var w=t.toString().split(/:/);u.values[1]=("undefined"==typeof w[0]?"":w[0]);u.values[2]=("undefined"==typeof w[1]?"":w[1]);u.values[3]=("undefined"==typeof w[3]?"":w[3]);u.orig=[u.values[1],u.values[2],u.values[3]].join(" ")}else{u.values[0]=t}}else{u.names=[""];u.values=[t]}}return u},ctc_set_query=function(t){s=t;c("#ctc_sel_ovrd_query").val("");c("#ctc_sel_ovrd_query_selected").text(t);c("#ctc_sel_ovrd_selector").val("");c("#ctc_sel_ovrd_selector_selected").html("&nbsp;");c("#ctc_sel_ovrd_rule_inputs").html("");ctc_setup_selector_menu(t);f("#ctc_child_all_0_swatch");c("#ctc_new_selector_row").show()},ctc_set_selector=function(u,t){c("#ctc_sel_ovrd_selector").val("");c("#ctc_sel_ovrd_selector_selected").text(t);c("#ctc_sel_ovrd_qsid").val(u);h=u;if(1!=loading.sel_val){loading.sel_val=0}g(u);c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_sel_ovrd_new_rule, #ctc_sel_ovrd_rule_header,#ctc_sel_ovrd_rule_inputs_container,#ctc_sel_ovrd_rule_inputs,.ctc-rewrite-toggle").show()},ctc_set_rule=function(u,t){c("#ctc_rule_menu").val("");c("#ctc_rule_menu_selected").text(t);if(1!=loading.rule_val){loading.rule_val=0}ctc_render_rule_value_inputs(u);c(".ctc-rewrite-toggle").text(ctcAjax.rename_txt);c("#ctc_rule_value_inputs,#ctc_input_row_rule_header").show()},ctc_setup_query_menu=function(){ctc_queries=a();c("#ctc_sel_ovrd_query").autocomplete({source:ctc_queries,minLength:0,selectFirst:true,autoFocus:true,select:function(u,t){ctc_set_query(t.item.value);return false},focus:function(t){t.preventDefault()}})},ctc_setup_selector_menu=function(t){ctc_selectors=o(t);c("#ctc_sel_ovrd_selector").autocomplete({source:ctc_selectors,selectFirst:true,autoFocus:true,select:function(v,u){ctc_set_selector(u.item.value,u.item.label);return false},focus:function(u){u.preventDefault()}})},ctc_setup_rule_menu=function(){ctc_rules=d();c("#ctc_rule_menu").autocomplete({source:ctc_rules,selectFirst:true,autoFocus:true,select:function(u,t){ctc_set_rule(t.item.value,t.item.label);return false},focus:function(t){t.preventDefault()}})},ctc_filtered_rules=function(w,u){var t=[],v=(r(ctcAjax.sel_val[h]))||(r(ctcAjax.sel_val[h].value));if(r(ctc_rules)){ctc_rules=d()}c.each(ctc_rules,function(x,A){var y=false,z=new RegExp(c.ui.autocomplete.escapeRegex(w.term),"i");if(z.test(A.label)){if(false===v){c.each(ctcAjax.sel_val[h].value,function(C,B){if(A.label==C.replace(/\d+/g,e)){y=true;return false}});if(y){return}}t.push(A)}});u(t)},ctc_setup_new_rule_menu=function(){c("#ctc_new_rule_menu").autocomplete({source:ctc_filtered_rules,selectFirst:true,autoFocus:true,select:function(u,t){u.preventDefault();var v=c(j(h,t.item.label.replace(/[^\w\-]/g,m),"ovrd"));c("#ctc_sel_ovrd_rule_inputs").append(v);c("#ctc_new_rule_menu").val("");if(r(ctcAjax.sel_val[h].value)){ctcAjax.sel_val[h]["value"]={}}ctcAjax.sel_val[h].value[t.item.label]={child:""};v.find('input[type="text"]').each(function(w,x){if(c(x).hasClass("color-picker")){k(x)}c(x).focus()});return false},focus:function(t){t.preventDefault()}})},ctc_setup_menus=function(){ctc_setup_query_menu();ctc_setup_selector_menu(s);ctc_setup_rule_menu();ctc_setup_new_rule_menu()},ctc_theme_exists=function(t,u){var v=false;c.each(ctcAjax.themes,function(w,x){c.each(x,function(y,z){if(y==t&&("parnt"==w||"new"==u)){v=true;return false}});if(v){return false}});return v},ctc_set_notice=function(t){var u="";if(false===r(t)){c.each(t,function(v,w){u+='<div class="'+v+'"><ul>'+l;c(w).each(function(x,y){u+="<li>"+y.toString()+"</li>"+l});u+="</ul></div>"})}c("#ctc_error_notice").html(u)},ctc_validate=function(){var w=/[^\w\-]/,u=c("#ctc_child_template").val().toString().replace(w).toLowerCase(),t=c("#ctc_theme_child").val().toString().replace(w).toLowerCase(),v=c("input[name=ctc_child_type]:checked").val(),x=[];if("new"==v){t=u}if(ctc_theme_exists(t,v)){x.push(ctcAjax.theme_exists_txt.toString().replace(/%s/,t))}if(""===t){x.push(ctcAjax.inval_theme_txt)}if(""===c("#ctc_child_name").val()){x.push(ctcAjax.inval_name_txt)}if(x.length){ctc_set_notice({error:x});return false}return true},ctc_set_theme_menu=function(u){var t=c("#ctc_theme_child").val();if(false===r(ctcAjax.themes.child[t])){c("#ctc_child_name").val(ctcAjax.themes.child[t].Name);c("#ctc_child_author").val(ctcAjax.themes.child[t].Author);c("#ctc_child_version").val(ctcAjax.themes.child[t].Version)}},fade_update_notice=function(){c(".updated, .error").slideUp("slow",function(){c(".updated").remove()})},ctc_focus_panel=function(u){var t=u+"_panel";c(".nav-tab").removeClass("nav-tab-active");c(".ctc-option-panel").removeClass("ctc-option-panel-active");c(".ctc-selector-container").hide();c(u).addClass("nav-tab-active");c(".ctc-option-panel-container").scrollTop(0);c(t).addClass("ctc-option-panel-active")},ctc_selector_edit=function(w){var t=c(w).attr("id").match(/_(\d+)$/)[1],v=ctcAjax.sel_val[t].query,u=ctcAjax.sel_val[t].selector,x="#query_selector_options";ctc_set_query(v);ctc_set_selector(t,u);ctc_focus_panel(x)},ctc_selector_input_toggle=function(u){var t;if(c("#ctc_rewrite_selector").length){t=c("#ctc_rewrite_selector_orig").val();c("#ctc_sel_ovrd_selector_selected").text(t);c(u).text(ctcAjax.rename_txt)}else{t=c("#ctc_sel_ovrd_selector_selected").text();c("#ctc_sel_ovrd_selector_selected").html('<input id="ctc_rewrite_selector" name="ctc_rewrite_selector" type="text" value="'+t+'" autocomplete="off" /><input id="ctc_rewrite_selector_orig" name="ctc_rewrite_selector_orig" type="hidden" value="'+t+'"/>');c(u).text(ctcAjax.cancel_txt)}};loading={rule:2,sel_ndx:2,val_qry:0,rule_val:0,sel_val:0,preview:0},ctc_selectors=[],ctc_queries=[],ctc_rules=[];c(".color-picker").each(function(){k(this)});c(".ctc-option-panel-container").on("focus",".color-picker",function(){ctc_set_notice("");c(this).iris("toggle");c(".iris-picker").css({position:"absolute","z-index":10})});c(".ctc-option-panel-container").on("focus","input",function(){ctc_set_notice("");c(".color-picker").not(this).iris("hide")});c(".ctc-option-panel-container").on("change",".ctc-child-value, input[type=checkbox]",function(){f(this)});c(".ctc-option-panel-container").on("click",".ctc-selector-handle",function(u){u.preventDefault();ctc_set_notice("");var v=c(this).attr("id").toString().replace("_close",""),t=v.toString().match(/_(\d+)$/)[1];if(c("#"+v+"_container").is(":hidden")){if(1!=loading.val_qry){loading.val_qry=0}ctc_render_selector_value_inputs(t)}c("#"+v+"_container").fadeToggle("fast");c(".ctc-selector-container").not("#"+v+"_container").fadeOut("fast")});c(".nav-tab").on("click",function(t){t.preventDefault();ctc_set_notice("");c(".ctc-status-icon").remove();var u="#"+c(this).attr("id");ctc_focus_panel(u)});c("#view_child_options,#view_parnt_options").on("click",ctc_render_css_preview);c("#ctc_load_form").on("submit",function(){return(ctc_validate()&&confirm(ctcAjax.load_txt))});c("#parent_child_options_panel").on("change","#ctc_theme_child",ctc_set_theme_menu);c(document).on("click",".ctc-save-input",function(t){ctc_save(this)});c(document).on("click",".ctc-selector-edit",function(t){ctc_selector_edit(this)});c(document).on("click",".ctc-rewrite-toggle",function(t){t.preventDefault();ctc_selector_input_toggle(this)});ctc_setup_menus();ctc_set_query(s);c("input[type=submit],input[type=button]").prop("disabled",false);setTimeout(fade_update_notice,6000)});
readme.txt CHANGED
@@ -4,7 +4,7 @@ Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_i
4
  Tags: child theme, custom theme, CSS, responsive design, CSS editor, theme generator
5
  Requires at least: 3.7
6
  Tested up to: 3.8
7
- Stable tag: 1.2.3
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
@@ -125,6 +125,12 @@ You can also create a secondary stylesheet that contains @font-face rules and im
125
 
126
  == Changelog ==
127
 
 
 
 
 
 
 
128
  = 1.2.3 =
129
  * Replace PHP short tags with standard codes.
130
 
4
  Tags: child theme, custom theme, CSS, responsive design, CSS editor, theme generator
5
  Requires at least: 3.7
6
  Tested up to: 3.8
7
+ Stable tag: 1.3.0
8
  License: GPLv2 or later
9
  License URI: http://www.gnu.org/licenses/gpl-2.0.html
10
 
125
 
126
  == Changelog ==
127
 
128
+ = 1.3.0 =
129
+ * Changed CSS preview to retrieve directly from WordPress Admin instead of remote http GET to prevent caching issues.
130
+ * Added loading icon for CSS preview.
131
+ * Fixed JS type error on backup toggle.
132
+ * Improved extensibility throughout.
133
+
134
  = 1.2.3 =
135
  * Replace PHP short tags with standard codes.
136