PluginProbe
Customify / 2.10.9
Customify v2.10.9
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_preview.js

customizer_preview.js in Customify 2.10.9, at js/customizer_preview.js

757 lines 27.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 && typeof fontDetails.variants !== 'undefined' // If the font has no variants, any variant value we may have received should be ignored.
473 && _.includes(fontDetails.variants, font.font_variant) // If the value variant is not amongst the available ones, load all available variants.
474 ) ? font.font_variant : typeof fontDetails.variants !== 'undefined' ? fontDetails.variants : []
475
476 if (!_.isEmpty(variants)) {
477 variants = standardizeToArray(variants)
478
479 if (!_.isEmpty(variants)) {
480 family = family + ':' + variants.map(function (variant) {
481 return customify.fontFields.convertFontVariantToFVD(variant)
482 }).join(',')
483 }
484 }
485
486 if (fontsCache.indexOf(family) === -1) {
487 WebFont.load({
488 custom: {
489 families: [family],
490 urls: [fontDetails.src]
491 },
492 classes: false,
493 events: false,
494 })
495
496 // Remember we've loaded this family (with it's variants) so we don't load it again.
497 fontsCache.push(family)
498 }
499 }
500 // Handle Google fonts since Web Font Loader has a special module for them.
501 else if (fontType === 'google_font') {
502
503 // Handle the font variants
504 // If there is a selected font variant and we haven't been instructed to load all, load only that,
505 // otherwise load all the available variants.
506 let variants =
507 (
508 typeof font.font_variant !== 'undefined'
509 && (typeof fontConfig['fields']['font-weight']['loadAllVariants'] === 'undefined' || !fontConfig['fields']['font-weight']['loadAllVariants'])
510 && typeof fontDetails.variants !== 'undefined' // If the font has no variants, any variant value we may have received should be ignored.
511 && _.includes(fontDetails.variants, font.font_variant) // If the value variant is not amongst the available ones, load all available variants.
512 ) ? font.font_variant : typeof fontDetails.variants !== 'undefined' ? fontDetails.variants : []
513
514 if (!_.isEmpty(variants)) {
515 variants = standardizeToArray(variants)
516
517 if (!_.isEmpty(variants)) {
518 family = family + ':' + variants.join(',')
519 }
520 }
521
522 if (fontsCache.indexOf(family) === -1) {
523 WebFont.load({
524 google: {families: [family]},
525 classes: false,
526 events: false,
527 })
528
529 // Remember we've loaded this family (with it's variants) so we don't load it again.
530 fontsCache.push(family)
531 }
532
533 } else {
534 // Maybe Typekit, Fonts.com or Fontdeck fonts
535 }
536 }
537
538 const standardizeToArray = function (value) {
539 if (typeof value === 'string' || typeof value === 'number') {
540 value = [value]
541 } else if (typeof value === 'object') {
542 value = Object.values(value)
543 }
544
545 return value
546 }
547
548 // This is a mirror logic of the server-side Customify_Fonts_Global::getFontFamilyFallbackStack()
549 const getFontFamilyFallbackStack = function (fontFamily) {
550 let fallbackStack = ''
551
552 const fontDetails = customify.fontFields.getFontDetails(fontFamily)
553 if (typeof fontDetails.fallback_stack !== 'undefined' && !_.isEmpty(fontDetails.fallback_stack)) {
554 fallbackStack = fontDetails.fallback_stack
555 } else if (typeof fontDetails.category !== 'undefined' && !_.isEmpty(fontDetails.category)) {
556 const category = fontDetails.category
557 // Search in the available categories for a match.
558 if (typeof customify.fonts.categories[category] !== 'undefined') {
559 // Matched by category ID/key
560 fallbackStack = typeof customify.fonts.categories[category].fallback_stack !== 'undefined' ? customify.fonts.categories[category].fallback_stack : ''
561 } else {
562 // We need to search for aliases.
563 _.find(customify.fonts.categories, function (categoryDetails) {
564 if (typeof categoryDetails.aliases !== 'undefined') {
565 const aliases = maybeImplodeList(categoryDetails.aliases)
566 if (aliases.indexOf(category) !== -1) {
567 // Found it.
568 fallbackStack = typeof categoryDetails.fallback_stack !== 'undefined' ? categoryDetails.fallback_stack : ''
569 return true
570 }
571 }
572
573 return false
574 })
575 }
576 }
577
578 return fallbackStack
579 }
580
581 // Mirror logic of server-side Customify_Fonts_Global::sanitizeFontFamilyCSSValue()
582 const sanitizeFontFamilyCSSValue = function (value) {
583 // Since we might get a stack, attempt to treat is a comma-delimited list.
584 let fontFamilies = maybeExplodeList(value)
585 if (!fontFamilies.length) {
586 return ''
587 }
588
589 _.each(fontFamilies, function (fontFamily, key) {
590 // Make sure that the font family is free from " or ' or whitespace, at the front.
591 fontFamily = fontFamily.replace(new RegExp(/^\s*["'‘’“”]*\s*/), '')
592 // Make sure that the font family is free from " or ' or whitespace, at the back.
593 fontFamily = fontFamily.replace(new RegExp(/\s*["'‘’“”]*\s*$/), '')
594
595 if ('' === fontFamily) {
596 delete fontFamilies[key]
597 return;
598 }
599
600 // Now, if the font family contains spaces, wrap it in ".
601 if (fontFamily.indexOf(' ') !== -1) {
602 fontFamily = '"' + fontFamily + '"'
603 }
604
605 // Finally, put it back.
606 fontFamilies[key] = fontFamily
607 })
608
609 return maybeImplodeList( fontFamilies );
610 }
611
612 const maybeExplodeList = function(str, delimiter = ',') {
613 if (typeof str === 'object') {
614 str = standardizeToArray(str)
615 }
616
617 // If by any chance we are given an array, just return it
618 if (Array.isArray(str)) {
619 return str
620 }
621
622 // Anything else we coerce to a string
623 if ( typeof str !== 'string' ) {
624 str = String(str);
625 }
626
627 // Make sure we trim it
628 str = str.trim();
629
630 // Bail on empty string
631 if ( !str.length ) {
632 return [];
633 }
634
635 // Return the whole string as an element if the delimiter is missing
636 if ( str.indexOf(delimiter) === -1 ) {
637 return [str];
638 }
639
640 // Explode it and return it
641 return explode(delimiter, str);
642 }
643
644 const maybeImplodeList = function(value, glue = ',') {
645 // If by any chance we are given a string, just return it
646 if (typeof value === 'string' || typeof value === 'number') {
647 return String(value)
648 }
649
650 if (typeof value === 'object') {
651 value = standardizeToArray(value)
652 }
653
654 if (Array.isArray(value)) {
655 return implode(glue, value)
656 }
657
658 // For anything else we return an empty string.
659 return ''
660 }
661
662 const explode = function (delimiter, string, limit) {
663 // discuss at: https://locutus.io/php/explode/
664 // original by: Kevin van Zonneveld (https://kvz.io)
665 // example 1: explode(' ', 'Kevin van Zonneveld')
666 // returns 1: [ 'Kevin', 'van', 'Zonneveld' ]
667
668 if (arguments.length < 2 ||
669 typeof delimiter === 'undefined' ||
670 typeof string === 'undefined') {
671 return null
672 }
673 if (delimiter === '' ||
674 delimiter === false ||
675 delimiter === null) {
676 return false
677 }
678 if (typeof delimiter === 'function' ||
679 typeof delimiter === 'object' ||
680 typeof string === 'function' ||
681 typeof string === 'object') {
682 return {
683 0: ''
684 }
685 }
686 if (delimiter === true) {
687 delimiter = '1'
688 }
689
690 // Here we go...
691 delimiter += ''
692 string += ''
693
694 let s = string.split(delimiter)
695
696 if (typeof limit === 'undefined') return s
697
698 // Support for limit
699 if (limit === 0) limit = 1
700
701 // Positive limit
702 if (limit > 0) {
703 if (limit >= s.length) {
704 return s
705 }
706 return s
707 .slice(0, limit - 1)
708 .concat([s.slice(limit - 1)
709 .join(delimiter)
710 ])
711 }
712
713 // Negative limit
714 if (-limit >= s.length) {
715 return []
716 }
717
718 s.splice(s.length + limit)
719 return s
720 }
721
722 const implode = function (glue, pieces) {
723 // discuss at: https://locutus.io/php/implode/
724 // original by: Kevin van Zonneveld (https://kvz.io)
725 // improved by: Waldo Malqui Silva (https://waldo.malqui.info)
726 // improved by: Itsacon (https://www.itsacon.net/)
727 // bugfixed by: Brett Zamir (https://brett-zamir.me)
728 // example 1: implode(' ', ['Kevin', 'van', 'Zonneveld'])
729 // returns 1: 'Kevin van Zonneveld'
730 // example 2: implode(' ', {first:'Kevin', last: 'van Zonneveld'})
731 // returns 2: 'Kevin van Zonneveld'
732
733 let i = ''
734 let retVal = ''
735 let tGlue = ''
736
737 if (arguments.length === 1) {
738 pieces = glue
739 glue = ''
740 }
741
742 if (typeof pieces === 'object') {
743 if (Object.prototype.toString.call(pieces) === '[object Array]') {
744 return pieces.join(glue)
745 }
746 for (i in pieces) {
747 retVal += tGlue + pieces[i]
748 tGlue = glue
749 }
750 return retVal
751 }
752
753 return pieces
754 }
755 })
756 })(jQuery, window, document)
757