| 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 |
const id = $(this).attr('id'), |
| 19 |
css_editor = ace.edit(id) |
| 20 |
|
| 21 |
const 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 |
const 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 |
const setting_id = key.replace('_control', '') |
| 90 |
const 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 |
const container = $(this).parents('.control-panel'), |
| 103 |
id = container.attr('id') |
| 104 |
|
| 105 |
if (typeof id !== 'undefined') { |
| 106 |
const 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 |
const 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 |
const controls = this.controls() |
| 127 |
|
| 128 |
if (controls.length > 0) { |
| 129 |
$.each(controls, function (key, ctrl) { |
| 130 |
const 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 |
const 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 |
const 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 |
const section_id = $(this).data('section'), |
| 165 |
section = api.section(section_id), |
| 166 |
controls = section.controls() |
| 167 |
|
| 168 |
const 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 |
const 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 |
const 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 |
const $input = $(this).parents('.options').siblings('.customify_typography').children('.customify_typography_values'); |
| 196 |
let 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 |
const $input = $(this).parents('.options').siblings('.customify_typography').children('.customify_typography_values'); |
| 211 |
let 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 |
customifyBackgroundJsControl.init() |
| 245 |
|
| 246 |
// sometimes a php save may be needed |
| 247 |
if (getUrlVars('save_customizer_once')) { |
| 248 |
api.previewer.save() |
| 249 |
} |
| 250 |
|
| 251 |
setTimeout(function () { |
| 252 |
customifyFoldingFields() |
| 253 |
}, 1000); |
| 254 |
|
| 255 |
// Handle the section tabs (ex: Layout | Fonts | Colors) |
| 256 |
( |
| 257 |
function () { |
| 258 |
const $navs = $('.js-section-navigation') |
| 259 |
|
| 260 |
$navs.each(function () { |
| 261 |
const $nav = $(this) |
| 262 |
const $title = $nav.parents('.accordion-section-content').find('.customize-section-title') |
| 263 |
|
| 264 |
$nav.closest('.customize-control').addClass('screen-reader-text') |
| 265 |
$title.append($nav).parent().addClass('has-nav') |
| 266 |
}) |
| 267 |
|
| 268 |
$('.js-section-navigation a').on('click', function (e) { |
| 269 |
e.preventDefault() |
| 270 |
|
| 271 |
const $sidebar = $(this).parents('.customize-pane-child'), |
| 272 |
$parent = $(this).parents('.accordion-section-content'), |
| 273 |
href = $.attr(this, 'href') |
| 274 |
|
| 275 |
if (href != '#') { |
| 276 |
$sidebar.animate({ |
| 277 |
scrollTop: $($.attr(this, 'href')).position().top - $parent.find('.customize-section-title').outerHeight() |
| 278 |
}, 500) |
| 279 |
} |
| 280 |
}) |
| 281 |
} |
| 282 |
)(); |
| 283 |
|
| 284 |
( |
| 285 |
function () { |
| 286 |
// Close a font field when clicking on another field |
| 287 |
$('.customify_font_tooltip').on('click', function () { |
| 288 |
if ($(this).prop('checked') === true) { |
| 289 |
$('.customify_font_tooltip').prop('checked', false) |
| 290 |
$(this).prop('checked', true) |
| 291 |
} |
| 292 |
}) |
| 293 |
} |
| 294 |
)() |
| 295 |
|
| 296 |
// Bind any connected fields, except those in the Style Manager. |
| 297 |
// Those are handled by the appropriate Style Manager component (Color Palettes, Font Palettes, etc ). |
| 298 |
bindConnectedFields() |
| 299 |
|
| 300 |
}) |
| 301 |
|
| 302 |
const getConnectedFieldsCallback = function (parent_setting_data, parent_setting_id) { |
| 303 |
return function (new_value, old_value) { |
| 304 |
_.each(parent_setting_data.connected_fields, function (connected_field_data) { |
| 305 |
if (_.isUndefined(connected_field_data) || _.isUndefined(connected_field_data.setting_id) || !_.isString(connected_field_data.setting_id)) { |
| 306 |
return |
| 307 |
} |
| 308 |
const setting = wp.customize(connected_field_data.setting_id) |
| 309 |
if (_.isUndefined(setting)) { |
| 310 |
return |
| 311 |
} |
| 312 |
setting.set(new_value) |
| 313 |
}) |
| 314 |
} |
| 315 |
} |
| 316 |
|
| 317 |
const bindConnectedFields = function () { |
| 318 |
_.each(wp.customize.settings.settings, function (parent_setting_data, parent_setting_id) { |
| 319 |
// We don't want to handle the binding of the Style Manager settings |
| 320 |
if (typeof ColorPalettes !== 'undefined' |
| 321 |
&& typeof ColorPalettes.masterSettingIds !== 'undefined' |
| 322 |
&& _.contains(ColorPalettes.masterSettingIds, parent_setting_id)) { |
| 323 |
return |
| 324 |
} |
| 325 |
if (typeof FontPalettes !== 'undefined' |
| 326 |
&& typeof FontPalettes.masterSettingIds !== 'undefined' |
| 327 |
&& _.contains(FontPalettes.masterSettingIds, parent_setting_id)) { |
| 328 |
return |
| 329 |
} |
| 330 |
|
| 331 |
let parent_setting = wp.customize(parent_setting_id) |
| 332 |
if (typeof parent_setting_data.connected_fields !== 'undefined') { |
| 333 |
connectedFieldsCallbacks[parent_setting_id] = getConnectedFieldsCallback(parent_setting_data, parent_setting_id) |
| 334 |
parent_setting.bind(connectedFieldsCallbacks[parent_setting_id]) |
| 335 |
} |
| 336 |
}) |
| 337 |
} |
| 338 |
|
| 339 |
const unbindConnectedFields = function () { |
| 340 |
_.each(wp.customize.settings.settings, function (parent_setting_data, parent_setting_id) { |
| 341 |
// We don't want to handle the binding of the Style Manager settings |
| 342 |
if (typeof ColorPalettes !== 'undefined' |
| 343 |
&& typeof ColorPalettes.masterSettingIds !== 'undefined' |
| 344 |
&& _.contains(ColorPalettes.masterSettingIds, parent_setting_id)) { |
| 345 |
return |
| 346 |
} |
| 347 |
if (typeof FontPalettes !== 'undefined' |
| 348 |
&& typeof FontPalettes.masterSettingIds !== 'undefined' |
| 349 |
&& _.contains(FontPalettes.masterSettingIds, parent_setting_id)) { |
| 350 |
return |
| 351 |
} |
| 352 |
|
| 353 |
let parent_setting = wp.customize(parent_setting_id) |
| 354 |
if (typeof parent_setting_data.connected_fields !== 'undefined' && typeof connectedFieldsCallbacks[parent_setting_id] !== 'undefined') { |
| 355 |
parent_setting.unbind(connectedFieldsCallbacks[parent_setting_id]) |
| 356 |
} |
| 357 |
delete connectedFieldsCallbacks[parent_setting_id] |
| 358 |
}) |
| 359 |
} |
| 360 |
|
| 361 |
const customifyHandleRangeFields = function (el) { |
| 362 |
|
| 363 |
// For each range input add a number field (for preview mainly - but it can also be used for input) |
| 364 |
$(el).find('input[type="range"]').each(function () { |
| 365 |
if (!$(this).siblings('.range-value').length) { |
| 366 |
const $clone = $(this).clone() |
| 367 |
|
| 368 |
$clone |
| 369 |
.attr('type', 'number') |
| 370 |
.attr('class', 'range-value') |
| 371 |
.removeAttr('data-field') |
| 372 |
|
| 373 |
$(this).after($clone) |
| 374 |
|
| 375 |
// Update the range field when changing the number |
| 376 |
$($clone).on('change', function () { |
| 377 |
$(this).siblings('input[type="range"]').val($(this).val()) |
| 378 |
}) |
| 379 |
} |
| 380 |
|
| 381 |
// Update the number field when changing the range |
| 382 |
$(this).on('change', function () { |
| 383 |
$(this).siblings('.range-value').val($(this).val()) |
| 384 |
}) |
| 385 |
}) |
| 386 |
} |
| 387 |
|
| 388 |
/** |
| 389 |
* This function will search for all the interdependend fields and make a bound between them. |
| 390 |
* So whenever a target is changed, it will take actions to the dependent fields. |
| 391 |
* @TODO this is still written in a barbaric way, refactor when needed |
| 392 |
*/ |
| 393 |
const customifyFoldingFields = function () { |
| 394 |
|
| 395 |
if (_.isUndefined(customify_settings) || _.isUndefined(customify_settings.settings)) { |
| 396 |
return // bail |
| 397 |
} |
| 398 |
|
| 399 |
/** |
| 400 |
* Let's iterate through all the customify settings and gather all the fields that have a "show_if" |
| 401 |
* property set. |
| 402 |
* |
| 403 |
* At the end `targets` will hold a list of [ target : [field, field,...], ... ] |
| 404 |
* so when a target is changed we will change all the fields. |
| 405 |
*/ |
| 406 |
var targets = {} |
| 407 |
|
| 408 |
$.fn.reactor.defaults.compliant = function () { |
| 409 |
$(this).slideDown() |
| 410 |
// $(this).animate({opacity: 1}); |
| 411 |
$(this).find(':disabled').attr({disabled: false}) |
| 412 |
} |
| 413 |
|
| 414 |
$.fn.reactor.defaults.uncompliant = function () { |
| 415 |
$(this).slideUp() |
| 416 |
// $(this).animate({opacity: 0.25}); |
| 417 |
$(this).find(':enabled').attr({disabled: true}) |
| 418 |
} |
| 419 |
|
| 420 |
let IS = $.extend({}, $.fn.reactor.helpers) |
| 421 |
|
| 422 |
let bind_folding_events = function (parent_id, field, relation) { |
| 423 |
|
| 424 |
let key = null |
| 425 |
|
| 426 |
if (_.isString(field)) { |
| 427 |
key = field |
| 428 |
} else if (!_.isUndefined(field.id)) { |
| 429 |
key = field.id |
| 430 |
} else if (isString(field[0])) { |
| 431 |
key = field[0] |
| 432 |
} else { |
| 433 |
return // no key, no fun |
| 434 |
} |
| 435 |
|
| 436 |
let value = 1, // by default we use 1 the most used value for checkboxes or inputs |
| 437 |
compare = '==', // ... ye |
| 438 |
action = 'show', |
| 439 |
between = [0, 1] // can only be `show` or `hide` |
| 440 |
|
| 441 |
const target_key = customify_settings.options_name + '[' + key + ']' |
| 442 |
const target_type = customify_settings.settings[target_key].type |
| 443 |
|
| 444 |
// we support the usual syntax like a config array like `array( 'id' => $id, 'value' => $value, 'compare' => $compare )` |
| 445 |
// but we also support a non-associative array like `array( $id, $value, $compare )` |
| 446 |
if (!_.isUndefined(field.value)) { |
| 447 |
value = field.value |
| 448 |
} else if (!_.isUndefined(field[1]) && !_.isString(field[1])) { |
| 449 |
value = field[1] |
| 450 |
} |
| 451 |
|
| 452 |
if (!_.isUndefined(field.compare)) { |
| 453 |
compare = field.compare |
| 454 |
} else if (!_.isUndefined(field[2])) { |
| 455 |
compare = field[2] |
| 456 |
} |
| 457 |
|
| 458 |
if (!_.isUndefined(field.action)) { |
| 459 |
action = field.action |
| 460 |
} else if (!_.isUndefined(field[3])) { |
| 461 |
action = field[3] |
| 462 |
} |
| 463 |
|
| 464 |
// a field can also overwrite the parent relation |
| 465 |
if (!_.isUndefined(field.relation)) { |
| 466 |
action = field.relation |
| 467 |
} else if (!_.isUndefined(field[4])) { |
| 468 |
action = field[4] |
| 469 |
} |
| 470 |
|
| 471 |
if (!_.isUndefined(field.between)) { |
| 472 |
between = field.between |
| 473 |
} |
| 474 |
|
| 475 |
/** |
| 476 |
* Now for each target we have, we will bind a change event to hide or show the dependent fields |
| 477 |
*/ |
| 478 |
const target_selector = '[data-customize-setting-link="' + customify_settings.options_name + '[' + key + ']"]' |
| 479 |
|
| 480 |
switch (target_type) { |
| 481 |
case 'checkbox': |
| 482 |
$(parent_id).reactIf(target_selector, function () { |
| 483 |
return $(this).is(':checked') == value |
| 484 |
}) |
| 485 |
break |
| 486 |
|
| 487 |
case 'radio': |
| 488 |
case 'sm_radio': |
| 489 |
case 'sm_switch': |
| 490 |
case 'radio_image': |
| 491 |
|
| 492 |
// in case of an array of values we use the ( val in array) condition |
| 493 |
if (_.isObject(value)) { |
| 494 |
$(parent_id).reactIf(target_selector, function () { |
| 495 |
return ( |
| 496 |
value.indexOf($(target_selector + ':checked').val()) !== -1 |
| 497 |
) |
| 498 |
}) |
| 499 |
} else { // in any other case we use a simple == comparison |
| 500 |
$(parent_id).reactIf(target_selector, function () { |
| 501 |
return $(target_selector + ':checked').val() == value |
| 502 |
}) |
| 503 |
} |
| 504 |
break |
| 505 |
|
| 506 |
case 'range': |
| 507 |
const x = IS.Between(between[0], between[1]) |
| 508 |
|
| 509 |
$(parent_id).reactIf(target_selector, x) |
| 510 |
break |
| 511 |
|
| 512 |
default: |
| 513 |
// in case of an array of values we use the ( val in array) condition |
| 514 |
if (_.isObject(value)) { |
| 515 |
$(parent_id).reactIf(target_selector, function () { |
| 516 |
return ( |
| 517 |
value.indexOf($(target_selector).val()) !== -1 |
| 518 |
) |
| 519 |
}) |
| 520 |
} else { // in any other case we use a simple == comparison |
| 521 |
$(parent_id).reactIf(target_selector, function () { |
| 522 |
return $(target_selector).val() == value |
| 523 |
}) |
| 524 |
} |
| 525 |
break |
| 526 |
} |
| 527 |
|
| 528 |
$(target_selector).trigger('change') |
| 529 |
$('.reactor').trigger('change.reactor') // triggers all events on load |
| 530 |
} |
| 531 |
|
| 532 |
$.each(customify_settings.settings, function (id, field) { |
| 533 |
/** |
| 534 |
* Here we have the id of the fields. but we know for sure that we just need his parent selector |
| 535 |
* So we just create it |
| 536 |
*/ |
| 537 |
let parent_id = id.replace('[', '-') |
| 538 |
parent_id = parent_id.replace(']', '') |
| 539 |
parent_id = '#customize-control-' + parent_id + '_control' |
| 540 |
|
| 541 |
// get only the fields that have a 'show_if' property |
| 542 |
if (field.hasOwnProperty('show_if')) { |
| 543 |
let relation = 'AND' |
| 544 |
|
| 545 |
if (!_.isUndefined(field.show_if.relation)) { |
| 546 |
relation = field.show_if.relation |
| 547 |
// remove the relation property, we need the config to be array based only |
| 548 |
delete field.show_if.relation |
| 549 |
} |
| 550 |
|
| 551 |
/** |
| 552 |
* The 'show_if' can be a simple array with one target like: [ id, value, comparison, action ] |
| 553 |
* Or it could be an array of multiple targets and we need to process both cases |
| 554 |
*/ |
| 555 |
|
| 556 |
if (!_.isUndefined(field.show_if.id)) { |
| 557 |
bind_folding_events(parent_id, field.show_if, relation) |
| 558 |
} else if (_.isObject(field.show_if)) { |
| 559 |
$.each(field.show_if, function (i, j) { |
| 560 |
bind_folding_events(parent_id, j, relation) |
| 561 |
}) |
| 562 |
} |
| 563 |
} |
| 564 |
}) |
| 565 |
} |
| 566 |
|
| 567 |
const get_typography_font_family = function ($el) { |
| 568 |
|
| 569 |
let font_family_value = $el.val() |
| 570 |
// first time this will not be a json so catch that error |
| 571 |
try { |
| 572 |
font_family_value = JSON.parse(font_family_value) |
| 573 |
} catch (e) { |
| 574 |
return {font_family: font_family_value} |
| 575 |
} |
| 576 |
|
| 577 |
if (!_.isUndefined(font_family_value.font_family)) { |
| 578 |
return font_family_value.font_family |
| 579 |
} |
| 580 |
|
| 581 |
return false |
| 582 |
} |
| 583 |
|
| 584 |
// get each typography field and bind events |
| 585 |
// @todo Are we still using the typography field since we have the font field? |
| 586 |
const prepare_typography_field = function () { |
| 587 |
|
| 588 |
const $typos = $('.customify_typography_font_family') |
| 589 |
|
| 590 |
$typos.each(function () { |
| 591 |
var font_family_select = this, |
| 592 |
$input = $(font_family_select).siblings('.customify_typography_values') |
| 593 |
// on change |
| 594 |
$(font_family_select).on('change', function () { |
| 595 |
update_siblings_selects(font_family_select) |
| 596 |
$input.trigger('change') |
| 597 |
}) |
| 598 |
update_siblings_selects(font_family_select) |
| 599 |
}) |
| 600 |
} |
| 601 |
|
| 602 |
const api_set_setting_value = function (setting_id, value) { |
| 603 |
let setting = api(setting_id), |
| 604 |
field = $('[data-customize-setting-link="' + setting_id + '"]'), |
| 605 |
field_class = $(field).parent().attr('class') |
| 606 |
|
| 607 |
// Legacy field type |
| 608 |
if (!_.isUndefined(field_class) && field_class === 'customify_typography') { |
| 609 |
|
| 610 |
let family_select = field.siblings('select') |
| 611 |
|
| 612 |
if (_.isString(value)) { |
| 613 |
let this_option = family_select.find('option[value="' + value + '"]') |
| 614 |
$(this_option[0]).attr('selected', 'selected') |
| 615 |
update_siblings_selects(family_select) |
| 616 |
} else if (_.isObject(value)) { |
| 617 |
let this_family_option = family_select.find('option[value="' + value['font_family'] + '"]') |
| 618 |
|
| 619 |
$(this_family_option[0]).attr('selected', 'selected') |
| 620 |
|
| 621 |
update_siblings_selects(this_family_option) |
| 622 |
|
| 623 |
setTimeout(function () { |
| 624 |
let weight_select = field.parent().siblings('.options').find('.customify_typography_font_weight'), |
| 625 |
this_weight_option = weight_select.find('option[value="' + value['selected_variants'] + '"]') |
| 626 |
|
| 627 |
$(this_weight_option[0]).attr('selected', 'selected') |
| 628 |
|
| 629 |
update_siblings_selects(this_family_option) |
| 630 |
|
| 631 |
weight_select.trigger('change') |
| 632 |
}, 300) |
| 633 |
} |
| 634 |
|
| 635 |
family_select.trigger('change') |
| 636 |
|
| 637 |
} else if (!_.isUndefined(field_class) && field_class === 'font-options__wrapper') { |
| 638 |
|
| 639 |
// if the value is a simple string it must be the font family |
| 640 |
if (_.isString(value)) { |
| 641 |
let option = field.parent().find('option[value="' + value + '"]') |
| 642 |
|
| 643 |
option.attr('selected', 'selected') |
| 644 |
// option.parents('select').trigger('change'); |
| 645 |
} else if (_.isObject(value)) { |
| 646 |
// Find the options list wrapper |
| 647 |
let optionsList = field.parent().children('.font-options__options-list') |
| 648 |
|
| 649 |
if (optionsList.length) { |
| 650 |
// We will process each font property and update it |
| 651 |
_.each(value, function (val, key) { |
| 652 |
// We need to map the keys to the data attributes we are using - I know :( |
| 653 |
let mappedKey = key |
| 654 |
switch (key) { |
| 655 |
case 'font-family': |
| 656 |
mappedKey = 'font_family' |
| 657 |
break |
| 658 |
case 'font-size': |
| 659 |
mappedKey = 'font_size' |
| 660 |
break |
| 661 |
case 'font-weight': |
| 662 |
mappedKey = 'selected_variants' |
| 663 |
break |
| 664 |
case 'letter-spacing': |
| 665 |
mappedKey = 'letter_spacing' |
| 666 |
break |
| 667 |
case 'text-transform': |
| 668 |
mappedKey = 'text_transform' |
| 669 |
break |
| 670 |
default: |
| 671 |
break |
| 672 |
} |
| 673 |
let subField = optionsList.find('[data-field="' + mappedKey + '"]') |
| 674 |
if (subField.length) { |
| 675 |
subField.val(val) |
| 676 |
subField.trigger('change') |
| 677 |
} |
| 678 |
}) |
| 679 |
} |
| 680 |
} |
| 681 |
|
| 682 |
} else { |
| 683 |
setting.set(value) |
| 684 |
} |
| 685 |
} |
| 686 |
|
| 687 |
const update_siblings_selects = function (font_select) { |
| 688 |
let selected_font = $(font_select).val(), |
| 689 |
$input = $(font_select).siblings('.customify_typography_values'), |
| 690 |
current_val = $input.attr('value') |
| 691 |
|
| 692 |
if (current_val === '[object Object]') { |
| 693 |
current_val = $input.data('default') |
| 694 |
} else if (_.isString(current_val) && !isJsonString(current_val) && current_val.substr(0, 1) == '[') { |
| 695 |
// a rare case when the value isn't a json but is a representative string like [family,weight] |
| 696 |
current_val = current_val.split(',') |
| 697 |
let new_current_value = {} |
| 698 |
if (!_.isUndefined(current_val[0])) { |
| 699 |
new_current_value['font_family'] = current_val[0] |
| 700 |
} |
| 701 |
|
| 702 |
if (!_.isUndefined(current_val[1])) { |
| 703 |
new_current_value['selected_variants'] = current_val[1] |
| 704 |
} |
| 705 |
|
| 706 |
current_val = JSON.stringify(new_current_value) |
| 707 |
} |
| 708 |
|
| 709 |
let $font_weight = $(font_select).parent().siblings('ul.options').find('.customify_typography_font_weight'), |
| 710 |
$font_subsets = $(font_select).parent().siblings('ul.options').find('.customify_typography_font_subsets') |
| 711 |
|
| 712 |
try { |
| 713 |
current_val = JSON.parse(decodeURIComponent(current_val)) |
| 714 |
} catch (e) { |
| 715 |
|
| 716 |
// in case of an error, force the rebuild of the json |
| 717 |
if (_.isUndefined($(font_select).data('bound_once'))) { |
| 718 |
|
| 719 |
$(font_select).data('bound_once', true) |
| 720 |
|
| 721 |
$(font_select).change() |
| 722 |
$font_weight.change() |
| 723 |
$font_subsets.change() |
| 724 |
} |
| 725 |
} |
| 726 |
|
| 727 |
// first try to get the font from sure sources, not from the recommended list. |
| 728 |
let option_data = $(font_select).find(':not(optgroup[label=Recommended]) option[value="' + selected_font + '"]') |
| 729 |
// however, if there isn't an option found, get what you can |
| 730 |
if (option_data.length < 1) { |
| 731 |
option_data = $(font_select).find('option[value="' + selected_font + '"]') |
| 732 |
} |
| 733 |
|
| 734 |
if (option_data.length > 0) { |
| 735 |
|
| 736 |
let font_type = option_data.data('type'), |
| 737 |
value_to_add = {'type': font_type, 'font_family': selected_font}, |
| 738 |
variants = null, |
| 739 |
subsets = null |
| 740 |
|
| 741 |
if (font_type == 'std') { |
| 742 |
variants = { |
| 743 |
0: '100', |
| 744 |
1: '200', |
| 745 |
3: '300', |
| 746 |
4: '400', |
| 747 |
5: '500', |
| 748 |
6: '600', |
| 749 |
7: '700', |
| 750 |
8: '800', |
| 751 |
9: '900' |
| 752 |
} |
| 753 |
if (!_.isUndefined($(option_data[0]).data('variants'))) { |
| 754 |
//maybe the variants are a JSON |
| 755 |
variants = maybeJsonParse($(option_data[0]).data('variants')) |
| 756 |
} |
| 757 |
} else { |
| 758 |
//maybe the variants are a JSON |
| 759 |
variants = maybeJsonParse($(option_data[0]).data('variants')) |
| 760 |
|
| 761 |
//maybe the subsets are a JSON |
| 762 |
subsets = maybeJsonParse($(option_data[0]).data('subsets')) |
| 763 |
} |
| 764 |
|
| 765 |
// make the variants selector |
| 766 |
if (!_.isUndefined(variants) && !_.isNull(variants) && !_.isEmpty(variants)) { |
| 767 |
|
| 768 |
value_to_add['variants'] = variants |
| 769 |
// when a font is selected force the first weight to load |
| 770 |
value_to_add['selected_variants'] = {0: variants[0]} |
| 771 |
|
| 772 |
let variants_options = '', |
| 773 |
count_weights = 0 |
| 774 |
|
| 775 |
if (_.isArray(variants) || _.isObject(variants)) { |
| 776 |
// Take each variant and produce the option markup |
| 777 |
$.each(variants, function (key, el) { |
| 778 |
let is_selected = '' |
| 779 |
if (_.isObject(current_val.selected_variants) && inObject(el, current_val.selected_variants)) { |
| 780 |
is_selected = ' selected="selected"' |
| 781 |
} else if (_.isString(current_val.selected_variants) && el === current_val.selected_variants) { |
| 782 |
is_selected = ' selected="selected"' |
| 783 |
} |
| 784 |
|
| 785 |
// initialize |
| 786 |
let variant_option_value = el, |
| 787 |
variant_option_display = el |
| 788 |
|
| 789 |
// If we are dealing with a object variant then it means things get tricky (probably it's our fault but bear with us) |
| 790 |
// This probably comes from our Fonto plugin - a font with individually named variants - hence each has its own font-family |
| 791 |
if (_.isObject(el)) { |
| 792 |
//put the entire object in the variation value - we will need it when outputting the custom CSS |
| 793 |
variant_option_value = encodeURIComponent(JSON.stringify(el)) |
| 794 |
variant_option_display = '' |
| 795 |
|
| 796 |
//if we have weight and style then "compose" them into something standard |
| 797 |
if (!_.isUndefined(el['font-weight'])) { |
| 798 |
variant_option_display += el['font-weight'] |
| 799 |
} |
| 800 |
|
| 801 |
if (_.isString(el['font-style']) && $.inArray(el['font-style'].toLowerCase(), [ |
| 802 |
'normal', |
| 803 |
'regular' |
| 804 |
]) < 0) { //this comparison means it hasn't been found |
| 805 |
variant_option_display += el['font-style'] |
| 806 |
} |
| 807 |
} |
| 808 |
|
| 809 |
variants_options += '<option value="' + variant_option_value + '"' + is_selected + '>' + variant_option_display + '</option>' |
| 810 |
count_weights++ |
| 811 |
}) |
| 812 |
} |
| 813 |
|
| 814 |
if (!_.isUndefined($font_weight)) { |
| 815 |
$font_weight.html(variants_options) |
| 816 |
// if there is no weight or just 1 we hide the weight select ... cuz is useless |
| 817 |
if ($(font_select).data('load_all_weights') === true || count_weights <= 1) { |
| 818 |
$font_weight.parent().css('display', 'none') |
| 819 |
} else { |
| 820 |
$font_weight.parent().css('display', 'inline-block') |
| 821 |
} |
| 822 |
} |
| 823 |
} else if (!_.isUndefined($font_weight)) { |
| 824 |
$font_weight.parent().css('display', 'none') |
| 825 |
} |
| 826 |
|
| 827 |
// make the subsets selector |
| 828 |
if (!_.isUndefined(subsets) && !_.isNull(subsets) && !_.isEmpty(subsets)) { |
| 829 |
|
| 830 |
value_to_add['subsets'] = subsets |
| 831 |
// when a font is selected force the first subset to load |
| 832 |
value_to_add['selected_subsets'] = {0: subsets[0]} |
| 833 |
let subsets_options = '', |
| 834 |
count_subsets = 0 |
| 835 |
$.each(subsets, function (key, el) { |
| 836 |
let is_selected = '' |
| 837 |
if (_.isObject(current_val.selected_subsets) && inObject(el, current_val.selected_subsets)) { |
| 838 |
is_selected = ' selected="selected"' |
| 839 |
} |
| 840 |
|
| 841 |
subsets_options += '<option value="' + el + '"' + is_selected + '>' + el + '</option>' |
| 842 |
count_subsets++ |
| 843 |
}) |
| 844 |
|
| 845 |
if (!_.isUndefined($font_subsets)) { |
| 846 |
$font_subsets.html(subsets_options) |
| 847 |
|
| 848 |
// if there is no subset or just 1 we hide the subsets select ... cuz is useless |
| 849 |
if (count_subsets <= 1) { |
| 850 |
$font_subsets.parent().css('display', 'none') |
| 851 |
} else { |
| 852 |
$font_subsets.parent().css('display', 'inline-block') |
| 853 |
} |
| 854 |
} |
| 855 |
} else if (!_.isUndefined($font_subsets)) { |
| 856 |
$font_subsets.parent().css('display', 'none') |
| 857 |
} |
| 858 |
|
| 859 |
$input.val(encodeURIComponent(JSON.stringify(value_to_add))) |
| 860 |
} |
| 861 |
} |
| 862 |
|
| 863 |
/** Modules **/ |
| 864 |
|
| 865 |
const customifyBackgroundJsControl = ( |
| 866 |
function () { |
| 867 |
'use strict' |
| 868 |
|
| 869 |
function init () { |
| 870 |
// Remove the image button |
| 871 |
$('.customize-control-custom_background .remove-image, .customize-control-custom_background .remove-file').unbind('click').on('click', function (e) { |
| 872 |
removeImage($(this).parents('.customize-control-custom_background:first')) |
| 873 |
preview($(this)) |
| 874 |
return false |
| 875 |
}) |
| 876 |
|
| 877 |
// Upload media button |
| 878 |
$('.customize-control-custom_background .background_upload_button').unbind().on('click', function (event) { |
| 879 |
addImage(event, $(this).parents('.customize-control-custom_background:first')) |
| 880 |
}) |
| 881 |
|
| 882 |
$('.customify_background_select').on('change', function () { |
| 883 |
preview($(this)) |
| 884 |
}) |
| 885 |
} |
| 886 |
|
| 887 |
// Add a file via the wp.media function |
| 888 |
function addImage (event, selector) { |
| 889 |
|
| 890 |
event.preventDefault() |
| 891 |
|
| 892 |
var frame |
| 893 |
var jQueryel = jQuery(this) |
| 894 |
|
| 895 |
// If the media frame already exists, reopen it. |
| 896 |
if (frame) { |
| 897 |
frame.open() |
| 898 |
return |
| 899 |
} |
| 900 |
|
| 901 |
// Create the media frame. |
| 902 |
frame = wp.media({ |
| 903 |
multiple: false, |
| 904 |
library: { |
| 905 |
//type: 'image' //Only allow images |
| 906 |
}, |
| 907 |
// Set the title of the modal. |
| 908 |
title: jQueryel.data('choose'), |
| 909 |
|
| 910 |
// Customize the submit button. |
| 911 |
button: { |
| 912 |
// Set the text of the button. |
| 913 |
text: jQueryel.data('update') |
| 914 |
// Tell the button not to close the modal, since we're |
| 915 |
// going to refresh the page when the image is selected. |
| 916 |
} |
| 917 |
}) |
| 918 |
|
| 919 |
// When an image is selected, run a callback. |
| 920 |
frame.on('select', function () { |
| 921 |
// Grab the selected attachment. |
| 922 |
const attachment = frame.state().get('selection').first() |
| 923 |
frame.close() |
| 924 |
|
| 925 |
if (attachment.attributes.type !== 'image') { |
| 926 |
return |
| 927 |
} |
| 928 |
|
| 929 |
selector.find('.upload').attr('value', attachment.attributes.url) |
| 930 |
selector.find('.upload-id').attr('value', attachment.attributes.id) |
| 931 |
selector.find('.upload-height').attr('value', attachment.attributes.height) |
| 932 |
selector.find('.upload-width').attr('value', attachment.attributes.width) |
| 933 |
|
| 934 |
let thumbSrc = attachment.attributes.url |
| 935 |
if (!_.isUndefined(attachment.attributes.sizes) && !_.isUndefined(attachment.attributes.sizes.thumbnail)) { |
| 936 |
thumbSrc = attachment.attributes.sizes.thumbnail.url |
| 937 |
} else if (!_.isUndefined(attachment.attributes.sizes)) { |
| 938 |
let height = attachment.attributes.height |
| 939 |
for (let key in attachment.attributes.sizes) { |
| 940 |
const object = attachment.attributes.sizes[key] |
| 941 |
if (object.height < height) { |
| 942 |
height = object.height |
| 943 |
thumbSrc = object.url |
| 944 |
} |
| 945 |
} |
| 946 |
} else { |
| 947 |
thumbSrc = attachment.attributes.icon |
| 948 |
} |
| 949 |
|
| 950 |
selector.find('.customify_background_input.background-image').val(attachment.attributes.url) |
| 951 |
|
| 952 |
if (!selector.find('.upload').hasClass('noPreview')) { |
| 953 |
selector.find('.preview_screenshot').empty().hide().append('<img class="preview_image" src="' + thumbSrc + '">').slideDown('fast') |
| 954 |
} |
| 955 |
//selector.find('.media_upload_button').unbind(); |
| 956 |
selector.find('.remove-image').removeClass('hide')//show "Remove" button |
| 957 |
selector.find('.customify_background_select').removeClass('hide')//show "Remove" button |
| 958 |
|
| 959 |
preview(selector) |
| 960 |
}) |
| 961 |
|
| 962 |
// Finally, open the modal. |
| 963 |
frame.open() |
| 964 |
} |
| 965 |
|
| 966 |
// Update the background preview |
| 967 |
function preview (selector) { |
| 968 |
|
| 969 |
let $parent = selector.parents('.customize-control-custom_background:first') |
| 970 |
|
| 971 |
if (selector.hasClass('customize-control-custom_background')) { |
| 972 |
$parent = selector |
| 973 |
} |
| 974 |
|
| 975 |
if ($parent.length > 0) { |
| 976 |
$parent = $($parent[0]) |
| 977 |
} else { |
| 978 |
return |
| 979 |
} |
| 980 |
|
| 981 |
const image_holder = $parent.find('.background-preview') |
| 982 |
|
| 983 |
if (!image_holder) { // No preview present |
| 984 |
return |
| 985 |
} |
| 986 |
|
| 987 |
const the_id = $parent.find('.button.background_upload_button').data('setting_id'), |
| 988 |
this_setting = api.instance(the_id) |
| 989 |
|
| 990 |
let background_data = {} |
| 991 |
|
| 992 |
$parent.find('.customify_background_select, .customify_background_input').each(function () { |
| 993 |
var data = $(this).serializeArray() |
| 994 |
|
| 995 |
data = data[0] |
| 996 |
if (data && data.name.indexOf('[background-') != -1) { |
| 997 |
|
| 998 |
background_data[$(this).data('select_name')] = data.value |
| 999 |
|
| 1000 |
//default_default[data.name] = data.value; |
| 1001 |
//if (data.name == "background-image") { |
| 1002 |
// css += data.name + ':url("' + data.value + '");'; |
| 1003 |
//} else { |
| 1004 |
// css += data.name + ':' + data.value + ';'; |
| 1005 |
//} |
| 1006 |
} |
| 1007 |
}) |
| 1008 |
|
| 1009 |
api.instance(the_id).set(background_data) |
| 1010 |
//// Notify the customizer api about this change |
| 1011 |
api.trigger('change') |
| 1012 |
api.previewer.refresh() |
| 1013 |
|
| 1014 |
//image_holder.attr('style', css).fadeIn(); |
| 1015 |
} |
| 1016 |
|
| 1017 |
// Update the background preview |
| 1018 |
function removeImage (parent) { |
| 1019 |
const selector = parent.find('.upload_button_div') |
| 1020 |
// This shouldn't have been run... |
| 1021 |
if (!selector.find('.remove-image').addClass('hide')) { |
| 1022 |
return |
| 1023 |
} |
| 1024 |
|
| 1025 |
selector.find('.remove-image').addClass('hide')//hide "Remove" button |
| 1026 |
parent.find('.customify_background_select').addClass('hide') |
| 1027 |
|
| 1028 |
selector.find('.upload').val('') |
| 1029 |
selector.find('.upload-id').val('') |
| 1030 |
selector.find('.upload-height').val('') |
| 1031 |
selector.find('.upload-width').val('') |
| 1032 |
parent.find('.customify_background_input.background-image').val('') |
| 1033 |
|
| 1034 |
let customizer_id = selector.find('.background_upload_button').data('setting_id'), |
| 1035 |
this_setting = api.control(customizer_id + '_control'), |
| 1036 |
current_vals = this_setting.setting(), |
| 1037 |
screenshot = parent.find('.preview_screenshot'), |
| 1038 |
to_array = $.map(current_vals, function (value, index) { |
| 1039 |
return [value] |
| 1040 |
}) |
| 1041 |
|
| 1042 |
// Hide the screenshot |
| 1043 |
screenshot.slideUp() |
| 1044 |
selector.find('.remove-file').unbind() |
| 1045 |
to_array['background-image'] = '' |
| 1046 |
this_setting.setting(to_array) |
| 1047 |
} |
| 1048 |
|
| 1049 |
return { |
| 1050 |
init: init |
| 1051 |
} |
| 1052 |
} |
| 1053 |
)(jQuery) |
| 1054 |
|
| 1055 |
/** HELPERS **/ |
| 1056 |
|
| 1057 |
/** |
| 1058 |
* Function to check if a value exists in an object |
| 1059 |
* @param value |
| 1060 |
* @param obj |
| 1061 |
* @returns {boolean} |
| 1062 |
*/ |
| 1063 |
const inObject = function (value, obj) { |
| 1064 |
for (let k in obj) { |
| 1065 |
if (!obj.hasOwnProperty(k)) { |
| 1066 |
continue |
| 1067 |
} |
| 1068 |
if (_.isEqual(obj[k], value)) { |
| 1069 |
return true |
| 1070 |
} |
| 1071 |
} |
| 1072 |
return false |
| 1073 |
} |
| 1074 |
|
| 1075 |
const maybeJsonParse = function (value) { |
| 1076 |
let parsed |
| 1077 |
|
| 1078 |
//try and parse it, with decodeURIComponent |
| 1079 |
try { |
| 1080 |
parsed = JSON.parse(decodeURIComponent(value)) |
| 1081 |
} catch (e) { |
| 1082 |
|
| 1083 |
// in case of an error, treat is as a string |
| 1084 |
parsed = value |
| 1085 |
} |
| 1086 |
|
| 1087 |
return parsed |
| 1088 |
} |
| 1089 |
|
| 1090 |
const getUrlVars = function (name) { |
| 1091 |
let vars = [], hash |
| 1092 |
const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&') |
| 1093 |
for (let i = 0; i < hashes.length; i++) { |
| 1094 |
hash = hashes[i].split('=') |
| 1095 |
|
| 1096 |
vars.push(hash[0]) |
| 1097 |
vars[hash[0]] = hash[1] |
| 1098 |
} |
| 1099 |
|
| 1100 |
if (!_.isUndefined(vars[name])) { |
| 1101 |
return vars[name] |
| 1102 |
} |
| 1103 |
return false |
| 1104 |
} |
| 1105 |
|
| 1106 |
const isJsonString = function (str) { |
| 1107 |
try { |
| 1108 |
JSON.parse(str) |
| 1109 |
} catch (e) { |
| 1110 |
return false |
| 1111 |
} |
| 1112 |
return true |
| 1113 |
} |
| 1114 |
} |
| 1115 |
)(jQuery, window, wp) |
| 1116 |
|