PluginProbe
Customify / 1.3.0
Customify v1.3.0
2.10.9 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.7.1 1.3.0 1.3.1 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.6.0 1.6.0.1 1.6.5 1.7.0 1.7.1 All 77 releases
customify / js / customizer.js

customizer.js in Customify 1.3.0, at js/customizer.js

1,369 lines 40.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 (function ( $, exports ) {
2 $(document).ready(function () {
3 // when the customizer is ready prepare our fields events
4 wp.customize.bind('ready', function () {
5 var api = this,
6 timeout = null;
7
8 // add ace editors
9 $('.customify_ace_editor').each(function ( key, el ) {
10 var id = $(this).attr('id'),
11 css_editor = ace.edit(id);
12
13 var editor_type = $(this).data('editor_type');
14 // init the ace editor
15 css_editor.setTheme("ace/theme/github");
16 css_editor.getSession().setMode("ace/mode/" + editor_type);
17
18 // hide the textarea and enable the ace editor
19 var textarea = $('#' + id + '_textarea').hide();
20 css_editor.getSession().setValue(textarea.val());
21
22 // each time a change is triggered start a timeout of 1,5s and when is finished refresh the previewer
23 // if the user types faster than this delay then reset it
24 css_editor.getSession().on('change', function ( e ) {
25 if ( timeout !== null ) {
26 clearTimeout(timeout);
27 timeout = null;
28 } else {
29 timeout = setTimeout(function () {
30 //var state = css_editor.session.getState();
31 textarea.val(css_editor.getSession().getValue());
32 textarea.trigger('change');
33 }, 1500);
34 }
35 });
36 });
37
38 // simple select2 field
39 $('.customify_select2').select2();
40
41 customifyFontSelect.init(this);
42
43 prepare_typography_field();
44
45 /**
46 * Make the customizer save on CMD/CTRL+S action
47 * This is awesome!!!
48 */
49 $(window).bind('keydown', function ( event ) {
50 if ( event.ctrlKey || event.metaKey ) {
51 switch ( String.fromCharCode(event.which).toLowerCase() ) {
52 case 's':
53 event.preventDefault();
54 api.previewer.save();
55 break;
56 }
57 }
58 });
59
60 // for each range input add a value preview output
61 $('input[type="range"]').each(function () {
62 var $clone = $(this).clone();
63
64 $clone
65 .attr('type', 'number')
66 .attr('class', 'range-value');
67
68 $(this).after($clone);
69
70 $(this).on('input', function () {
71 $(this).siblings('.range-value').val($(this).val());
72 });
73 });
74
75 if ( $('button[data-action="reset_customify"]').length > 0 ) {
76 // reset_button
77 $(document).on('click', '#customize-control-reset_customify button', function ( ev ) {
78 ev.preventDefault();
79
80 var iAgree = confirm('Do you really want to reset to defaults all the fields? Watch out, this will reset all your Customify options and will save them!');
81
82 if ( !iAgree ) {
83 return;
84 }
85
86 $.each(api.settings.controls, function ( key, ctrl ) {
87 var id = key.replace('_control', '');
88 var setting = customify_settings.settings[id];
89
90 if ( !_.isUndefined(setting) && !_.isUndefined(setting.default) ) {
91
92 var start_pos = id.indexOf('[') + 1;
93 var end_pos = id.indexOf(']', start_pos);
94
95 id = id.substring(start_pos, end_pos);
96 api_set_setting_value(id, setting.default);
97 }
98 });
99
100 api.previewer.save();
101 });
102
103 // add a reset button for each panel
104 $('.panel-meta').each(function ( el, key ) {
105 var container = $(this).parents('.control-panel'),
106 id = container.attr('id'),
107 panel_id = id.replace('accordion-panel-', '');
108
109
110 $(this).parent().append('<button class="reset_panel button" data-panel="' + panel_id + '">Panel\'s defaults</button>');
111 });
112
113 // reset panel
114 $(document).on('click', '.reset_panel', function ( e ) {
115 e.preventDefault();
116
117 var panel_id = $(this).data('panel'),
118 panel = api.panel(panel_id),
119 sections = panel.sections(),
120 iAgree = confirm("Do you really want to reset " + panel.params.title + "?");
121
122 if ( !iAgree ) {
123 return;
124 }
125 if ( sections.length > 0 ) {
126 $.each(sections, function () {
127 //var settings = this.settings();
128 var controls = this.controls();
129
130 if ( controls.length > 0 ) {
131 $.each(controls, function ( key, ctrl ) {
132 var id = ctrl.id.replace('_control', ''),
133 setting = customify_settings.settings[id];
134
135 if ( !_.isUndefined(setting) && !_.isUndefined(setting.default) ) {
136
137 var start_pos = id.indexOf('[') + 1,
138 end_pos = id.indexOf(']', start_pos);
139
140 id = id.substring(start_pos, end_pos);
141 api_set_setting_value(id, setting.default);
142 }
143 });
144 }
145 });
146 }
147 });
148
149 //add reset section
150 $('.accordion-section-content').each(function ( el, key ) {
151 var section = $(this).parent(),
152 section_id = section.attr('id');
153
154 if ( ( ( !_.isUndefined(section_id) ) ? section_id.indexOf(customify_settings.options_name) : -1 ) === -1 ) {
155 return;
156 }
157
158 if ( !_.isUndefined(section_id) && section_id.indexOf('accordion-section-') > -1 ) {
159 var id = section_id.replace('accordion-section-', '');
160 $(this).prepend('<button class="reset_section button" data-section="' + id + '">Section\'s defaults</button>');
161 }
162 });
163
164 // reset section event
165 $(document).on('click', '.reset_section', function ( e ) {
166 e.preventDefault();
167
168 var section_id = $(this).data('section'),
169 section = api.section(section_id),
170 controls = section.controls();
171
172 var iAgree = confirm("Do you really want to reset " + section.params.title + "?");
173
174 if ( !iAgree ) {
175 return;
176 }
177
178 if ( controls.length > 0 ) {
179 $.each(controls, function ( key, ctrl ) {
180 var id = ctrl.id.replace('_control', ''),
181 setting = customify_settings.settings[id];
182
183 if ( !_.isUndefined(setting) && !_.isUndefined(setting.default) ) {
184
185 var start_pos = id.indexOf('[') + 1,
186 end_pos = id.indexOf(']', start_pos);
187
188 id = id.substring(start_pos, end_pos);
189 api_set_setting_value(id, setting.default);
190 }
191 });
192 }
193 });
194 }
195
196 $(document).on('change', '.customize-control input.range-value', function () {
197 var range = $(this).siblings('input[type="range"]');
198 range.val($(this).val());
199 });
200
201 $(document).on('change', '.customify_typography_font_subsets', function ( ev ) {
202
203 var $input = $(this).parents('.options').siblings('.customify_typography').children('.customify_typography_values'),
204 current_val = $input.val();
205
206 current_val = JSON.parse(decodeURIComponent(current_val));
207
208 //maybe the selected option holds a JSON in its value
209 current_val.selected_subsets = maybeJsonParse($(this).val());
210
211 $input.val(encodeURIComponent(JSON.stringify(current_val)));
212
213 $input.trigger('change');
214 });
215
216 $(document).on('change', '.customify_typography_font_weight', function ( ev ) {
217
218 var $input = $(this).parents('.options').siblings('.customify_typography').children('.customify_typography_values'),
219 current_val = $input.val();
220
221 current_val = maybeJsonParse(current_val);
222 // @todo currently the font weight selector works for one value only
223 // maybe make this a multiselect
224
225 //maybe the selected option holds a JSON in its value
226 current_val.selected_variants = {0: maybeJsonParse($(this).val())};
227
228 $input.val(encodeURIComponent(JSON.stringify(current_val)));
229 $input.trigger('change');
230 });
231
232 // presets
233 $(document).on('change', '.customify_preset.select', function () {
234 var api = wp.customize,
235 this_option = $(this).children('[value="' + $(this).val() + '"]'),
236 data = $(this_option).data('options');
237
238 if ( !_.isUndefined(data) ) {
239 $.each(data, function ( id, value ) {
240 api_set_setting_value(id, value);
241 });
242 }
243
244 api.previewer.refresh();
245 });
246
247 $(document).on('click', '.customify_preset.radio input, .customify_preset.radio_buttons input, .awesome_presets input', function () {
248 var api = wp.customize;
249 var this_option = this;//$(this).children('[value="' + $(this).val() + '"]');
250 var data = $(this_option).data('options');
251
252 if ( !_.isUndefined(data) ) {
253 $.each(data, function ( id, value ) {
254 api_set_setting_value(id, value);
255 });
256 }
257
258 api.previewer.refresh();
259 });
260
261 // bind our event on click
262 $(document).on('click', '.customify_import_demo_data_button', function ( event ) {
263 //if ( $( this ).hasClass( '.wpGrade_button_inactive' ) ) {
264 // return false;
265 //} else {
266 // $( this ).addClass( '.wpGrade_button_inactive' );
267 // $( this ).attr( 'disabled', 'disabled' );
268 //}
269 //var confirmImport = confirm( listable_demodata_params.l10n.import_confirm );
270 //if ( confirmImport == false ) return false;
271
272 //@todo start an animation here
273 var key = $(this).data('key');
274
275 var import_queue = new Queue(api);
276
277 /// calculate the number of steps
278 var steps = [];
279
280 if ( !_.isUndefined(customify_settings.settings[key].imports) ) {
281
282 $.each(customify_settings.settings[key].imports, function ( i, import_setts, k ) {
283 if ( _.isUndefined(import_setts.steps) ) {
284 steps.push({id: i, type: import_setts.type});
285 } else {
286 var count = import_setts.steps;
287
288 while ( count >= 1 ) {
289 steps.push({id: i, type: import_setts.type, count: count});
290 count = count - 1;
291 }
292 }
293 });
294 }
295
296 import_queue.add_steps('import_demo_data_action_id', steps);
297 return false;
298 });
299
300 customifyBackgroundJsControl.init();
301
302 // sometimes there may be needed a php save
303 if ( getUrlVars('save_customizer_once') ) {
304 api.previewer.save();
305 }
306
307 setTimeout(function () {
308 customifyFoldingFields();
309 }, 1000);
310
311
312 // Handle the section tabs (ex: Layout | Fonts | Colors)
313 (function() {
314 var $navs = $( '.js-section-navigation' );
315
316 $navs.each( function () {
317 var $nav = $( this );
318 var $title = $nav.parents( '.accordion-section-content' ).find( '.customize-section-title' );
319
320 $title.append( $nav ).parent().addClass( 'has-nav' );
321 });
322
323 $('.js-section-navigation a').on( 'click', function(e) {
324 e.preventDefault();
325
326 var $sidebar = $('.wp-full-overlay-sidebar-content');
327 var $parent = $(this).parents( '.accordion-section-content' );
328 var href = $.attr(this, 'href');
329
330 if ( href != '#' ) {
331 $sidebar.animate({
332 scrollTop: $( $.attr(this, 'href') ).position().top - $parent.find( '.customize-section-title' ).outerHeight()
333 }, 500);
334 }
335 });
336 })();
337 });
338
339 /**
340 * This function will search for all the interdependend fields and make a bound between them.
341 * So whenever a target is changed, it will take actions to the dependent fields.
342 */
343 var customifyFoldingFields = function () {
344
345 if ( _.isUndefined(customify_settings) || _.isUndefined(customify_settings.settings) ) {
346 return; // bail
347 }
348
349 /**
350 * Let's iterate through all the customify settings and gather all the fields that have a "show_on"
351 * property set.
352 *
353 * At the end `targets` will hold a list of [ target : [field, field,...], ... ]
354 * so when a target is changed we will change all the fields.
355 */
356 var targets = {};
357
358 $.fn.reactor.defaults.compliant = function () {
359 $(this).slideDown();
360 // $(this).animate({opacity: 1});
361 $(this).find(':disabled').attr({disabled: false});
362 };
363
364 $.fn.reactor.defaults.uncompliant = function () {
365 $(this).slideUp();
366 // $(this).animate({opacity: 0.25});
367 $(this).find(':enabled').attr({disabled: true});
368 };
369
370 var IS = $.extend({}, $.fn.reactor.helpers);
371
372 var process_a_target = function ( parent_id, field ) {
373
374 if ( _.isUndefined(field[0]) ) {
375 return; // no id, no fun
376 }
377
378 var key = field[0],
379 value = 1, // by default we use 1 the most used value for checboxes or inputs
380 compare = '==', // ... ye
381 action = "show"; // can only be `show` or `hide`
382
383 var target_key = customify_settings.options_name + '[' + key + ']';
384 var target_type = customify_settings.settings[target_key].type;
385
386
387 if ( !_.isUndefined(field[1]) ) {
388 value = field[1];
389 }
390
391 if ( !_.isUndefined(field[2]) ) {
392 compare = field[2];
393 }
394
395 if ( !_.isUndefined(field[3]) ) {
396 action = field[3];
397 }
398
399 /**
400 * Now for each target we have, we will bind a change event to hide or show the dependent fields
401 */
402 var target_selector = '[data-customize-setting-link="' + customify_settings.options_name + '[' + key + ']"]';
403
404 if ( target_type == 'checkbox' ) {
405 $(parent_id).reactIf(target_selector, function () {
406 return $(this).is(':checked') == value;
407 });
408 } else if ( target_type == 'radio' || target_type == 'radio_image' ) {
409 $(parent_id)
410 .reactIf(target_selector, function () {
411 return $(target_selector + ':checked').val() == value;
412 });
413 } else {
414 $(parent_id)
415 .reactIf(target_selector, function () {
416 return $(target_selector).val() == value;
417 });
418 }
419
420 $(target_selector).trigger('change');
421 $('.reactor').trigger('change.reactor'); // triggers all events on load
422 };
423
424 $.each(customify_settings.settings, function ( id, field ) {
425
426 /**
427 * Here we have the id of the fields. but we know for sure that we just need his parent selector
428 * So we just create it
429 */
430 var parent_id = id.replace('[', '-');
431 parent_id = parent_id.replace(']', '');
432 parent_id = '#customize-control-' + parent_id + '_control';
433
434
435 // get only the fields that have a 'show_on' property
436 if ( field.hasOwnProperty('show_on') && field.show_on.length > 0 ) {
437
438 /**
439 * The 'show_on' can be a simple array with one target like: [ id, value, comparison, action ]
440 * Or it could be an array of multiple targets and we need to process both cases
441 */
442 if ( _.isString(field.show_on[0]) ) {
443 process_a_target(parent_id, field.show_on);
444 } else if ( _.isObject(field.show_on[0]) ) {
445 $.each(field.show_on, function ( i, j ) {
446 process_a_target(parent_id, j);
447 });
448 }
449 }
450 });
451 };
452
453 var get_typography_font_family = function ( $el ) {
454
455 var font_family_value = $el.val();
456 // first time this will not be a json so catch that error
457 try {
458 font_family_value = JSON.parse(font_family_value);
459 } catch ( e ) {
460 return {font_family: font_family_value};
461 }
462
463 if ( !_.isUndefined(font_family_value.font_family) ) {
464 return font_family_value.font_family;
465 }
466
467 return false;
468 };
469
470 // get each typography field and bind events
471 var prepare_typography_field = function () {
472
473 var $typos = $('.customify_typography_font_family');
474
475 $typos.each(function () {
476 var font_family_select = this,
477 $input = $(font_family_select).siblings('.customify_typography_values');
478 // on change
479 $(font_family_select).on('change', function () {
480 update_siblings_selects(font_family_select);
481 $input.trigger('change');
482 });
483 update_siblings_selects(font_family_select);
484 });
485 };
486
487 var api_set_setting_value = function ( id, value ) {
488
489 var api = wp.customize,
490 setting_id = customify_settings.options_name + '[' + id + ']',
491 setting = api(setting_id),
492 field = $('[data-customize-setting-link="' + setting_id + '"]'),
493 field_class = $(field).parent().attr('class');
494
495 if ( !_.isUndefined(field_class) && field_class === 'customify_typography' ) {
496
497 var family_select = field.siblings('select');
498
499 if ( _.isString(value) ) {
500 var this_option = family_select.find('option[value="' + value + '"]');
501 $(this_option[0]).attr('selected', 'selected');
502 update_siblings_selects(family_select);
503 } else if ( _.isObject(value) ) {
504 var this_family_option = family_select.find('option[value="' + value['font_family'] + '"]');
505 $(this_family_option[0]).attr('selected', 'selected');
506
507 update_siblings_selects(this_family_option);
508
509 setTimeout(function () {
510 var weight_select = field.parent().siblings('.options').find('.customify_typography_font_weight');
511
512 var this_weight_option = weight_select.find('option[value="' + value['selected_variants'] + '"]');
513
514 $(this_weight_option[0]).attr('selected', 'selected');
515
516 update_siblings_selects(this_family_option);
517
518 weight_select.trigger('change');
519 }, 300);
520 }
521
522 family_select.trigger('change');
523
524 } else {
525 setting.set(value);
526 }
527 };
528
529 var update_siblings_selects = function ( font_select ) {
530
531 this.bound_once = false;
532 var selected_font = $(font_select).val(),
533 $input = $(font_select).siblings('.customify_typography_values'),
534 current_val = $input.attr('value');
535
536 if ( current_val === '[object Object]' ) {
537 current_val = $input.data('default');
538 } else if ( _.isString(current_val) && !isJsonString(current_val) && current_val.substr(0, 1) == '[' ) {
539 // a rare case when the value isn't a json but is a representative string like [family,weight]
540 current_val = current_val.split(',');
541 var new_current_value = {};
542 if ( !_.isUndefined(current_val[0]) ) {
543 new_current_value['font_family'] = current_val[0];
544 }
545
546 if ( !_.isUndefined(current_val[1]) ) {
547 new_current_value['selected_variants'] = current_val[1];
548 }
549
550 current_val = JSON.stringify(new_current_value);
551 }
552
553 var $font_weight = $(font_select).parent().siblings('ul.options').find('.customify_typography_font_weight'),
554 $font_subsets = $(font_select).parent().siblings('ul.options').find('.customify_typography_font_subsets');
555
556 try {
557 current_val = JSON.parse(decodeURIComponent(current_val));
558 } catch ( e ) {
559
560 // in case of an error, force the rebuild of the json
561 if ( _.isUndefined($(font_select).data('bound_once')) ) {
562
563 $(font_select).data('bound_once', true);
564 //var api = wp.customize;
565 //api.previewer.refresh();
566
567 $(font_select).change();
568 $font_weight.change();
569 $font_subsets.change();
570 }
571 }
572
573 // first try to get the font from sure sources, not from the recommended list.
574 var option_data = $(font_select).find(':not(optgroup[label=Recommended]) option[value="' + selected_font + '"]');
575 // however, if there isn't an option found, get what you can
576 if ( option_data.length < 1 ) {
577 option_data = $(font_select).find('option[value="' + selected_font + '"]');
578 }
579
580 if ( option_data.length > 0 ) {
581
582 var font_type = option_data.data('type'),
583 value_to_add = {'type': font_type, 'font_family': selected_font},
584 variants = null,
585 subsets = null;
586
587 if ( font_type == 'std' ) {
588 variants = {
589 0: '100',
590 1: '200',
591 3: '300',
592 4: '400',
593 5: '500',
594 6: '600',
595 7: '700',
596 8: '800',
597 9: '900'
598 };
599 if ( !_.isUndefined($(option_data[0]).data('variants')) ) {
600 //maybe the variants are a JSON
601 variants = maybeJsonParse($(option_data[0]).data('variants'));
602 }
603 } else {
604 //maybe the variants are a JSON
605 variants = maybeJsonParse($(option_data[0]).data('variants'));
606
607 //maybe the subsets are a JSON
608 subsets = maybeJsonParse($(option_data[0]).data('subsets'));
609 }
610
611 // make the variants selector
612 if ( !_.isUndefined(variants) && !_.isNull(variants) && !_.isEmpty(variants) ) {
613
614 value_to_add['variants'] = variants;
615 // when a font is selected force the first weight to load
616 value_to_add['selected_variants'] = {0: variants[0]};
617
618 var variants_options = '',
619 count_weights = 0;
620
621 if ( _.isArray(variants) || _.isObject(variants) ) {
622 // Take each variant and produce the option markup
623 $.each(variants, function ( key, el ) {
624 var is_selected = '';
625 if ( _.isObject(current_val.selected_variants) && inObject(el, current_val.selected_variants) ) {
626 is_selected = ' selected="selected"';
627 } else if ( _.isString(current_val.selected_variants) && el === current_val.selected_variants ) {
628 is_selected = ' selected="selected"';
629 }
630
631 // initialize
632 var variant_option_value = el,
633 variant_option_display = el;
634
635 // If we are dealing with a object variant then it means things get tricky (probably it's our fault but bear with us)
636 // This probably comes from our Fonto plugin - a font with individually named variants - hence each has its own font-family
637 if ( _.isObject(el) ) {
638 //put the entire object in the variation value - we will need it when outputting the custom CSS
639 variant_option_value = encodeURIComponent(JSON.stringify(el));
640 variant_option_display = '';
641
642 //if we have weight and style then "compose" them into something standard
643 if ( !_.isUndefined(el['font-weight']) ) {
644 variant_option_display += el['font-weight'];
645 }
646
647 if ( _.isString(el['font-style']) && $.inArray(el['font-style'].toLowerCase(), ["normal", "regular"]) < 0 ) { //this comparison means it hasn't been found
648 variant_option_display += el['font-style'];
649 }
650 }
651
652 variants_options += '<option value="' + variant_option_value + '"' + is_selected + '>' + variant_option_display + '</option>';
653 count_weights++;
654 });
655 }
656
657 if ( !_.isUndefined($font_weight) ) {
658 $font_weight.html(variants_options);
659 // if there is no weight or just 1 we hide the weight select ... cuz is useless
660 if ( $(font_select).data('load_all_weights') === true || count_weights <= 1 ) {
661 $font_weight.parent().css('display', 'none');
662 } else {
663 $font_weight.parent().css('display', 'inline-block');
664 }
665 }
666 } else if ( !_.isUndefined($font_weight) ) {
667 $font_weight.parent().css('display', 'none');
668 }
669
670 // make the subsets selector
671 if ( !_.isUndefined(subsets) && !_.isNull(subsets) && !_.isEmpty(subsets) ) {
672
673 value_to_add['subsets'] = subsets;
674 // when a font is selected force the first subset to load
675 value_to_add['selected_subsets'] = {0: subsets[0]};
676 var subsets_options = '',
677 count_subsets = 0;
678 $.each(subsets, function ( key, el ) {
679 var is_selected = '';
680 if ( _.isObject(current_val.selected_subsets) && inObject(el, current_val.selected_subsets) ) {
681 is_selected = ' selected="selected"';
682 }
683
684 subsets_options += '<option value="' + el + '"' + is_selected + '>' + el + '</option>';
685 count_subsets++;
686 });
687
688 if ( !_.isUndefined($font_subsets) ) {
689 $font_subsets.html(subsets_options);
690
691 // if there is no subset or just 1 we hide the subsets select ... cuz is useless
692 if ( count_subsets <= 1 ) {
693 $font_subsets.parent().css('display', 'none');
694 } else {
695 $font_subsets.parent().css('display', 'inline-block');
696 }
697 }
698 } else if ( !_.isUndefined($font_subsets) ) {
699 $font_subsets.parent().css('display', 'none');
700 }
701
702 $input.val(encodeURIComponent(JSON.stringify(value_to_add)));
703 }
704 };
705
706 /**
707 * Function to check if a value exists in an object
708 * @param value
709 * @param obj
710 * @returns {boolean}
711 */
712 var inObject = function ( value, obj ) {
713 for ( var k in obj ) {
714 if ( !obj.hasOwnProperty(k) ) continue;
715 if ( _.isEqual(obj[k], value) ) {
716 return true;
717 }
718 }
719 return false;
720 };
721
722 var maybeJsonParse = function ( value ) {
723 var parsed;
724
725 //try and parse it, with decodeURIComponent
726 try {
727 parsed = JSON.parse(decodeURIComponent(value));
728 } catch ( e ) {
729
730 // in case of an error, treat is as a string
731 parsed = value;
732 }
733
734 return parsed;
735 };
736
737 var customifyBackgroundJsControl = (function () {
738 "use strict";
739
740 var api = wp.customize;
741
742 function init() {
743 // Remove the image button
744 $('.customize-control-custom_background .remove-image, .customize-control-custom_background .remove-file').unbind('click').on('click', function ( e ) {
745 removeImage($(this).parents('.customize-control-custom_background:first'));
746 preview($(this));
747 return false;
748 });
749
750 // Upload media button
751 $('.customize-control-custom_background .background_upload_button').unbind().on('click', function ( event ) {
752 addImage(event, $(this).parents('.customize-control-custom_background:first'));
753 });
754
755 $('.customify_background_select').on('change', function () {
756 preview($(this));
757 });
758 }
759
760 // Add a file via the wp.media function
761 function addImage( event, selector ) {
762
763 event.preventDefault();
764
765 var frame;
766 var jQueryel = jQuery(this);
767
768 // If the media frame already exists, reopen it.
769 if ( frame ) {
770 frame.open();
771 return;
772 }
773
774 // Create the media frame.
775 frame = wp.media({
776 multiple: false,
777 library: {
778 //type: 'image' //Only allow images
779 },
780 // Set the title of the modal.
781 title: jQueryel.data('choose'),
782
783 // Customize the submit button.
784 button: {
785 // Set the text of the button.
786 text: jQueryel.data('update')
787 // Tell the button not to close the modal, since we're
788 // going to refresh the page when the image is selected.
789 }
790 });
791
792 // When an image is selected, run a callback.
793 frame.on('select', function () {
794 // Grab the selected attachment.
795 var attachment = frame.state().get('selection').first();
796 frame.close();
797
798 if ( attachment.attributes.type !== "image" ) {
799 return;
800 }
801
802 selector.find('.upload').attr('value', attachment.attributes.url);
803 selector.find('.upload-id').attr('value', attachment.attributes.id);
804 selector.find('.upload-height').attr('value', attachment.attributes.height);
805 selector.find('.upload-width').attr('value', attachment.attributes.width);
806
807 var thumbSrc = attachment.attributes.url;
808 if ( !_.isUndefined(attachment.attributes.sizes) && !_.isUndefined(attachment.attributes.sizes.thumbnail) ) {
809 thumbSrc = attachment.attributes.sizes.thumbnail.url;
810 } else if ( !_.isUndefined(attachment.attributes.sizes) ) {
811 var height = attachment.attributes.height;
812 for ( var key in attachment.attributes.sizes ) {
813 var object = attachment.attributes.sizes[key];
814 if ( object.height < height ) {
815 height = object.height;
816 thumbSrc = object.url;
817 }
818 }
819 } else {
820 thumbSrc = attachment.attributes.icon;
821 }
822
823 selector.find('.customify_background_input.background-image').val(attachment.attributes.url);
824
825 if ( !selector.find('.upload').hasClass('noPreview') ) {
826 selector.find('.preview_screenshot').empty().hide().append('<img class="preview_image" src="' + thumbSrc + '">').slideDown('fast');
827 }
828 //selector.find('.media_upload_button').unbind();
829 selector.find('.remove-image').removeClass('hide');//show "Remove" button
830 selector.find('.customify_background_select').removeClass('hide');//show "Remove" button
831
832 preview(selector);
833 });
834
835 // Finally, open the modal.
836 frame.open();
837 }
838
839 // Update the background preview
840 function preview( selector ) {
841
842 var $parent = selector.parents('.customize-control-custom_background:first');
843
844 if ( selector.hasClass('customize-control-custom_background') ) {
845 $parent = selector;
846 }
847
848 if ( $parent.length > 0 ) {
849 $parent = $($parent[0]);
850 } else {
851 return;
852 }
853
854 var image_holder = $parent.find('.background-preview');
855
856 if ( !image_holder ) { // No preview present
857 return;
858 }
859
860 var the_id = $parent.find('.button.background_upload_button').data('setting_id'),
861 this_setting = api.instance(the_id);
862
863 var background_data = {};
864
865 $parent.find('.customify_background_select, .customify_background_input').each(function () {
866 var data = $(this).serializeArray();
867
868 data = data[0];
869 if ( data && data.name.indexOf('[background-') != -1 ) {
870
871 background_data[$(this).data('select_name')] = data.value;
872
873 //default_default[data.name] = data.value;
874 //if (data.name == "background-image") {
875 // css += data.name + ':url("' + data.value + '");';
876 //} else {
877 // css += data.name + ':' + data.value + ';';
878 //}
879 }
880 });
881
882 api.instance(the_id).set(background_data);
883 //// Notify the customizer api about this change
884 api.trigger('change');
885 api.previewer.refresh();
886
887 //image_holder.attr('style', css).fadeIn();
888 }
889
890 // Update the background preview
891 function removeImage( parent ) {
892 var selector = parent.find('.upload_button_div');
893 // This shouldn't have been run...
894 if ( !selector.find('.remove-image').addClass('hide') ) {
895 return;
896 }
897
898 selector.find('.remove-image').addClass('hide');//hide "Remove" button
899 parent.find('.customify_background_select').addClass('hide');
900
901 selector.find('.upload').val('');
902 selector.find('.upload-id').val('');
903 selector.find('.upload-height').val('');
904 selector.find('.upload-width').val('');
905 parent.find('.customify_background_input.background-image').val('');
906
907 var customizer_id = selector.find('.background_upload_button').data('setting_id'),
908 this_setting = api.control(customizer_id + '_control'),
909 current_vals = this_setting.setting(),
910 screenshot = parent.find('.preview_screenshot'),
911 to_array = $.map(current_vals, function ( value, index ) {
912 return [value];
913 });
914
915 // Hide the screenshot
916 screenshot.slideUp();
917 selector.find('.remove-file').unbind();
918 to_array['background-image'] = '';
919 this_setting.setting(to_array);
920 }
921
922 return {
923 init: init
924 }
925 })(jQuery);
926
927 var getUrlVars = function ( name ) {
928 var vars = [], hash;
929 var hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&');
930 for ( var i = 0; i < hashes.length; i++ ) {
931 hash = hashes[i].split('=');
932
933 vars.push(hash[0]);
934 vars[hash[0]] = hash[1];
935 }
936
937 if ( !_.isUndefined(vars[name]) ) {
938 return vars[name];
939 }
940 return false;
941 };
942
943 var isJsonString = function ( str ) {
944 try {
945 JSON.parse(str);
946 } catch ( e ) {
947 return false;
948 }
949 return true;
950 };
951 });
952
953
954 var customifyFontSelect = (function () {
955 var wpapi = null,
956 fontSelector = '.customify_font_family',
957 selectPlacehoder = "Select a font family",
958 weightPlaceholder = "Select a font weight",
959 subsetPlaceholder = "Select a font subset";
960
961 function init( wpapi ) {
962
963 this.wpapi = wpapi;
964
965 setTimeout(function () {
966 $(fontSelector).select2({
967 placeholder: selectPlacehoder
968 }).on('change', function ( e ) {
969 var new_option = $(e.target).find('option:selected'),
970 wraper = $(e.target).closest('.font-options__wrapper'),
971 type = $(new_option).data('type');
972
973 update_weight_field(new_option, wraper);
974 update_subset_field(new_option, wraper);
975
976 // serialize stuff and refresh
977 update_font_value(wraper);
978
979 // find weight and subset select
980 // var api = wp.customize;
981 // api.previewer.refresh();
982 });
983 }, 333);
984
985 $('.customify_font_weight').each(function ( i, el ) {
986
987 var select2_args = {
988 debug: false
989 };
990
991 // all this fuss is for the case when the font doesn't come with variants from PHP, lile a theme_font
992 if ( this.options.length === 0 ) {
993 var wraper = $(el).closest('.font-options__wrapper'),
994 font = wraper.find('.customify_font_family'),
995 option = font[0].options[font[0].selectedIndex],
996 variants = maybeJsonParse( $(option).data('variants') ),
997 data = [],
998 selecter_variants = $(el).data('default') || null;
999
1000 if ( typeof variants === "undefined" ) {
1001 $(this).hide();
1002 return;
1003 }
1004
1005 $.each( variants, function ( index, weight ) {
1006 var this_value = {
1007 id: weight,
1008 text: weight
1009 };
1010 if ( selecter_variants !== null && weight == selecter_variants ) {
1011 this_value.selected = true;
1012 }
1013
1014 data.push(this_value);
1015 } );
1016
1017 if ( data !== [] ) {
1018 select2_args.data = data;
1019 }
1020 }
1021
1022 $(this).select2( select2_args )
1023 .on('change', function ( e ) {
1024 var wraper = $(e.target).closest('.font-options__wrapper');
1025 var current_value = update_font_value(wraper);
1026 // temporary just set the new value and refresh the previewr
1027 // we may update this with a live version sometime
1028 var value_holder = wraper.children('.customify_font_values');
1029 var setting_id = $(value_holder).data('customize-setting-link');
1030 var setting = wpapi(setting_id);
1031 setting.set(encodeValues(current_value));
1032 });
1033 });
1034
1035 $('.customify_font_subsets')
1036 .select2({
1037 placeholder: "Extra Subsets"
1038 })
1039 .on('change', function ( e ) {
1040 var wraper = $(e.target).closest('.font-options__wrapper');
1041 var current_value = update_font_value(wraper);
1042 // temporary just set the new value and refresh the previewr
1043 // we may update this with a live version sometime
1044 var value_holder = wraper.children('.customify_font_values');
1045 var setting_id = $(value_holder).data('customize-setting-link');
1046 var setting = wpapi(setting_id);
1047 setting.set(encodeValues(current_value));
1048 });
1049
1050 var rangers = $(fontSelector).parents('.font-options__wrapper').find('input[type=range]');
1051 var selects = $(fontSelector).parents('.font-options__wrapper').find('select');
1052
1053 if ( selects.length > 0 ) {
1054 selects.on('change', function ( e ) {
1055 var wraper = $(e.target).closest('.font-options__wrapper');
1056 var current_value = update_font_value(wraper);
1057 // temporary just set the new value and refresh the previewr
1058 // we may update this with a live version sometime
1059 var value_holder = wraper.children('.customify_font_values');
1060 var setting_id = $(value_holder).data('customize-setting-link');
1061 var setting = wpapi(setting_id);
1062 setting.set(encodeValues(current_value));
1063 });
1064 }
1065
1066 if ( rangers.length > 0 ) {
1067 rangers.on('mousemove', function ( e ) {
1068 var wraper = $(e.target).closest('.font-options__wrapper');
1069 var current_value = update_font_value(wraper);
1070 // temporary just set the new value and refresh the previewr
1071 // we may update this with a live version sometime
1072 var value_holder = wraper.children('.customify_font_values');
1073 var setting_id = $(value_holder).data('customize-setting-link');
1074 var setting = wpapi(setting_id);
1075 setting.set(encodeValues(current_value));
1076 // setting.trigger('change');
1077 wpapi.previewer.send( 'font-changed' );
1078 });
1079 }
1080 }
1081
1082 /**
1083 * This function updates the data in font weight selector from the givin <option> element
1084 *
1085 * @param new_option
1086 * @param wraper
1087 */
1088 function update_weight_field( option, wraper ) {
1089 var variants = $(option).data('variants'),
1090 font_weights = wraper.find('.customify_font_weight'),
1091 new_variants = [],
1092 type = $(option).data('type'),
1093 id = wraper.find('.customify_font_values').data('customizeSettingLink');
1094
1095 variants = maybeJsonParse(variants);
1096
1097 if ( customify_settings.settings[id].load_all_weights || typeof variants === "undefined" || Object.keys(variants).length < 2 ) {
1098 font_weights.parent().hide();
1099 } else {
1100 font_weights.parent().show();
1101 }
1102
1103 var selected = 1;
1104
1105 // we need to turn the data array into a specific form like [{id:"id", text:"Text"}]
1106 $.each(variants, function ( i, j ) {
1107 new_variants[i] = {
1108 'id': j,
1109 'text': j
1110 };
1111
1112 if ( selected === 3 ) {
1113 new_variants[i].selected = true;
1114 }
1115 selected++;
1116 });
1117
1118 // we need to clear the old values
1119 $(font_weights).select2().empty();
1120 $(font_weights).select2({
1121 data: new_variants
1122 }).on('change', function ( e ) {
1123 var select_element = e.target;
1124 var wraper = $(select_element).closest('.font-options__wrapper');
1125 update_font_value(wraper);
1126 });
1127 }
1128
1129 /**
1130 * This function updates the data in font subset selector from the givin <option> element
1131 * @param new_option
1132 * @param wraper
1133 */
1134 function update_subset_field( option, wraper ) {
1135 var subsets = $(option).data('subsets'),
1136 font_subsets = wraper.find('.customify_font_subsets'),
1137 new_subsets = [],
1138 type = $(option).data('type');
1139
1140 if ( type !== 'google' ) {
1141 font_subsets.parent().hide();
1142 return;
1143 }
1144
1145 subsets = maybeJsonParse(subsets);
1146
1147 if ( Object.keys(subsets).length < 2 ) {
1148 font_subsets.parent().hide();
1149 } else {
1150 font_subsets.parent().show();
1151 }
1152
1153 // we need to turn the data array into a specific form like [{id:"id", text:"Text"}]
1154 $.each(subsets, function ( i, j ) {
1155 new_subsets[i] = {
1156 'id': j,
1157 'text': j
1158 }
1159 });
1160
1161 // we need to clear the old values
1162 $(font_subsets).select2().empty();
1163 $(font_subsets).select2({
1164 data: new_subsets
1165 }).on('change', function ( e ) {
1166 var select_element = e.target;
1167 var wraper = $(select_element).closest('.font-options__wrapper');
1168 update_font_value(wraper);
1169 });
1170 }
1171
1172 /**
1173 * This function is a custom value serializer for our entire font field
1174 * It collects values and saves them (encoded) into the `.customify_font_values` input's value
1175 */
1176 function update_font_value( wraper ) {
1177 var element = $(wraper).find('.font-options__wrapper'),
1178 options_list = $(wraper).find('.font-options__options-list'),
1179 inputs = options_list.find('select, input'),
1180 value_holder = wraper.children('.customify_font_values'),
1181 new_vals = {};
1182
1183 inputs.each(function ( key, el ) {
1184 var field = $(el).data('field'),
1185 value = $(el).val();
1186
1187 if ( field === 'font_family' ) {
1188 // the font family also holds the type
1189 var selected_opt = $(el.options[el.selectedIndex]),
1190 type = selected_opt.data('type'),
1191 subsets = selected_opt.data('subsets'),
1192 variants = selected_opt.data('variants');
1193
1194 if ( typeof type !== "undefined") {
1195 new_vals['type'] = type;
1196 if ( type === 'theme_font' ) {
1197 new_vals['src'] = selected_opt.data('src');
1198 }
1199 }
1200
1201 if ( typeof variants !== "undefined") {
1202 new_vals['variants'] = maybeJsonParse(variants);
1203 }
1204
1205 if ( typeof subsets !== "subsets") {
1206 new_vals['subsets'] = maybeJsonParse(subsets);
1207 }
1208 }
1209
1210
1211 if ( typeof field !== "undefined" && typeof value !== "undefined" && value !== "" ) {
1212 new_vals[field] = value;
1213 }
1214 });
1215
1216 value_holder.val(encodeValues(new_vals));
1217
1218 return new_vals;
1219 }
1220
1221 var maybeJsonParse = function ( value ) {
1222 var parsed;
1223
1224 //try and parse it, with decodeURIComponent
1225 try {
1226 parsed = JSON.parse(decodeURIComponent(value));
1227 } catch ( e ) {
1228
1229 // in case of an error, treat is as a string
1230 parsed = value;
1231 }
1232
1233 return parsed;
1234 };
1235
1236 function encodeValues( obj ) {
1237 return encodeURIComponent(JSON.stringify(obj));
1238 }
1239
1240 return {
1241 init: init,
1242 update_font_value: update_font_value
1243 };
1244 })();
1245
1246
1247 var Queue = function () {
1248 var lastPromise = null;
1249 var queueDeferred = null;
1250 var methodDeferred = null;
1251
1252 this.add_steps = function ( key, steps, args ) {
1253 var self = this;
1254 this.methodDeferred = $.Deferred();
1255 this.queueDeferred = this.setup();
1256
1257 $.each(steps, function ( i, step ) {
1258 self.queue(key, step);
1259 });
1260 };
1261
1262 this.process_remote_step = function ( key, data, step ) {
1263 var self = this;
1264
1265 if ( _.isUndefined(data) || _.isNull(data) ) {
1266 return false;
1267 }
1268
1269 var new_step = step;
1270 $.each(data, function ( i, k ) {
1271 debugger;
1272 // prepare data for new requests
1273 new_step.recall_data = k.data;
1274 new_step.recall_type = k.type;
1275 new_step.type = 'recall';
1276
1277 self.queue(key, new_step, k.id);
1278 });
1279 };
1280
1281 this.log_action = function ( action, key, msg ) {
1282 if ( action === 'start' ) {
1283 $('.wpGrade-import-results').show();
1284 $('.wpGrade-import-results').append('<span class="import_step_note imports_step_' + key + '" ><span class="step_info" data-balloon="Working on it" data-balloon-pos="up"></span>Importing ' + key + '</span>');
1285 } else if ( action === 'end' ) {
1286 var $notice = $('.imports_step_' + key + ' .step_info');
1287
1288 if ( $notice.length > 0 || msg !== "undefined" ) {
1289 $notice.attr('data-balloon', msg);
1290 $notice.addClass('success');
1291 } else {
1292 $notice.attr('data-balloon', 'Done');
1293 $notice.addClass('failed');
1294 }
1295 }
1296 };
1297
1298 this.queue = function ( key, data, step_key ) {
1299 var self = this;
1300 if ( !_.isUndefined(step_key) ) {
1301 this.log_action('start', step_key);
1302 }
1303
1304 // execute next queue method
1305 this.queueDeferred.done(this.request(key, data, step_key));
1306 lastPromise = self.methodDeferred.promise();
1307 };
1308
1309 this.request = function ( key, step, step_key ) {
1310 var self = this;
1311 // call actual method and wrap output in deferred
1312 //setTimeout( function() {
1313 var data_args = {
1314 action: 'customify_import_step',
1315 step_id: step.id,
1316 step_type: step.type,
1317 option_key: key
1318 };
1319
1320 if ( !_.isUndefined(step.recall_data) ) {
1321 data_args.recall_data = step.recall_data;
1322 }
1323
1324 if ( !_.isUndefined(step.recall_type) ) {
1325 data_args.recall_type = step.recall_type;
1326 }
1327
1328 $.ajax({
1329 url: customify_settings.import_rest_url + 'customify/1.0/import',
1330 method: 'POST',
1331 beforeSend: function ( xhr ) {
1332 xhr.setRequestHeader('X-WP-Nonce', WP_API_Settings.nonce);
1333 },
1334 dataType: 'json',
1335 contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
1336 data: data_args
1337 }).done(function ( response ) {
1338 if ( !_.isUndefined(response.success) && response.success ) {
1339 var results = response.data;
1340 if ( step.type === 'remote' ) {
1341 self.process_remote_step(key, results, step);
1342 }
1343 }
1344
1345 if ( !_.isUndefined(step_key) && !_.isUndefined(response.message) ) {
1346 self.log_action('end', step_key, response.message);
1347 }
1348 });
1349
1350 self.methodDeferred.resolve();
1351 //}, 3450 );
1352 };
1353
1354 this.setup = function () {
1355 var self = this;
1356
1357 self.queueDeferred = $.Deferred();
1358
1359 // when the previous method returns, resolve this one
1360 $.when(lastPromise).always(function () {
1361 self.queueDeferred.resolve();
1362 });
1363
1364 return self.queueDeferred.promise();
1365 }
1366 };
1367
1368 })(jQuery, window);
1369