| 1 |
;(function ($, window, document) { |
| 2 |
|
| 3 |
/* global customify.config */ |
| 4 |
/* global WebFont */ |
| 5 |
|
| 6 |
$(window).on('load', function () { |
| 7 |
// We need to do this on window.load because on document.ready might be too early. |
| 8 |
maybeLoadWebfontloaderScript() |
| 9 |
}) |
| 10 |
|
| 11 |
const maybeLoadWebfontloaderScript = function () { |
| 12 |
if (typeof WebFont === 'undefined') { |
| 13 |
let tk = document.createElement('script') |
| 14 |
tk.src = parent.customify.config.webfontloader_url |
| 15 |
tk.type = 'text/javascript' |
| 16 |
let s = document.getElementsByTagName('script')[0] |
| 17 |
s.parentNode.insertBefore(tk, s) |
| 18 |
} |
| 19 |
} |
| 20 |
|
| 21 |
const fontsCache = [] |
| 22 |
|
| 23 |
// Do everything at document.ready |
| 24 |
$(function () { |
| 25 |
const api = parent.wp.customize |
| 26 |
const customify = parent.customify |
| 27 |
const apiSettings = api.settings.settings |
| 28 |
const regexForMultipleReplace = new RegExp('-', 'g') |
| 29 |
|
| 30 |
$.each(customify.config.settings, function (key, settingConfig) { |
| 31 |
const propertiesPrefix = typeof settingConfig.properties_prefix === 'undefined' ? '' : settingConfig.properties_prefix |
| 32 |
if (settingConfig.type === 'font') { |
| 33 |
api(key, function (setting) { |
| 34 |
setting.bind(function (newValue) { |
| 35 |
if (typeof newValue === 'undefined') { |
| 36 |
return |
| 37 |
} |
| 38 |
|
| 39 |
if (typeof newValue.font_family !== 'undefined') { |
| 40 |
maybeLoadFontFamily(newValue, this.id) |
| 41 |
} |
| 42 |
|
| 43 |
const $styleElement = $('#customify_font_output_for_' + settingConfig.html_safe_option_id) |
| 44 |
if (!$styleElement.length) { |
| 45 |
return |
| 46 |
} |
| 47 |
|
| 48 |
const cssValue = getFontFieldCSSValue(this.id, newValue) |
| 49 |
if (_.isEmpty(cssValue)) { |
| 50 |
// Empty the style element. |
| 51 |
$styleElement.html('') |
| 52 |
return |
| 53 |
} |
| 54 |
|
| 55 |
$styleElement.html(getFontFieldCSSCode(this.id, cssValue, propertiesPrefix, newValue)) |
| 56 |
}) |
| 57 |
}) |
| 58 |
|
| 59 |
} else if (typeof apiSettings !== 'undefined' |
| 60 |
&& typeof apiSettings[key] !== 'undefined' |
| 61 |
&& typeof settingConfig.css !== 'undefined' |
| 62 |
&& typeof settingConfig.live !== 'undefined' |
| 63 |
&& settingConfig.live === true) { |
| 64 |
|
| 65 |
api(key, function (setting) { |
| 66 |
setting.bind(function (newValue) { |
| 67 |
|
| 68 |
$.each(settingConfig.css, function (idx, propertyConfig) { |
| 69 |
// Replace all dashes with underscores thus making the CSS property safe to us in a HTML ID. |
| 70 |
const $styleElement = $('.dynamic_setting_' + settingConfig.html_safe_option_id + '_property_' + propertyConfig.property.replace(regexForMultipleReplace, '_') + '_' + idx) |
| 71 |
if (!$styleElement.length) { |
| 72 |
return |
| 73 |
} |
| 74 |
|
| 75 |
const properties = {} |
| 76 |
if (typeof propertyConfig.property !== 'undefined' && typeof propertyConfig.selector !== 'undefined') { |
| 77 |
properties[propertyConfig.property] = propertyConfig.selector |
| 78 |
} |
| 79 |
if (typeof propertyConfig.callback_filter !== 'undefined') { |
| 80 |
properties['callback'] = propertyConfig.callback_filter |
| 81 |
} |
| 82 |
if (_.isEmpty(properties)) { |
| 83 |
return |
| 84 |
} |
| 85 |
|
| 86 |
const cssUpdateArgs = { |
| 87 |
properties: properties, |
| 88 |
propertyValue: newValue, |
| 89 |
negative_value: propertyConfig.hasOwnProperty('negative_value') ? propertyConfig['negative_value'] : false |
| 90 |
} |
| 91 |
|
| 92 |
if (typeof this.unit !== 'undefined') { |
| 93 |
cssUpdateArgs.unit = this.unit |
| 94 |
} |
| 95 |
|
| 96 |
$styleElement.cssUpdate(cssUpdateArgs) |
| 97 |
}) |
| 98 |
|
| 99 |
}) |
| 100 |
}) |
| 101 |
} else if (typeof settingConfig.live === 'object' && settingConfig.live.length > 0) { |
| 102 |
// If the live parameter is an object it means that this is a list of css classes. |
| 103 |
// These classes should be affected by the change of the text fields. |
| 104 |
const fieldClass = settingConfig.live.join() |
| 105 |
|
| 106 |
// if this field is allowed to modify text then we'll edit this live |
| 107 |
if ($.inArray(settingConfig.type, ['text', 'textarea', 'ace_editor']) > -1) { |
| 108 |
api(key, function (value) { |
| 109 |
value.bind(function (text) { |
| 110 |
let sanitizer = document.createElement('div') |
| 111 |
|
| 112 |
sanitizer.innerHTML = text |
| 113 |
$(fieldClass).html(text) |
| 114 |
}) |
| 115 |
}) |
| 116 |
} |
| 117 |
} |
| 118 |
}) |
| 119 |
|
| 120 |
/** |
| 121 |
* HELPERS |
| 122 |
**/ |
| 123 |
|
| 124 |
// Mirror logic of server-side Customify_Fonts_Global::getCSSValue() |
| 125 |
const getFontFieldCSSValue = function (settingID, value) { |
| 126 |
|
| 127 |
const CSSValue = {} |
| 128 |
|
| 129 |
if (typeof value.font_family !== 'undefined' && !_.includes(['','false',false], value.font_family)) { |
| 130 |
CSSValue['font-family'] = value.font_family |
| 131 |
// "Expand" the font family by appending the fallback stack, if any is available. |
| 132 |
// But only do this, if the value is not already a font stack! |
| 133 |
if (CSSValue['font-family'].indexOf(',') === -1) { |
| 134 |
const fallbackStack = getFontFamilyFallbackStack(CSSValue['font-family']) |
| 135 |
if (fallbackStack.length) { |
| 136 |
CSSValue['font-family'] += ',' + fallbackStack |
| 137 |
} |
| 138 |
} |
| 139 |
|
| 140 |
CSSValue['font-family'] = sanitizeFontFamilyCSSValue(CSSValue['font-family']) |
| 141 |
} |
| 142 |
|
| 143 |
if (typeof value.font_variant !== 'undefined' && !_.includes(['','false',false], value.font_variant)) { |
| 144 |
let variant = value.font_variant |
| 145 |
|
| 146 |
if (_.isString(variant)) { |
| 147 |
// We may have a style in the variant; attempt to split. |
| 148 |
if (variant.indexOf('italic') !== -1) { |
| 149 |
CSSValue['font-style'] = 'italic' |
| 150 |
variant = variant.replace('italic', '') |
| 151 |
} else if (variant.indexOf('oblique') !== -1) { |
| 152 |
CSSValue['font-style'] = 'oblique' |
| 153 |
variant = variant.replace('oblique', '') |
| 154 |
} |
| 155 |
|
| 156 |
// If anything remained, then we have a font weight also. |
| 157 |
if (variant !== '') { |
| 158 |
if (variant === 'regular' || variant === 'normal') { |
| 159 |
variant = '400' |
| 160 |
} |
| 161 |
|
| 162 |
CSSValue['font-weight'] = variant |
| 163 |
} |
| 164 |
} else if (_.isNumeric(variant)) { |
| 165 |
CSSValue['font-weight'] = String(variant); |
| 166 |
} |
| 167 |
} |
| 168 |
|
| 169 |
if (typeof value.font_size !== 'undefined' && !_.includes(['','false',false], value.font_size)) { |
| 170 |
let fontSizeUnit = false |
| 171 |
|
| 172 |
CSSValue['font-size'] = value.font_size |
| 173 |
// If the value already contains a unit (is not numeric), go with that. |
| 174 |
if (isNaN(value.font_size)) { |
| 175 |
// If we have a standardized value field (as array), use that. |
| 176 |
if (typeof value.font_size.value !== 'undefined') { |
| 177 |
CSSValue['font-size'] = value.font_size.value |
| 178 |
if (typeof value.font_size.unit !== 'undefined') { |
| 179 |
fontSizeUnit = value.font_size.unit |
| 180 |
} |
| 181 |
} else { |
| 182 |
fontSizeUnit = getFieldUnit(settingID, 'font-size') |
| 183 |
} |
| 184 |
} else { |
| 185 |
fontSizeUnit = getFieldUnit(settingID, 'font-size') |
| 186 |
} |
| 187 |
|
| 188 |
if (false !== fontSizeUnit) { |
| 189 |
CSSValue['font-size'] += fontSizeUnit |
| 190 |
} |
| 191 |
} |
| 192 |
|
| 193 |
if (typeof value.letter_spacing !== 'undefined' && !_.includes(['','false',false], value.letter_spacing)) { |
| 194 |
let letterSpacingUnit = false |
| 195 |
|
| 196 |
CSSValue['letter-spacing'] = value.letter_spacing |
| 197 |
// If the value already contains a unit (is not numeric), go with that. |
| 198 |
if (isNaN(value.letter_spacing)) { |
| 199 |
// If we have a standardized value field (as array), use that. |
| 200 |
if (typeof value.letter_spacing.value !== 'undefined') { |
| 201 |
CSSValue['letter-spacing'] = value.letter_spacing.value |
| 202 |
if (typeof value.letter_spacing.unit !== 'undefined') { |
| 203 |
letterSpacingUnit = value.letter_spacing.unit |
| 204 |
} |
| 205 |
} else { |
| 206 |
letterSpacingUnit = getFieldUnit(settingID, 'letter-spacing') |
| 207 |
} |
| 208 |
} else { |
| 209 |
letterSpacingUnit = getFieldUnit(settingID, 'letter-spacing') |
| 210 |
} |
| 211 |
|
| 212 |
if (false !== letterSpacingUnit) { |
| 213 |
CSSValue['letter-spacing'] += letterSpacingUnit |
| 214 |
} |
| 215 |
} |
| 216 |
|
| 217 |
if (typeof value.line_height !== 'undefined' && !_.includes(['','false',false], value.line_height)) { |
| 218 |
let lineHeightUnit = false |
| 219 |
|
| 220 |
CSSValue['line-height'] = value.line_height |
| 221 |
// If the value already contains a unit (is not numeric), go with that. |
| 222 |
if (isNaN(value.line_height)) { |
| 223 |
// If we have a standardized value field (as array), use that. |
| 224 |
if (typeof value.line_height.value !== 'undefined') { |
| 225 |
CSSValue['line-height'] = value.line_height.value |
| 226 |
if (typeof value.line_height.unit !== 'undefined') { |
| 227 |
lineHeightUnit = value.line_height.unit |
| 228 |
} |
| 229 |
} else { |
| 230 |
lineHeightUnit = getFieldUnit(settingID, 'line-height') |
| 231 |
} |
| 232 |
} else { |
| 233 |
lineHeightUnit = getFieldUnit(settingID, 'line-height') |
| 234 |
} |
| 235 |
|
| 236 |
if (false !== lineHeightUnit) { |
| 237 |
CSSValue['line-height'] += lineHeightUnit |
| 238 |
} |
| 239 |
} |
| 240 |
|
| 241 |
if (typeof value.text_align !== 'undefined' && !_.includes(['','false',false], value.text_align)) { |
| 242 |
CSSValue['text-align'] = value.text_align |
| 243 |
} |
| 244 |
|
| 245 |
if (typeof value.text_transform !== 'undefined' && !_.includes(['','false',false], value.text_transform)) { |
| 246 |
CSSValue['text-transform'] = value.text_transform |
| 247 |
} |
| 248 |
|
| 249 |
if (typeof value.text_decoration !== 'undefined' && !_.includes(['','false',false], value.text_decoration)) { |
| 250 |
CSSValue['text-decoration'] = value.text_decoration |
| 251 |
} |
| 252 |
|
| 253 |
return CSSValue |
| 254 |
} |
| 255 |
|
| 256 |
// Mirror logic of server-side Customify_Fonts_Global::getFontStyle() |
| 257 |
const getFontFieldCSSCode = function (settingID, cssValue, prefix, value) { |
| 258 |
const fontConfig = customify.config.settings[settingID] |
| 259 |
let output = '' |
| 260 |
|
| 261 |
if (typeof window !== 'undefined' && typeof fontConfig.callback !== 'undefined' && typeof window[fontConfig.callback] === 'function') { |
| 262 |
// The callbacks expect a string selector right now, not a standardized list. |
| 263 |
// @todo Maybe migrate all callbacks to the new standardized data and remove all this. |
| 264 |
const plainSelectors = [] |
| 265 |
_.each(fontConfig.selector, function (details, selector) { |
| 266 |
plainSelectors.push(selector) |
| 267 |
}) |
| 268 |
const adjustedFontConfig = $.extend(true,{},fontConfig) |
| 269 |
adjustedFontConfig.selector = plainSelectors.join(', ') |
| 270 |
|
| 271 |
// Also, "kill" all fields unit since we pass final CSS values. |
| 272 |
// @todo For some reason, the client-side Typeline cbs are not consistent and expect the font-size value with unit. |
| 273 |
_.each(adjustedFontConfig['fields'], function(fieldValue, fieldKey) { |
| 274 |
if (typeof fieldValue.unit !== 'undefined') { |
| 275 |
adjustedFontConfig['fields'][fieldKey]['unit'] = false; |
| 276 |
} |
| 277 |
}) |
| 278 |
|
| 279 |
// Callbacks want the value keys with underscores, not dashes. |
| 280 |
// We will provide them in both versions for a smoother transition. |
| 281 |
_.each(cssValue, function (propertyValue, property) { |
| 282 |
const newKey = property.replace(regexForMultipleReplace, '_') |
| 283 |
cssValue[newKey] = propertyValue |
| 284 |
}) |
| 285 |
|
| 286 |
return window[fontConfig.callback](cssValue, adjustedFontConfig) |
| 287 |
} |
| 288 |
|
| 289 |
if (typeof fontConfig.selector === 'undefined' || _.isEmpty(fontConfig.selector) || _.isEmpty(cssValue)) { |
| 290 |
return output |
| 291 |
} |
| 292 |
|
| 293 |
// The general CSS allowed properties. |
| 294 |
const subFieldsCSSAllowedProperties = extractAllowedCSSPropertiesFromFontFields(fontConfig['fields']) |
| 295 |
|
| 296 |
// The selector is standardized to a list of simple string selectors, or a list of complex selectors with details. |
| 297 |
// In either case, the actual selector is in the key, and the value is an array (possibly empty). |
| 298 |
|
| 299 |
// Since we might have simple CSS selectors and complex ones (with special details), |
| 300 |
// for cleanliness we will group the simple ones under a single CSS rule, |
| 301 |
// and output individual CSS rules for complex ones. |
| 302 |
// Right now, for complex CSS selectors we are only interested in the `properties` sub-entry. |
| 303 |
const simpleCSSSelectors = [] |
| 304 |
const complexCSSSelectors = {} |
| 305 |
|
| 306 |
_.each(fontConfig.selector, function (details, selector) { |
| 307 |
if (_.isEmpty(details.properties)) { |
| 308 |
// This is a simple selector. |
| 309 |
simpleCSSSelectors.push(selector) |
| 310 |
} else { |
| 311 |
complexCSSSelectors[selector] = details |
| 312 |
} |
| 313 |
}) |
| 314 |
|
| 315 |
if (!_.isEmpty(simpleCSSSelectors)) { |
| 316 |
output += '\n' + simpleCSSSelectors.join(', ') + ' {\n' |
| 317 |
output += getFontFieldCSSProperties(cssValue, subFieldsCSSAllowedProperties, prefix) |
| 318 |
output += '}\n' |
| 319 |
} |
| 320 |
|
| 321 |
if (!_.isEmpty(complexCSSSelectors)) { |
| 322 |
_.each(complexCSSSelectors, function (details, selector) { |
| 323 |
output += '\n' + selector + ' {\n' |
| 324 |
output += getFontFieldCSSProperties(cssValue, details.properties, prefix) |
| 325 |
output += '}\n' |
| 326 |
}) |
| 327 |
} |
| 328 |
|
| 329 |
return output |
| 330 |
} |
| 331 |
|
| 332 |
// Mirror logic of server-side Customify_Fonts_Global::getCSSProperties() |
| 333 |
const getFontFieldCSSProperties = function (cssValue, allowedProperties = false, prefix = '') { |
| 334 |
let output = '' |
| 335 |
|
| 336 |
$.each(cssValue, function (property, propertyValue) { |
| 337 |
// We don't want to output empty CSS rules. |
| 338 |
if ('' === propertyValue || false === propertyValue) { |
| 339 |
return |
| 340 |
} |
| 341 |
|
| 342 |
// If the property is not allowed, skip it. |
| 343 |
if (!isCSSPropertyAllowed(property, allowedProperties)) { |
| 344 |
return |
| 345 |
} |
| 346 |
|
| 347 |
output += prefix + property + ': ' + propertyValue + ';\n' |
| 348 |
}) |
| 349 |
|
| 350 |
return output |
| 351 |
} |
| 352 |
|
| 353 |
// Mirror logic of server-side Customify_Fonts_Global::isCSSPropertyAllowed() |
| 354 |
const isCSSPropertyAllowed = function (property, allowedProperties = false) { |
| 355 |
// Empty properties are not allowed. |
| 356 |
if (_.isEmpty(property)) { |
| 357 |
return false |
| 358 |
} |
| 359 |
|
| 360 |
// Everything is allowed if nothing is specified. |
| 361 |
if (_.isEmpty(allowedProperties)) { |
| 362 |
return true |
| 363 |
} |
| 364 |
|
| 365 |
// For arrays |
| 366 |
if (_.includes(allowedProperties, property)) { |
| 367 |
return true |
| 368 |
} |
| 369 |
|
| 370 |
// For objects |
| 371 |
if (_.has(allowedProperties, property) && allowedProperties[property]) { |
| 372 |
return true |
| 373 |
} |
| 374 |
|
| 375 |
return false |
| 376 |
} |
| 377 |
|
| 378 |
const extractAllowedCSSPropertiesFromFontFields = function (subfields) { |
| 379 |
// Nothing is allowed by default. |
| 380 |
const allowedProperties = { |
| 381 |
'font-family': false, |
| 382 |
'font-weight': false, |
| 383 |
'font-style': false, |
| 384 |
'font-size': false, |
| 385 |
'line-height': false, |
| 386 |
'letter-spacing': false, |
| 387 |
'text-align': false, |
| 388 |
'text-transform': false, |
| 389 |
'text-decoration': false, |
| 390 |
} |
| 391 |
|
| 392 |
if (_.isEmpty(subfields)) { |
| 393 |
return allowedProperties |
| 394 |
} |
| 395 |
|
| 396 |
// We will match the subfield keys with the CSS properties, but only those that properties that are allowed. |
| 397 |
// Maybe at some point some more complex matching would be needed here. |
| 398 |
_.each(subfields, function (value, key) { |
| 399 |
if (typeof allowedProperties[key] !== 'undefined') { |
| 400 |
// Convert values to boolean. |
| 401 |
allowedProperties[key] = !!value |
| 402 |
|
| 403 |
// For font-weight we want font-style to go the same way, |
| 404 |
// since these two are generated from the same subfield: font-weight (actually holding the font variant value). |
| 405 |
if ('font-weight' === key) { |
| 406 |
allowedProperties['font-style'] = allowedProperties[key] |
| 407 |
} |
| 408 |
} |
| 409 |
}) |
| 410 |
|
| 411 |
return allowedProperties |
| 412 |
} |
| 413 |
|
| 414 |
// This is a mirror logic of the server-side Customify_Fonts_Global::getSubFieldUnit() |
| 415 |
const getFieldUnit = function (settingID, field) { |
| 416 |
if (typeof customify.config.settings[settingID] === 'undefined' || typeof customify.config.settings[settingID].fields[field] === 'undefined') { |
| 417 |
// These fields don't have an unit, by default. |
| 418 |
if (_.includes(['font-family', 'font-weight', 'font-style', 'line-height', 'text-align', 'text-transform', 'text-decoration'], field)) { |
| 419 |
return false |
| 420 |
} |
| 421 |
|
| 422 |
// The rest of the subfields have pixels as default units. |
| 423 |
return 'px' |
| 424 |
} |
| 425 |
|
| 426 |
if (typeof customify.config.settings[settingID].fields[field].unit !== 'undefined') { |
| 427 |
// Make sure that we convert all falsy unit values to the boolean false. |
| 428 |
return _.includes(['', 'false', false], customify.config.settings[settingID].fields[field].unit) ? false : customify.config.settings[settingID].fields[field].unit |
| 429 |
} |
| 430 |
|
| 431 |
if (typeof customify.config.settings[settingID].fields[field][3] !== 'undefined') { |
| 432 |
// Make sure that we convert all falsy unit values to the boolean false. |
| 433 |
return _.includes(['', 'false', false], customify.config.settings[settingID].fields[field][3]) ? false : customify.config.settings[settingID].fields[field][3] |
| 434 |
} |
| 435 |
|
| 436 |
return 'px' |
| 437 |
} |
| 438 |
|
| 439 |
const maybeLoadFontFamily = function (font, settingID) { |
| 440 |
if (typeof font.font_family === 'undefined') { |
| 441 |
return |
| 442 |
} |
| 443 |
|
| 444 |
const fontConfig = customify.config.settings[settingID] |
| 445 |
|
| 446 |
let family = font.font_family |
| 447 |
// The font family may be a comma separated list like "Roboto, sans" |
| 448 |
const fontType = customify.fontFields.determineFontType(family) |
| 449 |
|
| 450 |
if ('system_font' === fontType) { |
| 451 |
// Nothing to do for standard fonts |
| 452 |
return |
| 453 |
} |
| 454 |
|
| 455 |
const fontDetails = customify.fontFields.getFontDetails(family, fontType) |
| 456 |
|
| 457 |
// Handle theme defined fonts and cloud fonts together since they are very similar. |
| 458 |
if (fontType === 'theme_font' || fontType === 'cloud_font') { |
| 459 |
|
| 460 |
// Bail if we have no src. |
| 461 |
if (typeof fontDetails.src === undefined) { |
| 462 |
return |
| 463 |
} |
| 464 |
|
| 465 |
// Handle the font variants. |
| 466 |
// If there is a selected font variant and we haven't been instructed to load all, load only that, |
| 467 |
// otherwise load all the available variants. |
| 468 |
let variants = |
| 469 |
( |
| 470 |
typeof font.font_variant !== 'undefined' |
| 471 |
&& (typeof fontConfig['fields']['font-weight']['loadAllVariants'] === 'undefined' || !fontConfig['fields']['font-weight']['loadAllVariants']) |
| 472 |
) ? font.font_variant : typeof fontDetails.variants !== 'undefined' ? fontDetails.variants : [] |
| 473 |
|
| 474 |
if (!_.isEmpty(variants)) { |
| 475 |
variants = standardizeToArray(variants) |
| 476 |
|
| 477 |
if (!_.isEmpty(variants)) { |
| 478 |
family = family + ':' + variants.map(function (variant) { |
| 479 |
return customify.fontFields.convertFontVariantToFVD(variant) |
| 480 |
}).join(',') |
| 481 |
} |
| 482 |
} |
| 483 |
|
| 484 |
if (fontsCache.indexOf(family) === -1) { |
| 485 |
WebFont.load({ |
| 486 |
custom: { |
| 487 |
families: [family], |
| 488 |
urls: [fontDetails.src] |
| 489 |
}, |
| 490 |
classes: false, |
| 491 |
events: false, |
| 492 |
}) |
| 493 |
|
| 494 |
// Remember we've loaded this family (with it's variants) so we don't load it again. |
| 495 |
fontsCache.push(family) |
| 496 |
} |
| 497 |
} |
| 498 |
// Handle Google fonts since Web Font Loader has a special module for them. |
| 499 |
else if (fontType === 'google_font') { |
| 500 |
|
| 501 |
// Handle the font variants |
| 502 |
// If there is a selected font variant and we haven't been instructed to load all, load only that, |
| 503 |
// otherwise load all the available variants. |
| 504 |
let variants = |
| 505 |
( |
| 506 |
typeof font.font_variant !== 'undefined' |
| 507 |
&& (typeof fontConfig['fields']['font-weight']['loadAllVariants'] === 'undefined' || !fontConfig['fields']['font-weight']['loadAllVariants']) |
| 508 |
) ? font.font_variant : typeof fontDetails.variants !== 'undefined' ? fontDetails.variants : [] |
| 509 |
|
| 510 |
if (!_.isEmpty(variants)) { |
| 511 |
variants = standardizeToArray(variants) |
| 512 |
|
| 513 |
if (!_.isEmpty(variants)) { |
| 514 |
family = family + ':' + variants.join(',') |
| 515 |
} |
| 516 |
} |
| 517 |
|
| 518 |
if (fontsCache.indexOf(family) === -1) { |
| 519 |
WebFont.load({ |
| 520 |
google: {families: [family]}, |
| 521 |
classes: false, |
| 522 |
events: false, |
| 523 |
}) |
| 524 |
|
| 525 |
// Remember we've loaded this family (with it's variants) so we don't load it again. |
| 526 |
fontsCache.push(family) |
| 527 |
} |
| 528 |
|
| 529 |
} else { |
| 530 |
// Maybe Typekit, Fonts.com or Fontdeck fonts |
| 531 |
} |
| 532 |
} |
| 533 |
|
| 534 |
const standardizeToArray = function (value) { |
| 535 |
if (typeof value === 'string' || typeof value === 'number') { |
| 536 |
value = [value] |
| 537 |
} else if (typeof value === 'object') { |
| 538 |
value = Object.values(value) |
| 539 |
} |
| 540 |
|
| 541 |
return value |
| 542 |
} |
| 543 |
|
| 544 |
// This is a mirror logic of the server-side Customify_Fonts_Global::getFontFamilyFallbackStack() |
| 545 |
const getFontFamilyFallbackStack = function (fontFamily) { |
| 546 |
let fallbackStack = '' |
| 547 |
|
| 548 |
const fontDetails = customify.fontFields.getFontDetails(fontFamily) |
| 549 |
if (typeof fontDetails.fallback_stack !== 'undefined' && !_.isEmpty(fontDetails.fallback_stack)) { |
| 550 |
fallbackStack = fontDetails.fallback_stack |
| 551 |
} else if (typeof fontDetails.category !== 'undefined' && !_.isEmpty(fontDetails.category)) { |
| 552 |
const category = fontDetails.category |
| 553 |
// Search in the available categories for a match. |
| 554 |
if (typeof customify.fonts.categories[category] !== 'undefined') { |
| 555 |
// Matched by category ID/key |
| 556 |
fallbackStack = typeof customify.fonts.categories[category].fallback_stack !== 'undefined' ? customify.fonts.categories[category].fallback_stack : '' |
| 557 |
} else { |
| 558 |
// We need to search for aliases. |
| 559 |
_.find(customify.fonts.categories, function (categoryDetails) { |
| 560 |
if (typeof categoryDetails.aliases !== 'undefined') { |
| 561 |
const aliases = maybeImplodeList(categoryDetails.aliases) |
| 562 |
if (aliases.indexOf(category) !== -1) { |
| 563 |
// Found it. |
| 564 |
fallbackStack = typeof categoryDetails.fallback_stack !== 'undefined' ? categoryDetails.fallback_stack : '' |
| 565 |
return true |
| 566 |
} |
| 567 |
} |
| 568 |
|
| 569 |
return false |
| 570 |
}) |
| 571 |
} |
| 572 |
} |
| 573 |
|
| 574 |
return fallbackStack |
| 575 |
} |
| 576 |
|
| 577 |
// Mirror logic of server-side Customify_Fonts_Global::sanitizeFontFamilyCSSValue() |
| 578 |
const sanitizeFontFamilyCSSValue = function (value) { |
| 579 |
// Since we might get a stack, attempt to treat is a comma-delimited list. |
| 580 |
let fontFamilies = maybeExplodeList(value) |
| 581 |
if (!fontFamilies.length) { |
| 582 |
return '' |
| 583 |
} |
| 584 |
|
| 585 |
_.each(fontFamilies, function (fontFamily, key) { |
| 586 |
// Make sure that the font family is free from " or ' or whitespace, at the front. |
| 587 |
fontFamily = fontFamily.replace(new RegExp(/^\s*["'‘’“”]*\s*/), '') |
| 588 |
// Make sure that the font family is free from " or ' or whitespace, at the back. |
| 589 |
fontFamily = fontFamily.replace(new RegExp(/\s*["'‘’“”]*\s*$/), '') |
| 590 |
|
| 591 |
if ('' === fontFamily) { |
| 592 |
delete fontFamilies[key] |
| 593 |
return; |
| 594 |
} |
| 595 |
|
| 596 |
// Now, if the font family contains spaces, wrap it in ". |
| 597 |
if (fontFamily.indexOf(' ') !== -1) { |
| 598 |
fontFamily = '"' + fontFamily + '"' |
| 599 |
} |
| 600 |
|
| 601 |
// Finally, put it back. |
| 602 |
fontFamilies[key] = fontFamily |
| 603 |
}) |
| 604 |
|
| 605 |
return maybeImplodeList( fontFamilies ); |
| 606 |
} |
| 607 |
|
| 608 |
const maybeExplodeList = function(str, delimiter = ',') { |
| 609 |
if (typeof str === 'object') { |
| 610 |
str = standardizeToArray(str) |
| 611 |
} |
| 612 |
|
| 613 |
// If by any chance we are given an array, just return it |
| 614 |
if (Array.isArray(str)) { |
| 615 |
return str |
| 616 |
} |
| 617 |
|
| 618 |
// Anything else we coerce to a string |
| 619 |
if ( typeof str !== 'string' ) { |
| 620 |
str = String(str); |
| 621 |
} |
| 622 |
|
| 623 |
// Make sure we trim it |
| 624 |
str = str.trim(); |
| 625 |
|
| 626 |
// Bail on empty string |
| 627 |
if ( !str.length ) { |
| 628 |
return []; |
| 629 |
} |
| 630 |
|
| 631 |
// Return the whole string as an element if the delimiter is missing |
| 632 |
if ( str.indexOf(delimiter) === -1 ) { |
| 633 |
return [str]; |
| 634 |
} |
| 635 |
|
| 636 |
// Explode it and return it |
| 637 |
return explode(delimiter, str); |
| 638 |
} |
| 639 |
|
| 640 |
const maybeImplodeList = function(value, glue = ',') { |
| 641 |
// If by any chance we are given a string, just return it |
| 642 |
if (typeof value === 'string' || typeof value === 'number') { |
| 643 |
return String(value) |
| 644 |
} |
| 645 |
|
| 646 |
if (typeof value === 'object') { |
| 647 |
value = standardizeToArray(value) |
| 648 |
} |
| 649 |
|
| 650 |
if (Array.isArray(value)) { |
| 651 |
return implode(glue, value) |
| 652 |
} |
| 653 |
|
| 654 |
// For anything else we return an empty string. |
| 655 |
return '' |
| 656 |
} |
| 657 |
|
| 658 |
const explode = function (delimiter, string, limit) { |
| 659 |
// discuss at: https://locutus.io/php/explode/ |
| 660 |
// original by: Kevin van Zonneveld (https://kvz.io) |
| 661 |
// example 1: explode(' ', 'Kevin van Zonneveld') |
| 662 |
// returns 1: [ 'Kevin', 'van', 'Zonneveld' ] |
| 663 |
|
| 664 |
if (arguments.length < 2 || |
| 665 |
typeof delimiter === 'undefined' || |
| 666 |
typeof string === 'undefined') { |
| 667 |
return null |
| 668 |
} |
| 669 |
if (delimiter === '' || |
| 670 |
delimiter === false || |
| 671 |
delimiter === null) { |
| 672 |
return false |
| 673 |
} |
| 674 |
if (typeof delimiter === 'function' || |
| 675 |
typeof delimiter === 'object' || |
| 676 |
typeof string === 'function' || |
| 677 |
typeof string === 'object') { |
| 678 |
return { |
| 679 |
0: '' |
| 680 |
} |
| 681 |
} |
| 682 |
if (delimiter === true) { |
| 683 |
delimiter = '1' |
| 684 |
} |
| 685 |
|
| 686 |
// Here we go... |
| 687 |
delimiter += '' |
| 688 |
string += '' |
| 689 |
|
| 690 |
let s = string.split(delimiter) |
| 691 |
|
| 692 |
if (typeof limit === 'undefined') return s |
| 693 |
|
| 694 |
// Support for limit |
| 695 |
if (limit === 0) limit = 1 |
| 696 |
|
| 697 |
// Positive limit |
| 698 |
if (limit > 0) { |
| 699 |
if (limit >= s.length) { |
| 700 |
return s |
| 701 |
} |
| 702 |
return s |
| 703 |
.slice(0, limit - 1) |
| 704 |
.concat([s.slice(limit - 1) |
| 705 |
.join(delimiter) |
| 706 |
]) |
| 707 |
} |
| 708 |
|
| 709 |
// Negative limit |
| 710 |
if (-limit >= s.length) { |
| 711 |
return [] |
| 712 |
} |
| 713 |
|
| 714 |
s.splice(s.length + limit) |
| 715 |
return s |
| 716 |
} |
| 717 |
|
| 718 |
const implode = function (glue, pieces) { |
| 719 |
// discuss at: https://locutus.io/php/implode/ |
| 720 |
// original by: Kevin van Zonneveld (https://kvz.io) |
| 721 |
// improved by: Waldo Malqui Silva (https://waldo.malqui.info) |
| 722 |
// improved by: Itsacon (https://www.itsacon.net/) |
| 723 |
// bugfixed by: Brett Zamir (https://brett-zamir.me) |
| 724 |
// example 1: implode(' ', ['Kevin', 'van', 'Zonneveld']) |
| 725 |
// returns 1: 'Kevin van Zonneveld' |
| 726 |
// example 2: implode(' ', {first:'Kevin', last: 'van Zonneveld'}) |
| 727 |
// returns 2: 'Kevin van Zonneveld' |
| 728 |
|
| 729 |
let i = '' |
| 730 |
let retVal = '' |
| 731 |
let tGlue = '' |
| 732 |
|
| 733 |
if (arguments.length === 1) { |
| 734 |
pieces = glue |
| 735 |
glue = '' |
| 736 |
} |
| 737 |
|
| 738 |
if (typeof pieces === 'object') { |
| 739 |
if (Object.prototype.toString.call(pieces) === '[object Array]') { |
| 740 |
return pieces.join(glue) |
| 741 |
} |
| 742 |
for (i in pieces) { |
| 743 |
retVal += tGlue + pieces[i] |
| 744 |
tGlue = glue |
| 745 |
} |
| 746 |
return retVal |
| 747 |
} |
| 748 |
|
| 749 |
return pieces |
| 750 |
} |
| 751 |
}) |
| 752 |
})(jQuery, window, document) |
| 753 |
|