PluginProbe
Customify / 2.3.3
Customify v2.3.3
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 2.3.3, at js/customizer.js

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