PluginProbe
Customify / 2.10.1
Customify v2.10.1
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
← All changes | js/customizer.js +673 -837 1.2.3 → 2.10.1 View file →
@@ -1,987 +1,823 @@
1 -(function( $, exports ) {
2 - $( document ).ready( function() {
3 - // when the customizer is ready prepare our fields events
4 - wp.customize.bind( 'ready', function() {
5 - var api = this,
6 - timeout = null;
1 +/** @namespace customify */
2 +window.customify = window.customify || parent.customify || {};
7 3
8 - // add ace editors
9 - $( '.customify_ace_editor' ).each( function( key, el ) {
10 - var id = $( this ).attr( 'id' ),
11 - css_editor = ace.edit( id );
4 +(function ($, customify, wp) {
5 + const api = wp.customize
6 + const $window = $(window)
7 + const $document = $(document)
8 + let timeout = null
12 9
13 - var editor_type = $( this ).data( 'editor_type' );
14 - // init the ace editor
15 - css_editor.setTheme( "ace/theme/github" );
16 - css_editor.getSession().setMode( "ace/mode/" + editor_type );
10 + // when the customizer is ready prepare our fields events
11 + api.bind('ready', function () {
17 12
18 - // hide the textarea and enable the ace editor
19 - var textarea = $( '#' + id + '_textarea' ).hide();
20 - css_editor.getSession().setValue( textarea.val() );
13 + // Create a stack of callbacks bound to parent settings to be able to unbind them
14 + // when altering the connected_fields attribute.
15 + if (typeof customify.connectedFieldsCallbacks === 'undefined') {
16 + customify.connectedFieldsCallbacks = {}
17 + }
21 18
22 - // each time a change is triggered start a timeout of 1,5s and when is finished refresh the previewer
23 - // if the user types faster than this delay then reset it
24 - css_editor.getSession().on( 'change', function( e ) {
25 - if ( timeout !== null ) {
26 - clearTimeout( timeout );
27 - timeout = null;
28 - } else {
29 - timeout = setTimeout( function() {
30 - //var state = css_editor.session.getState();
31 - textarea.val( css_editor.getSession().getValue() );
32 - textarea.trigger( 'change' );
33 - }, 1500 );
34 - }
35 - } );
36 - } );
19 + // Initialize ACE editors.
20 + handleAceEditors()
37 21
38 - // simple select2 field
39 - $( '.customify_select2' ).select2();
22 + // Initialize simple select2 fields.
23 + $('.customify_select2').select2()
40 24
41 - prepare_typography_field();
25 + // Initialize font fields.
26 + customify.fontFields.init()
42 27
43 - /**
44 - * Make the customizer save on CMD/CTRL+S action
45 - * This is awesome!!!
46 - */
47 - $( window ).bind( 'keydown', function( event ) {
48 - if ( event.ctrlKey || event.metaKey ) {
49 - switch ( String.fromCharCode( event.which ).toLowerCase() ) {
50 - case 's':
51 - event.preventDefault();
52 - api.previewer.save();
53 - break;
54 - }
55 - }
56 - } );
28 + // For each range input add a value preview output.
29 + $('.accordion-section-content[id*="' + customify.config.options_name + '"], #sub-accordion-section-style_manager_section').each(function () {
30 + // Initialize range fields logic
31 + handleRangeFields(this)
32 + })
57 33
58 - // for each range input add a value preview output
59 - $( 'input[type="range"]' ).each( function() {
60 - var $clone = $( this ).clone();
34 + // Handle presets (legacy).
35 + handlePresets()
61 36
62 - $clone
63 - .attr( 'type', 'number' )
64 - .attr( 'class', 'range-value' );
37 + // Initialize custom background fields.
38 + customifyBackgroundJsControl.init()
65 39
66 - $( this ).after( $clone );
40 + setTimeout(function () {
41 + customifyFoldingFields()
42 + }, 1000)
67 43
68 - $( this ).on( 'input', function() {
69 - $( this ).siblings( '.range-value' ).val( $( this ).val() );
70 - } );
71 - } );
44 + // Handle reset buttons
45 + handleResetButtons()
72 46
73 - if ( $( 'button[data-action="reset_customify"]' ).length > 0 ) {
74 - // reset_button
75 - $( document ).on( 'click', '#customize-control-reset_customify button', function( ev ) {
76 - ev.preventDefault();
47 + // Handle the section tabs (ex: Layout | Fonts | Colors)
48 + handleSectionTabs()
77 49
78 - 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!' );
50 + // Bind any connected fields, except those in the Style Manager.
51 + // Those are handled by the appropriate Style Manager component (Color Palettes, Font Palettes, etc ).
52 + bindConnectedFields()
79 53
80 - if ( !iAgree ) {
81 - return;
82 - }
54 + // Handle the preview iframe.
55 + handlePreviewIframe()
83 56
84 - $.each( api.settings.controls, function( key, ctrl ) {
85 - var id = key.replace( '_control', '' );
86 - var setting = customify_settings.settings[id];
57 + // Sometimes a php save may be needed. Trigger it if the appropiate URL var is present.
58 + if (getUrlVar('save_customizer_once')) {
59 + api.previewer.save()
60 + }
61 + })
87 62
88 - if ( typeof setting !== "undefined" && typeof setting.default !== "undefined" ) {
63 + /**
64 + * Handle the ACE editor fields.
65 + */
66 + function handleAceEditors () {
67 + $('.customify_ace_editor').each(function (key, el) {
68 + const id = $(this).attr('id'),
69 + cssEditorInstance = ace.edit(id)
89 70
90 - var start_pos = id.indexOf( '[' ) + 1;
91 - var end_pos = id.indexOf( ']', start_pos );
71 + const editor_type = $(this).data('editor_type')
72 + // init the ace editor
73 + cssEditorInstance.setTheme('ace/theme/github')
74 + cssEditorInstance.getSession().setMode('ace/mode/' + editor_type)
92 75
93 - id = id.substring( start_pos, end_pos );
94 - api_set_setting_value( id, setting.default );
95 - }
96 - } );
76 + // hide the textarea and enable the ace editor
77 + const textarea = $('#' + id + '_textarea').hide()
78 + cssEditorInstance.getSession().setValue(textarea.val())
97 79
98 - api.previewer.save();
99 - } );
80 + // each time a change is triggered start a timeout of 1,5s and when is finished refresh the previewer
81 + // if the user types faster than this delay then reset it
82 + cssEditorInstance.getSession().on('change', function (event) {
83 + if (timeout !== null) {
84 + clearTimeout(timeout)
85 + timeout = null
86 + } else {
87 + timeout = setTimeout(function () {
88 + textarea.val(cssEditorInstance.getSession().getValue())
89 + textarea.trigger('change', ['customify'])
90 + }, 1500)
91 + }
92 + })
93 + })
94 + }
100 95
101 - // add a reset button for each panel
102 - $( '.panel-meta' ).each( function( el, key ) {
103 - var container = $( this ).parents( '.control-panel' ),
104 - id = container.attr( 'id' ),
105 - panel_id = id.replace( 'accordion-panel-', '' );
96 + /**
97 + * Handle the presets (legacy).
98 + */
99 + function handlePresets () {
100 + $('body').on('customify:preset-change', function (event) {
101 + const data = $(event.target).data('options')
106 102
103 + if (!_.isUndefined(data)) {
104 + $.each(data, function (settingID, value) {
105 + apiSetSettingValue(settingID, value)
106 + })
107 + }
108 + })
109 + $document.on('change', 'select.js-customify-preset', function () {
110 + const $source = $(this)
111 + const $target = $source.children('[value="' + $source.val() + '"]')
112 + $target.trigger('customify:preset-change')
113 + })
114 + $document.on('click', '.js-customify-preset input', function () {
115 + $(this).trigger('customify:preset-change')
116 + })
117 + }
107 118
108 - $( this ).parent().append( '<button class="reset_panel button" data-panel="' + panel_id + '">Panel\'s defaults</button>' );
109 - } );
119 + const handleRangeFields = function (el) {
110 120
111 - // reset panel
112 - $( document ).on( 'click', '.reset_panel', function( e ) {
113 - e.preventDefault();
121 + // For each range input add a number field (for preview mainly - but it can also be used for input)
122 + $(el).find('input[type="range"]').each(function () {
123 + const $range = $(this)
124 + let $number = $range.siblings('.range-value')
114 125
115 - var panel_id = $( this ).data( 'panel' ),
116 - panel = api.panel( panel_id ),
117 - sections = panel.sections(),
118 - iAgree = confirm( "Do you really want to reset " + panel.params.title + "?" );
126 + if (!$number.length) {
127 + $number = $range.clone()
119 128
120 - if ( !iAgree ) {
121 - return;
122 - }
123 - if ( sections.length > 0 ) {
124 - $.each( sections, function() {
125 - //var settings = this.settings();
126 - var controls = this.controls();
129 + $number
130 + .attr('type', 'number')
131 + .attr('class', 'range-value')
132 + .removeAttr('data-value_entry')
127 133
128 - if ( controls.length > 0 ) {
129 - $.each( controls, function( key, ctrl ) {
130 - var id = ctrl.id.replace( '_control', '' ),
131 - setting = customify_settings.settings[id];
134 + if ($range.first().attr('id')) {
135 + $number.attr('id', $range.first().attr('id') + '_number')
136 + }
137 + $number.insertAfter($range)
138 + }
132 139
133 - if ( typeof setting !== "undefined" && typeof setting.default !== "undefined" ) {
140 + function hasValidValue ($input) {
141 + const min = $input.attr('min')
142 + const max = $input.attr('max')
143 + const value = $input.val()
134 144
135 - var start_pos = id.indexOf( '[' ) + 1,
136 - end_pos = id.indexOf( ']', start_pos );
145 + if (typeof min !== 'undefined' && parseFloat(min) > parseFloat(value)) {
146 + return false
147 + }
137 148
138 - id = id.substring( start_pos, end_pos );
139 - api_set_setting_value( id, setting.default );
140 - }
141 - } );
142 - }
143 - } );
144 - }
145 - } );
149 + return !(typeof max !== 'undefined' && parseFloat(max) < parseFloat(value))
150 + }
146 151
147 - //add reset section
148 - $( '.accordion-section-content' ).each( function( el, key ) {
149 - var section = $( this ).parent(),
150 - section_id = section.attr( 'id' );
152 + // Put the value into the number field.
153 + $range.on('input change', function (event) {
154 + if (event.target.value === $number.val()) {
155 + // Nothing to do if the values are identical.
156 + return;
157 + }
151 158
152 - if ( (typeof section_id !== "undefined" ? section_id.indexOf( customify_settings.options_name ) : -1 ) === -1 ) {
153 - return;
154 - }
159 + $number.val($range.val())
160 + })
155 161
156 - if ( typeof section_id !== 'undefined' && section_id.indexOf( 'accordion-section-' ) > -1 ) {
157 - var id = section_id.replace( 'accordion-section-', '' );
158 - $( this ).prepend( '<button class="reset_section button" data-section="' + id + '">Section\'s defaults</button>' );
159 - }
160 - } );
162 + // When clicking outside the number field or on Enter.
163 + $number.on('blur keyup', function (event) {
164 + if ('keyup' === event.type && event.keyCode !== 13) {
165 + return
166 + }
161 167
162 - // reset section event
163 - $( document ).on( 'click', '.reset_section', function( e ) {
164 - e.preventDefault();
168 + if (event.target.value === $range.val()) {
169 + // Nothing to do if the values are identical.
170 + return;
171 + }
165 172
166 - var section_id = $( this ).data( 'section' ),
167 - section = api.section( section_id ),
168 - controls = section.controls();
173 + if (!hasValidValue($number)) {
174 + $number.val($range.val())
175 + shake($number)
176 + } else {
177 + // Do not mark this trigger as being programmatically triggered by Customify since it is a result of a user input.
178 + $range.val($number.val()).trigger('change')
179 + }
180 + })
169 181
170 - var iAgree = confirm( "Do you really want to reset " + section.params.title + "?" );
182 + function shake ($field) {
183 + $field.addClass('input-shake input-error')
184 + $field.one('animationend', function () {
185 + $field.removeClass('input-shake input-error')
186 + })
187 + }
188 + })
189 + }
171 190
172 - if ( !iAgree ) {
173 - return;
174 - }
191 + /**
192 + * Handle reset buttons in the Customizer.
193 + */
194 + function handleResetButtons () {
195 + const showResetButtons = $('button[data-action="reset_customify"]').length > 0
175 196
176 - if ( controls.length > 0 ) {
177 - $.each( controls, function( key, ctrl ) {
178 - var id = ctrl.id.replace( '_control', '' ),
179 - setting = customify_settings.settings[id];
197 + if (showResetButtons) {
198 + createResetPanelButtons()
199 + createResetSectionButtons()
180 200
181 - if ( typeof setting !== "undefined" && typeof setting.default !== "undefined" ) {
201 + $document.on('click', '.js-reset-panel', onResetPanel)
202 + $document.on('click', '.js-reset-section', onResetSection)
203 + $document.on('click', '#customize-control-reset_customify button', onReset)
204 + }
205 + }
182 206
183 - var start_pos = id.indexOf( '[' ) + 1,
184 - end_pos = id.indexOf( ']', start_pos );
207 + function createResetPanelButtons () {
185 208
186 - id = id.substring( start_pos, end_pos );
187 - api_set_setting_value( id, setting.default );
188 - }
189 - } );
190 - }
191 - } );
192 - }
209 + $('.panel-meta').each(function (i, obj) {
210 + const $this = $(obj)
211 + const container = $this.parents('.control-panel')
212 + let id = container.attr('id')
193 213
194 - $( document ).on( 'change', '.customize-control input.range-value', function() {
195 - var range = $( this ).siblings( 'input[type="range"]' );
196 - range.val( $( this ).val() );
197 - } );
214 + if (typeof id !== 'undefined') {
215 + id = id.replace('sub-accordion-panel-', '')
216 + id = id.replace('accordion-panel-', '')
217 + const $buttonWrapper = $('<li class="customize-control customize-control-reset"></li>')
218 + const $button = $('<button class="button js-reset-panel" data-panel="' + id + '"></button>')
198 219
199 - $( document ).on( 'change', '.customify_typography_font_subsets', function( ev ) {
220 + $button.text(customify.l10n.panelResetButton).appendTo($buttonWrapper)
221 + $this.parent().append($buttonWrapper)
222 + }
223 + })
224 + }
200 225
201 - var $input = $( this ).parents( '.options' ).siblings( '.customify_typography' ).children( '.customify_typography_values' ),
202 - current_val = $input.val();
226 + function createResetSectionButtons () {
227 + $('.accordion-section-content').each(function (el, key) {
228 + const $this = $(this)
229 + const sectionID = $this.attr('id')
203 230
204 - current_val = JSON.parse( current_val );
205 - current_val.selected_subsets = $( this ).val();
231 + if (_.isUndefined(sectionID) || sectionID.indexOf(customify.config.options_name) === -1) {
232 + return
233 + }
206 234
207 - $input.val( JSON.stringify( current_val ) );
235 + const id = sectionID.replace('sub-accordion-section-', '')
236 + const $button = $('<button class="button js-reset-section" data-section="' + id + '"></button>')
237 + const $buttonWrapper = $('<li class="customize-control customize-control-reset"></li>')
208 238
209 - $input.trigger( 'change' );
210 - } );
239 + $button.text(customify.l10n.sectionResetButton)
240 + $buttonWrapper.append($button)
211 241
212 - $( document ).on( 'change', '.customify_typography_font_weight', function( ev ) {
242 + $this.append($buttonWrapper)
243 + })
244 + }
213 245
214 - var $input = $( this ).parents( '.options' ).siblings( '.customify_typography' ).children( '.customify_typography_values' ),
215 - current_val = $input.val();
246 + function onReset (ev) {
247 + ev.preventDefault()
216 248
217 - current_val = JSON.parse( current_val );
218 - // @todo currently the font weight selector works for one value only
219 - // maybe make this a multiselect
220 - current_val.selected_variants = {0: $( this ).val()};
249 + const iAgree = confirm(customify.l10n.resetGlobalConfirmMessage)
221 250
222 - $input.val( JSON.stringify( current_val ) );
223 - $input.trigger( 'change' );
224 - } );
251 + if (!iAgree) {
252 + return
253 + }
225 254
226 - // presets
227 - $( document ).on( 'change', '.customify_preset.select', function() {
228 - var api = wp.customize,
229 - this_option = $( this ).children( '[value="' + $( this ).val() + '"]' ),
230 - data = $( this_option ).data( 'options' );
255 + $.each(api.settings.controls, function (key, ctrl) {
256 + const settingID = key.replace('_control', '')
257 + const setting = customify.config.settings[settingID]
231 258
232 - if ( typeof data !== 'undefined' ) {
233 - $.each( data, function( id, value ) {
234 - api_set_setting_value( id, value );
235 - } );
236 - }
259 + if (!_.isUndefined(setting) && !_.isUndefined(setting.default)) {
260 + apiSetSettingValue(settingID, setting.default)
261 + }
262 + })
237 263
238 - api.previewer.refresh();
239 - } );
264 + api.previewer.save()
265 + }
240 266
241 - $( document ).on( 'click', '.customify_preset.radio input, .customify_preset.radio_buttons input, .awesome_presets input', function() {
242 - var api = wp.customize;
243 - var this_option = this;//$(this).children('[value="' + $(this).val() + '"]');
244 - var data = $( this_option ).data( 'options' );
267 + function onResetPanel (e) {
268 + e.preventDefault()
245 269
246 - if ( typeof data !== 'undefined' ) {
247 - $.each( data, function( id, value ) {
248 - api_set_setting_value( id, value );
249 - } );
250 - }
270 + const panelID = $(this).data('panel'),
271 + panel = api.panel(panelID),
272 + sections = panel.sections(),
273 + iAgree = confirm(customify.l10n.resetPanelConfirmMessage)
251 274
252 - api.previewer.refresh();
253 - } );
275 + if (!iAgree) {
276 + return
277 + }
278 + if (sections.length > 0) {
279 + $.each(sections, function () {
280 + const controls = this.controls()
254 281
255 - // bind our event on click
256 - $( document ).on( 'click', '.customify_import_demo_data_button', function( event ) {
257 - //if ( $( this ).hasClass( '.wpGrade_button_inactive' ) ) {
258 - // return false;
259 - //} else {
260 - // $( this ).addClass( '.wpGrade_button_inactive' );
261 - // $( this ).attr( 'disabled', 'disabled' );
262 - //}
263 - //var confirmImport = confirm( listable_demodata_params.l10n.import_confirm );
264 - //if ( confirmImport == false ) return false;
282 + if (controls.length > 0) {
283 + $.each(controls, function (key, ctrl) {
284 + const settingID = ctrl.id.replace('_control', ''),
285 + setting = customify.config.settings[settingID]
265 286
266 - //@todo start an animation here
267 - var key = $( this ).data( 'key' );
287 + if (!_.isUndefined(setting) && !_.isUndefined(setting.default)) {
288 + apiSetSettingValue(settingID, setting.default)
289 + }
290 + })
291 + }
292 + })
293 + }
294 + }
268 295
269 - var import_queue = new Queue( api );
296 + function onResetSection (e) {
297 + e.preventDefault()
270 298
271 - /// calculate the number of steps
272 - var steps = [];
299 + const sectionID = $(this).data('section'),
300 + section = api.section(sectionID),
301 + controls = section.controls()
273 302
274 - if ( typeof customify_settings.settings[key].imports !== "undefined" ) {
303 + const iAgree = confirm(customify.l10n.resetSectionConfirmMessage)
275 304
276 - $.each( customify_settings.settings[key].imports, function( i, import_setts, k ) {
277 - if ( typeof import_setts.steps === "undefined" ) {
278 - steps.push( {id: i, type: import_setts.type} );
279 - } else {
280 - var count = import_setts.steps;
305 + if (!iAgree) {
306 + return
307 + }
281 308
282 - while ( count >= 1 ) {
283 - steps.push( {id: i, type: import_setts.type, count: count} );
284 - count = count - 1;
285 - }
286 - }
287 - } );
288 - }
309 + if (controls.length > 0) {
310 + $.each(controls, function (key, ctrl) {
311 + const setting_id = ctrl.id.replace('_control', ''),
312 + setting = customify.config.settings[setting_id]
289 313
290 - import_queue.add_steps( 'import_demo_data_action_id', steps );
291 - return false;
292 - } );
314 + if (!_.isUndefined(setting) && !_.isUndefined(setting.default)) {
315 + apiSetSettingValue(setting_id, setting.default)
316 + }
317 + })
318 + }
319 + }
293 320
294 - customifyBackgroundJsControl.init();
321 + function handleSectionTabs () {
322 + const $navs = $('.js-section-navigation')
295 323
296 - // sometimes there may be needed a php save
297 - if ( getUrlVars( 'save_customizer_once' ) ) {
298 - api.previewer.save();
299 - }
324 + $navs.each(function () {
325 + const $nav = $(this)
326 + const $title = $nav.parents('.accordion-section-content').find('.customize-section-title')
327 + const $parent = $nav.closest('.customize-control')
300 328
301 - setTimeout(function () {
302 - customifyFoldingFields();
303 - }, 1000);
304 - } );
329 + $nav.appendTo($title)
330 + $title.parent().addClass('has-nav')
331 + $parent.addClass('screen-reader-text')
332 + })
305 333
306 - /**
307 - * This function will search for all the interdependend fields and make a bound between them.
308 - * So whenever a target is changed, it will take actions to the dependent fields.
309 - */
310 - var customifyFoldingFields = function() {
334 + $('.js-section-navigation a').on('click', function (e) {
335 + e.preventDefault()
311 336
312 - if ( typeof customify_settings === "undefined" || typeof customify_settings.settings === "undefined" ) {
313 - return ; // bail
314 - }
337 + const $this = $(this)
338 + const $sidebar = $this.parents('.wp-full-overlay-sidebar-content')
339 + const $parent = $this.parents('.accordion-section-content')
340 + const href = $this.attr('href')
315 341
316 - /**
317 - * Let's iterate through all the customify settings and gather all the fields that have a "show_on"
318 - * property set.
319 - *
320 - * At the end `targets` will hold a list of [ target : [field, field,...], ... ]
321 - * so when a target is changed we will change all the fields.
322 - */
323 - var targets = {};
342 + if (href !== '#') {
343 + const actionsHeight = $('#customize-header-actions').outerHeight()
344 + const titleHeight = $parent.find('.customize-section-title').outerHeight()
345 + const $target = $(href)
346 + const offset = $target.position().top
324 347
325 - $.fn.reactor.defaults.compliant = function() {
326 - $(this).slideDown();
327 - // $(this).animate({opacity: 1});
328 - $(this).find(':disabled').attr({disabled: false});
329 - };
348 + $sidebar.animate({scrollTop: offset - titleHeight - actionsHeight}, 500)
349 + }
350 + })
351 + }
330 352
331 - $.fn.reactor.defaults.uncompliant = function() {
332 - $(this).slideUp();
333 - // $(this).animate({opacity: 0.25});
334 - $(this).find(':enabled').attr({disabled: true});
335 - };
353 + const getConnectedFieldsCallback = function (parentSettingData, parentSettingID) {
354 + return function (newValue, oldValue) {
355 + _.each(parentSettingData.connected_fields, function (connectedFieldData) {
356 + if (_.isUndefined(connectedFieldData) || _.isUndefined(connectedFieldData.setting_id) || !_.isString(connectedFieldData.setting_id)) {
357 + return
358 + }
359 + const setting = api(connectedFieldData.setting_id)
360 + if (_.isUndefined(setting)) {
361 + return
362 + }
363 + setting.set(newValue)
364 + })
365 + }
366 + }
336 367
337 - var IS = $.extend({}, $.fn.reactor.helpers);
368 + const bindConnectedFields = function () {
369 + _.each(api.settings.settings, function (parentSettingData, parentSettingID) {
370 + // We don't want to handle the binding of the Style Manager settings
371 + if (typeof customify.colorPalettes !== 'undefined'
372 + && typeof customify.colorPalettes.masterSettingIds !== 'undefined'
373 + && _.includes(customify.colorPalettes.masterSettingIds, parentSettingID)) {
374 + return
375 + }
376 + if (typeof customify.fontPalettes !== 'undefined'
377 + && typeof customify.fontPalettes.masterSettingIds !== 'undefined'
378 + && _.includes(customify.fontPalettes.masterSettingIds, parentSettingID)) {
379 + return
380 + }
338 381
339 - var process_a_target = function( parent_id, field ) {
382 + const parent_setting = api(parentSettingID)
383 + if (typeof parentSettingData.connected_fields !== 'undefined') {
384 + customify.connectedFieldsCallbacks[parentSettingID] = getConnectedFieldsCallback(parentSettingData, parentSettingID)
385 + parent_setting.bind(customify.connectedFieldsCallbacks[parentSettingID])
386 + }
387 + })
388 + }
340 389
341 - if ( typeof field[0] === "undefined" ) {
342 - return ; // no id, no fun
343 - }
390 + /**
391 + * This function will search for all the interdependend fields and make a bound between them.
392 + * So whenever a target is changed, it will take actions to the dependent fields.
393 + * @TODO this is still written in a barbaric way, refactor when needed
394 + */
395 + const customifyFoldingFields = function () {
344 396
345 - var key = field[0],
346 - value = 1, // by default we use 1 the most used value for checboxes or inputs
347 - compare = '==', // ... ye
348 - action = "show"; // can only be `show` or `hide`
397 + if (_.isUndefined(customify.config) || _.isUndefined(customify.config.settings)) {
398 + return // bail
399 + }
349 400
350 - var target_key = customify_settings.options_name + '[' + key + ']';
351 - var target_type = customify_settings.settings[ target_key ].type;
401 + $.fn.reactor.defaults.compliant = function () {
402 + $(this).slideDown()
403 + $(this).find(':disabled').attr({disabled: false})
404 + }
352 405
406 + $.fn.reactor.defaults.uncompliant = function () {
407 + $(this).slideUp()
408 + $(this).find(':enabled').attr({disabled: true})
409 + }
353 410
354 - if ( typeof field[1] !== "undefined" ) {
355 - value = field[1];
356 - }
411 + let IS = $.extend({}, $.fn.reactor.helpers)
357 412
358 - if ( typeof field[2] !== "undefined" ) {
359 - compare = field[2];
360 - }
413 + const bindFoldingEvents = function (parentID, field, relation) {
361 414
362 - if ( typeof field[3] !== "undefined" ) {
363 - action = field[3];
364 - }
415 + let key = null
365 416
366 - /**
367 - * Now for each target we have, we will bind a change event to hide or show the dependent fields
368 - */
369 - var target_selector = '[data-customize-setting-link="' + customify_settings.options_name + '[' + key + ']"]';
417 + if (_.isString(field)) {
418 + key = field
419 + } else if (!_.isUndefined(field.id)) {
420 + key = field.id
421 + } else if (_.isString(field[0])) {
422 + key = field[0]
423 + } else {
424 + return // no key, no fun
425 + }
370 426
371 - if ( target_type == 'checkbox' ) {
372 - $(parent_id).reactIf( target_selector, function () {
373 - return $( this ).is(':checked') == value;
374 - } );
375 - } else if ( target_type == 'radio' || target_type == 'radio_image' ) {
376 - $(parent_id)
377 - .reactIf( target_selector, function () {
378 - return $( target_selector + ':checked').val() == value;
379 - } );
380 - } else {
381 - $(parent_id)
382 - .reactIf( target_selector, function () {
383 - return $(target_selector).val() == value;
384 - } );
385 - }
427 + let value = 1, // by default we use 1 the most used value for checkboxes or inputs
428 + between = [0, 1] // can only be `show` or `hide`
386 429
387 - $(target_selector).trigger('change');
388 - $('.reactor').trigger('change.reactor'); // triggers all events on load
389 - };
430 + const target_key = customify.config.options_name + '[' + key + ']'
431 + const target_type = customify.config.settings[target_key].type
390 432
391 - $.each( customify_settings.settings, function ( id, field ) {
433 + // we support the usual syntax like a config array like `array( 'id' => $id, 'value' => $value, 'compare' => $compare )`
434 + // but we also support a non-associative array like `array( $id, $value, $compare )`
435 + if (!_.isUndefined(field.value)) {
436 + value = field.value
437 + } else if (!_.isUndefined(field[1]) && !_.isString(field[1])) {
438 + value = field[1]
439 + }
392 440
393 - /**
394 - * Here we have the id of the fields. but we know for sure that we just need his parent selector
395 - * So we just create it
396 - */
397 - var parent_id = id.replace( '[', '-' );
398 - parent_id = parent_id.replace( ']', '' );
399 - parent_id = '#customize-control-' + parent_id + '_control';
441 + if (!_.isUndefined(field.between)) {
442 + between = field.between
443 + }
400 444
445 + /**
446 + * Now for each target we have, we will bind a change event to hide or show the dependent fields
447 + */
448 + const target_selector = '[data-customize-setting-link="' + customify.config.options_name + '[' + key + ']"]'
401 449
402 - // get only the fields that have a 'show_on' property
403 - if ( field.hasOwnProperty( 'show_on' ) && field.show_on.length > 0 ) {
450 + switch (target_type) {
451 + case 'checkbox':
452 + $(parentID).reactIf(target_selector, function () {
453 + return $(this).is(':checked') == value
454 + })
455 + break
404 456
405 - /**
406 - * The 'show_on' can be a simple array with one target like: [ id, value, comparison, action ]
407 - * Or it could be an array of multiple targets and we need to process both cases
408 - */
409 - if ( typeof field.show_on[0] === 'string' ) {
410 - process_a_target( parent_id, field.show_on );
411 - } else if ( typeof field.show_on[0] === 'object' ) {
412 - $.each( field.show_on, function (i, j) {
413 - process_a_target( parent_id, j );
414 - });
415 - }
416 - }
417 - });
418 - };
457 + case 'radio':
458 + case 'sm_radio':
459 + case 'sm_switch':
460 + case 'radio_image':
461 + case 'radio_html':
419 462
420 - var get_typography_font_family = function( $el ) {
463 + // in case of an array of values we use the ( val in array) condition
464 + if (_.isObject(value)) {
465 + value = _.toArray(value)
466 + $(parentID).reactIf(target_selector, function () {
467 + return (
468 + value.indexOf($(target_selector + ':checked').val()) !== -1
469 + )
470 + })
471 + } else { // in any other case we use a simple == comparison
472 + $(parentID).reactIf(target_selector, function () {
473 + return $(target_selector + ':checked').val() == value
474 + })
475 + }
476 + break
421 477
422 - var font_family_value = $el.val();
423 - // first time this will not be a json so catch that error
424 - try {
425 - font_family_value = JSON.parse( font_family_value );
426 - } catch ( e ) {
427 - return {font_family: font_family_value};
428 - }
478 + case 'range':
479 + const x = IS.Between(between[0], between[1])
429 480
430 - if ( typeof font_family_value.font_family !== 'undefined' ) {
431 - return font_family_value.font_family;
432 - }
481 + $(parentID).reactIf(target_selector, x)
482 + break
433 483
434 - return false;
435 - };
484 + default:
485 + // in case of an array of values we use the ( val in array) condition
486 + if (_.isObject(value)) {
487 + value = _.toArray(value)
488 + $(parentID).reactIf(target_selector, function () {
489 + return (
490 + value.indexOf($(target_selector).val()) !== -1
491 + )
492 + })
493 + } else { // in any other case we use a simple == comparison
494 + $(parentID).reactIf(target_selector, function () {
495 + return $(target_selector).val() == value
496 + })
497 + }
498 + break
499 + }
436 500
437 - // get each typography field and bind events
438 - var prepare_typography_field = function() {
501 + $(target_selector).trigger('change', ['customify'])
502 + $('.reactor').trigger('change.reactor') // triggers all events on load
503 + }
439 504
440 - var $typos = $( '.customify_typography_font_family' );
505 + $.each(customify.config.settings, function (id, field) {
506 + /**
507 + * Here we have the id of the fields. but we know for sure that we just need his parent selector
508 + * So we just create it
509 + */
510 + let parentID = id.replace('[', '-')
511 + parentID = parentID.replace(']', '')
512 + parentID = '#customize-control-' + parentID + '_control'
441 513
442 - $typos.each( function() {
443 - var font_family_select = this,
444 - $input = $( font_family_select ).siblings( '.customify_typography_values' );
445 - // on change
446 - $( font_family_select ).on( 'change', function() {
447 - update_siblings_selects( font_family_select );
448 - $input.trigger( 'change' );
449 - } );
450 - update_siblings_selects( font_family_select );
451 - } );
452 - };
514 + // get only the fields that have a 'show_if' property
515 + if (field.hasOwnProperty('show_if')) {
516 + let relation = 'AND'
453 517
454 - var api_set_setting_value = function( id, value ) {
518 + if (!_.isUndefined(field.show_if.relation)) {
519 + relation = field.show_if.relation
520 + // remove the relation property, we need the config to be array based only
521 + delete field.show_if.relation
522 + }
455 523
456 - var api = wp.customize,
457 - setting_id = customify_settings.options_name + '[' + id + ']',
458 - setting = api( setting_id ),
459 - field = $( '[data-customize-setting-link="' + setting_id + '"]' ),
460 - field_class = $( field ).parent().attr( 'class' );
524 + /**
525 + * The 'show_if' can be a simple array with one target like: [ id, value, comparison, action ]
526 + * Or it could be an array of multiple targets and we need to process both cases
527 + */
461 528
462 - if ( typeof field_class !== "undefined" && field_class === 'customify_typography' ) {
529 + if (!_.isUndefined(field.show_if.id)) {
530 + bindFoldingEvents(parentID, field.show_if, relation)
531 + } else if (_.isObject(field.show_if)) {
532 + $.each(field.show_if, function (i, j) {
533 + bindFoldingEvents(parentID, j, relation)
534 + })
535 + }
536 + }
537 + })
538 + }
463 539
464 - var family_select = field.siblings( 'select' );
540 + /**
541 + * Set a setting value.
542 + *
543 + * Mostly used for resetting settings (via the reset buttons) but also for the preset (legacy) field.
544 + *
545 + * @param settingID
546 + * @param value
547 + */
548 + const apiSetSettingValue = function (settingID, value) {
549 + const setting = api(settingID),
550 + field = $('[data-customize-setting-link="' + settingID + '"]'),
551 + fieldClass = $(field).parent().attr('class')
465 552
466 - if ( typeof value === 'string' ) {
467 - var this_option = family_select.find( 'option[value="' + value + '"]' );
468 - $( this_option[0] ).attr( 'selected', 'selected' );
469 - update_siblings_selects( family_select );
470 - } else if ( typeof value === 'object' ) {
471 - var this_family_option = family_select.find( 'option[value="' + value['font_family'] + '"]' );
472 - $( this_family_option[0] ).attr( 'selected', 'selected' );
553 + if (!_.isUndefined(fieldClass) && fieldClass === 'font-options__wrapper') {
473 554
474 - update_siblings_selects( this_family_option );
555 + // if the value is a simple string it must be the font family
556 + if (_.isString(value)) {
557 + setting.set({'font_family': value})
558 + } else if (_.isObject(value)) {
559 + const standardValue = {}
560 + // We will process each font property and update it
561 + _.each(value, function (val, key) {
562 + // We need to map the keys to the data attributes we are using - I know :(
563 + let mappedKey = key
564 + switch (key) {
565 + case 'font-family':
566 + mappedKey = 'font_family'
567 + break
568 + case 'font-size':
569 + mappedKey = 'font_size'
570 + break
571 + case 'font-weight':
572 + mappedKey = 'font_variant'
573 + break
574 + case 'letter-spacing':
575 + mappedKey = 'letter_spacing'
576 + break
577 + case 'text-transform':
578 + mappedKey = 'text_transform'
579 + break
580 + default:
581 + break
582 + }
475 583
476 - setTimeout( function() {
477 - var weight_select = field.parent().siblings( '.options' ).find( '.customify_typography_font_weight' );
584 + standardValue[mappedKey] = val
585 + })
478 586
479 - var this_weight_option = weight_select.find( 'option[value="' + value['selected_variants'] + '"]' );
587 + setting.set(standardValue)
588 + }
589 + } else {
590 + setting.set(value)
591 + }
592 + }
480 593
481 - $( this_weight_option[0] ).attr( 'selected', 'selected' );
594 + const handlePreviewIframe = function () {
595 + api.previewer.bind('synced', function () {
596 + scaleIframe()
482 597
483 - update_siblings_selects( this_family_option );
598 + api.previewedDevice.bind(scaleIframe)
599 + $window.on('resize', scaleIframe)
600 + })
484 601
485 - weight_select.trigger( 'change' );
486 - }, 300 );
487 - }
602 + $('.collapse-sidebar').on('click', function () {
603 + setTimeout(scaleIframe, 300)
604 + })
605 + }
488 606
489 - family_select.trigger( 'change' );
607 + const scaleIframe = function () {
608 + const $previewIframe = $('.wp-full-overlay')
490 609
491 - } else {
492 - setting.set( value );
493 - }
494 - };
610 + // remove CSS properties that may have been previously added
611 + $previewIframe.find('iframe').css({
612 + width: '',
613 + height: '',
614 + transformOrigin: '',
615 + transform: ''
616 + })
495 617
496 - var update_siblings_selects = function( font_select ) {
618 + // scaling of the site preview should be done only in desktop preview mode
619 + if (api.previewedDevice.get() !== 'desktop') {
620 + return
621 + }
497 622
498 - this.bound_once = false;
499 - var selected_font = $( font_select ).val(),
500 - $input = $( font_select ).siblings( '.customify_typography_values' ),
501 - current_val = $input.attr( 'value' );
623 + const iframeWidth = $previewIframe.width()
624 + const windowWidth = $window.width()
625 + const windowHeight = $window.height()
502 626
503 - if ( current_val === '[object Object]' ) {
504 - current_val = $input.data( 'default' );
505 - } else if ( typeof current_val === "string" && !IsJsonString( current_val ) ) {
506 - // a rare case when the value isn't a json but is a representative string like [family,weight]
507 - current_val = current_val.split( ',' );
508 - var new_current_value = {};
509 - if ( typeof current_val[0] !== "undefined" ) {
510 - new_current_value['font_family'] = current_val[0];
511 - }
627 + // get the ratio between the site preview and actual browser width
628 + const scale = windowWidth / iframeWidth
512 629
513 - if ( typeof current_val[1] !== "undefined" ) {
514 - new_current_value['selected_variants'] = current_val[1];
515 - }
630 + // for an accurate preview at resolutions where media queries may intervene
631 + // increase the width of the iframe and use CSS transforms to scale it back down
632 + if (iframeWidth > 720 && iframeWidth < 1100) {
633 + $previewIframe.find('iframe').css({
634 + width: iframeWidth * scale,
635 + height: windowHeight * scale,
636 + transformOrigin: 'left top',
637 + transform: 'scale(' + 1 / scale + ')'
638 + })
639 + }
640 + }
516 641
517 - current_val = JSON.stringify( new_current_value );
518 - }
642 + /** Modules **/
519 643
520 - var $font_weight = $( font_select ).parent().siblings( 'ul.options' ).find( '.customify_typography_font_weight' ),
521 - $font_subsets = $( font_select ).parent().siblings( 'ul.options' ).find( '.customify_typography_font_subsets' );
644 + const customifyBackgroundJsControl = (
645 + function () {
646 + 'use strict'
522 647
523 - try {
524 - current_val = JSON.parse( current_val );
525 - } catch ( e ) {
648 + function init () {
649 + // Upload media button
650 + $('.customize-control-custom_background .background_upload_button').unbind().on('click', function (event) {
651 + addImage(event, $(this).parents('.customize-control-custom_background:first'))
652 + })
526 653
527 - // in case of an error, force the rebuild of the json
528 - if ( typeof $( font_select ).data( 'bound_once' ) === "undefined" ) {
654 + // Remove the image button
655 + $('.customize-control-custom_background .remove-image, .customize-control-custom_background .remove-file').unbind('click').on('click', function (e) {
656 + removeImage($(this).parents('.customize-control-custom_background:first'))
657 + })
658 + }
529 659
530 - $( font_select ).data( 'bound_once', true );
531 - //var api = wp.customize;
532 - //api.previewer.refresh();
660 + // Add a file via the wp.media function
661 + function addImage (event, selector) {
662 + // Stop this from propagating.
663 + event.preventDefault()
533 664
534 - $( font_select ).change();
535 - $font_weight.change();
536 - $font_subsets.change();
537 - }
538 - }
539 - // first try to get the font from sure sources, not from the recommended list.
540 - var option_data = $( font_select ).find( ':not(optgroup[label=Recommended]) option[value="' + selected_font + '"]' );
541 - // howevah, if there isn't an option found, get what you can
542 - if ( option_data.length < 1 ) {
543 - option_data = $( font_select ).find( 'option[value="' + selected_font + '"]' );
544 - }
665 + let frame
666 + const $thisElement = $(this)
545 667
546 - if ( option_data.length > 0 ) {
668 + // If the media frame already exists, reopen it.
669 + if (frame) {
670 + frame.open()
671 + return
672 + }
547 673
548 - var font_type = option_data.data( 'type' ),
549 - value_to_add = {'type': font_type, 'font_family': selected_font},
550 - variants = null,
551 - subsets = null;
674 + // Create the media frame.
675 + frame = wp.media({
676 + multiple: false,
677 + library: {
678 + //type: 'image' //Only allow images
679 + },
680 + // Set the title of the modal.
681 + title: $thisElement.data('choose'),
552 682
553 - if ( font_type == 'std' ) {
554 - variants = { 0: '100', 1: '200', 3: '300', 4: '400', 5: '500', 6: '600', 7: '700', 8: '800', 9: '900' };
555 - if ( typeof $( option_data[0] ).data( 'variants' ) !== 'undefined' ) {
556 - variants = $( option_data[0] ).data( 'variants' );
557 - }
683 + // Customize the submit button.
684 + button: {
685 + // Set the text of the button.
686 + text: $thisElement.data('update')
687 + // Tell the button not to close the modal, since we're
688 + // going to refresh the page when the image is selected.
689 + }
690 + })
558 691
559 - } else {
560 - variants = $( option_data[0] ).data( 'variants' );
561 - subsets = $( option_data[0] ).data( 'subsets' );
562 - }
692 + // When an image is selected, run a callback.
693 + frame.on('select', function () {
694 + // Grab the selected attachment.
695 + const attachment = frame.state().get('selection').first()
696 + frame.close()
563 697
564 - // make the variants selector
565 - if ( typeof variants !== 'undefined' && variants !== null && variants !== '' ) {
698 + if (attachment.attributes.type !== 'image') {
699 + return
700 + }
566 701
567 - value_to_add['variants'] = variants;
568 - // when a font is selected force the first weight to load
569 - value_to_add['selected_variants'] = {0: variants[0]};
702 + selector.find('.customify_background_input.background-image').val(attachment.attributes.url)
570 703
571 - var variants_options = '',
572 - count_weights = 0;
704 + selector.find('.upload').attr('value', attachment.attributes.url)
705 + selector.find('.upload-id').attr('value', attachment.attributes.id)
706 + selector.find('.upload-height').attr('value', attachment.attributes.height)
707 + selector.find('.upload-width').attr('value', attachment.attributes.width)
573 708
574 - $.each( variants, function( key, el ) {
575 - var is_selected = '';
576 - if ( typeof current_val.selected_variants === "object" && inObject( el, current_val.selected_variants ) ) {
577 - is_selected = ' selected="selected"';
578 - } else if ( typeof current_val.selected_variants === "string" && el === current_val.selected_variants ) {
579 - is_selected = ' selected="selected"';
580 - }
709 + let thumbSrc = attachment.attributes.url
710 + if (!_.isUndefined(attachment.attributes.sizes) && !_.isUndefined(attachment.attributes.sizes.thumbnail)) {
711 + thumbSrc = attachment.attributes.sizes.thumbnail.url
712 + } else if (!_.isUndefined(attachment.attributes.sizes)) {
713 + let height = attachment.attributes.height
714 + for (let key in attachment.attributes.sizes) {
715 + const object = attachment.attributes.sizes[key]
716 + if (object.height < height) {
717 + height = object.height
718 + thumbSrc = object.url
719 + }
720 + }
721 + } else {
722 + thumbSrc = attachment.attributes.icon
723 + }
581 724
582 - variants_options += '<option value="' + el + '"' + is_selected + '>' + el + '</option>';
583 - count_weights++;
584 - } );
585 - if ( typeof $font_weight !== "undefined" ) {
586 - $font_weight.html( variants_options );
587 - // if there is no weight or just 1 we hide the weight select ... cuz is useless
588 - if ( $( font_select ).data( 'load_all_weights' ) === true || count_weights <= 1 ) {
589 - $font_weight.parent().css( 'display', 'none' );
590 - } else {
591 - $font_weight.parent().css( 'display', 'inline-block' );
592 - }
593 - }
594 - } else if ( typeof $font_weight !== "undefined" ) {
595 - $font_weight.parent().css( 'display', 'none' );
596 - }
725 + if (!selector.find('.upload').hasClass('noPreview')) {
726 + selector.find('.preview_screenshot').empty().hide().append('<img class="preview_image" src="' + thumbSrc + '">').slideDown('fast')
727 + }
728 + selector.find('.remove-image').removeClass('hide') // Show "Remove" button
729 + selector.find('.customify_background_select').removeClass('hide') // Show background selects
597 730
598 - // make the subsets selector
599 - if ( typeof subsets !== 'undefined' && subsets !== null && subsets !== '' ) {
731 + updateData(selector)
732 + })
600 733
601 - value_to_add['subsets'] = subsets;
602 - // when a font is selected force the first subset to load
603 - value_to_add['selected_subsets'] = {0: subsets[0]};
604 - var subsets_options = '',
605 - count_subsets = 0;
606 - $.each( subsets, function( key, el ) {
607 - var is_selected = '';
608 - if ( typeof current_val.selected_subsets === "object" && inObject( el, current_val.selected_subsets ) ) {
609 - is_selected = ' selected="selected"';
610 - }
734 + // Finally, open the modal.
735 + frame.open()
736 + }
611 737
612 - subsets_options += '<option value="' + el + '"' + is_selected + '>' + el + '</option>';
613 - count_subsets++;
614 - } );
738 + // Update the background data
739 + function updateData (selector) {
615 740
616 - if ( typeof $font_subsets !== "undefined" ) {
617 - $font_subsets.html( subsets_options );
741 + let $parent = selector.parents('.customize-control-custom_background:first')
618 742
619 - // if there is no subset or just 1 we hide the subsets select ... cuz is useless
620 - if ( count_subsets <= 1 ) {
621 - $font_subsets.parent().css( 'display', 'none' );
622 - } else {
623 - $font_subsets.parent().css( 'display', 'inline-block' );
624 - }
625 - }
626 - } else if ( typeof $font_subsets !== "undefined" ) {
627 - $font_subsets.parent().css( 'display', 'none' );
628 - }
743 + if (selector.hasClass('customize-control-custom_background')) {
744 + $parent = selector
745 + }
629 746
630 - $input.val( JSON.stringify( value_to_add ) );
631 - }
632 - };
747 + if ($parent.length > 0) {
748 + $parent = $($parent[0])
749 + } else {
750 + return
751 + }
633 752
634 - /**
635 - * Function to check if a value exists in an object
636 - * @param value
637 - * @param obj
638 - * @returns {boolean}
639 - */
640 - var inObject = function( value, obj ) {
641 - for ( var k in obj ) {
642 - if ( !obj.hasOwnProperty( k ) ) continue;
643 - if ( obj[k] === value ) {
644 - return true;
645 - }
646 - }
647 - return false;
648 - };
753 + const settingID = $parent.find('.button.background_upload_button').data('setting_id'),
754 + setting = api.instance(settingID)
649 755
650 - var customifyBackgroundJsControl = (function() {
651 - "use strict";
756 + const background_data = {}
652 757
653 - var api = wp.customize;
758 + $parent.find('.customify_background_select, .customify_background_input').each(function () {
759 + let data = $(this).serializeArray()[0]
760 + if (data && data.name.indexOf('[background-') !== -1) {
761 + background_data[$(this).data('select_name')] = data.value
762 + }
763 + })
654 764
655 - function init() {
656 - // Remove the image button
657 - $( '.customize-control-custom_background .remove-image, .customize-control-custom_background .remove-file' ).unbind( 'click' ).on( 'click', function( e ) {
658 - removeImage( $( this ).parents( '.customize-control-custom_background:first' ) );
659 - preview( $( this ) );
660 - return false;
661 - } );
765 + background_data.media = {}
766 + background_data.media.id = $parent.find('.upload-id').val()
767 + background_data.media.height = $parent.find('.upload-height').val()
768 + background_data.media.width = $parent.find('.upload-width').val()
769 + background_data.media.thumbnail = $parent.find('.upload-thumbnail').val()
662 770
663 - // Upload media button
664 - $( '.customize-control-custom_background .background_upload_button' ).unbind().on( 'click', function( event ) {
665 - addImage( event, $( this ).parents( '.customize-control-custom_background:first' ) );
666 - } );
771 + setting.set(background_data)
772 + }
667 773
668 - $( '.customify_background_select' ).on( 'change', function() {
669 - preview( $( this ) );
670 - } );
671 - }
774 + // Update the background preview
775 + function removeImage (parent) {
776 + const selector = parent.find('.upload_button_div')
777 + // This shouldn't have been run...
778 + if (!selector.find('.remove-image').addClass('hide')) {
779 + return
780 + }
672 781
673 - // Add a file via the wp.media function
674 - function addImage( event, selector ) {
782 + // Hide "Remove" button.
783 + selector.find('.remove-image').addClass('hide')
784 + parent.find('.customify_background_select').addClass('hide')
675 785
676 - event.preventDefault();
786 + parent.find('.upload').val(null)
787 + parent.find('.upload-id').val(null)
788 + parent.find('.upload-height').val(null)
789 + parent.find('.upload-width').val(null)
790 + parent.find('.customify_background_input.background-image').val(null)
677 791
678 - var frame;
679 - var jQueryel = jQuery( this );
792 + // Hide the screenshot
793 + parent.find('.preview_screenshot').slideUp()
680 794
681 - // If the media frame already exists, reopen it.
682 - if ( frame ) {
683 - frame.open();
684 - return;
685 - }
795 + updateData(parent)
796 + }
686 797
687 - // Create the media frame.
688 - frame = wp.media( {
689 - multiple: false,
690 - library: {
691 - //type: 'image' //Only allow images
692 - },
693 - // Set the title of the modal.
694 - title: jQueryel.data( 'choose' ),
798 + return {
799 + init: init
800 + }
801 + }
802 + )(jQuery)
695 803
696 - // Customize the submit button.
697 - button: {
698 - // Set the text of the button.
699 - text: jQueryel.data( 'update' )
700 - // Tell the button not to close the modal, since we're
701 - // going to refresh the page when the image is selected.
702 - }
703 - } );
804 + /** HELPERS **/
704 805
705 - // When an image is selected, run a callback.
706 - frame.on( 'select', function() {
707 - // Grab the selected attachment.
708 - var attachment = frame.state().get( 'selection' ).first();
709 - frame.close();
806 + const getUrlVar = function (name) {
807 + const vars = []
808 + let hash
809 + const hashes = window.location.href.slice(window.location.href.indexOf('?') + 1).split('&')
710 810
711 - if ( attachment.attributes.type !== "image" ) {
712 - return;
713 - }
811 + for (let i = 0; i < hashes.length; i++) {
812 + hash = hashes[i].split('=')
714 813
715 - selector.find( '.upload' ).attr( 'value', attachment.attributes.url );
716 - selector.find( '.upload-id' ).attr( 'value', attachment.attributes.id );
717 - selector.find( '.upload-height' ).attr( 'value', attachment.attributes.height );
718 - selector.find( '.upload-width' ).attr( 'value', attachment.attributes.width );
814 + vars.push(hash[0])
815 + vars[hash[0]] = hash[1]
816 + }
719 817
720 - var thumbSrc = attachment.attributes.url;
721 - if ( typeof attachment.attributes.sizes !== 'undefined' && typeof attachment.attributes.sizes.thumbnail !== 'undefined' ) {
722 - thumbSrc = attachment.attributes.sizes.thumbnail.url;
723 - } else if ( typeof attachment.attributes.sizes !== 'undefined' ) {
724 - var height = attachment.attributes.height;
725 - for ( var key in attachment.attributes.sizes ) {
726 - var object = attachment.attributes.sizes[key];
727 - if ( object.height < height ) {
728 - height = object.height;
729 - thumbSrc = object.url;
730 - }
731 - }
732 - } else {
733 - thumbSrc = attachment.attributes.icon;
734 - }
735 -
736 - selector.find( '.customify_background_input.background-image' ).val( attachment.attributes.url );
737 -
738 - if ( !selector.find( '.upload' ).hasClass( 'noPreview' ) ) {
739 - selector.find( '.preview_screenshot' ).empty().hide().append( '<img class="preview_image" src="' + thumbSrc + '">' ).slideDown( 'fast' );
740 - }
741 - //selector.find('.media_upload_button').unbind();
742 - selector.find( '.remove-image' ).removeClass( 'hide' );//show "Remove" button
743 - selector.find( '.customify_background_select' ).removeClass( 'hide' );//show "Remove" button
744 -
745 - preview( selector );
746 - } );
747 -
748 - // Finally, open the modal.
749 - frame.open();
750 - }
751 -
752 - // Update the background preview
753 - function preview( selector ) {
754 -
755 - var $parent = selector.parents( '.customize-control-custom_background:first' );
756 -
757 - if ( selector.hasClass( 'customize-control-custom_background' ) ) {
758 - var $parent = selector;
759 - }
760 -
761 - if ( $parent.length > 0 ) {
762 - $parent = $( $parent[0] );
763 - } else {
764 - return;
765 - }
766 -
767 - var image_holder = $parent.find( '.background-preview' );
768 -
769 - if ( !image_holder ) { // No preview present
770 - return;
771 - }
772 -
773 - var the_id = $parent.find( '.button.background_upload_button' ).data( 'setting_id' ),
774 - this_setting = api.instance( the_id );
775 -
776 - var background_data = {};
777 -
778 - $parent.find( '.customify_background_select, .customify_background_input' ).each( function() {
779 - var data = $( this ).serializeArray();
780 -
781 - data = data[0];
782 - if ( data && data.name.indexOf( '[background-' ) != -1 ) {
783 -
784 - background_data[$( this ).data( 'select_name' )] = data.value;
785 -
786 - //default_default[data.name] = data.value;
787 - //if (data.name == "background-image") {
788 - // css += data.name + ':url("' + data.value + '");';
789 - //} else {
790 - // css += data.name + ':' + data.value + ';';
791 - //}
792 - }
793 - } );
794 -
795 - api.instance( the_id ).set( background_data );
796 - //// Notify the customizer api about this change
797 - api.trigger( 'change' );
798 - api.previewer.refresh();
799 -
800 - //image_holder.attr('style', css).fadeIn();
801 - }
802 -
803 - // Update the background preview
804 - function removeImage( parent ) {
805 - var selector = parent.find( '.upload_button_div' );
806 - // This shouldn't have been run...
807 - if ( !selector.find( '.remove-image' ).addClass( 'hide' ) ) {
808 - return;
809 - }
810 -
811 - selector.find( '.remove-image' ).addClass( 'hide' );//hide "Remove" button
812 - parent.find( '.customify_background_select' ).addClass( 'hide' );
813 -
814 - selector.find( '.upload' ).val( '' );
815 - selector.find( '.upload-id' ).val( '' );
816 - selector.find( '.upload-height' ).val( '' );
817 - selector.find( '.upload-width' ).val( '' );
818 - parent.find( '.customify_background_input.background-image' ).val( '' );
819 -
820 - var customizer_id = selector.find( '.background_upload_button' ).data( 'setting_id' ),
821 - this_setting = api.control( customizer_id + '_control' ),
822 - current_vals = this_setting.setting(),
823 - screenshot = parent.find( '.preview_screenshot' ),
824 - to_array = $.map( current_vals, function( value, index ) {
825 - return [value];
826 - } );
827 -
828 - // Hide the screenshot
829 - screenshot.slideUp();
830 - selector.find( '.remove-file' ).unbind();
831 - to_array['background-image'] = '';
832 - this_setting.setting( to_array );
833 - }
834 -
835 - return {
836 - init: init
837 - }
838 - })( jQuery );
839 -
840 - var getUrlVars = function( name ) {
841 - var vars = [], hash;
842 - var hashes = window.location.href.slice( window.location.href.indexOf( '?' ) + 1 ).split( '&' );
843 - for ( var i = 0; i < hashes.length; i++ ) {
844 - hash = hashes[i].split( '=' );
845 -
846 - vars.push( hash[0] );
847 - vars[hash[0]] = hash[1];
848 - }
849 -
850 - if ( typeof vars[name] !== "undefined" ) {
851 - return vars[name];
852 - }
853 - return false;
854 - };
855 -
856 - var IsJsonString = function( str ) {
857 - try {
858 - JSON.parse( str );
859 - } catch ( e ) {
860 - return false;
861 - }
862 - return true;
863 - };
864 - } );
865 -
866 - var Queue = function() {
867 - var lastPromise = null;
868 - var queueDeferred = null;
869 - var methodDeferred = null;
870 -
871 - this.add_steps = function( key, steps, args ) {
872 - var self = this;
873 - this.methodDeferred = $.Deferred();
874 - this.queueDeferred = this.setup();
875 -
876 - $.each( steps, function( i, step ) {
877 - self.queue( key, step );
878 - } );
879 - };
880 -
881 - this.process_remote_step = function( key, data, step ) {
882 - var self = this;
883 -
884 - if ( typeof data === "undefined" || data === null ) {
885 - return false;
886 - }
887 -
888 - var new_step = step;
889 - $.each( data, function( i, k ) {
890 -debugger;
891 - // prepare data for new requests
892 - new_step.recall_data = k.data;
893 - new_step.recall_type = k.type;
894 - new_step.type = 'recall';
895 -
896 - self.queue( key, new_step, k.id );
897 - } );
898 - };
899 -
900 - this.log_action = function( action, key, msg ) {
901 - if ( action === 'start' ) {
902 - $('.wpGrade-import-results' ).show();
903 - $('.wpGrade-import-results' ).append( '<span class="import_step_note imports_step_' + key + '" ><span class="step_info" data-balloon="Working on it" data-balloon-pos="up"></span>Importing ' + key + '</span>' );
904 - } else if ( action === 'end' ) {
905 - var $notice = $('.imports_step_' + key + ' .step_info');
906 -
907 - if ( $notice.length > 0 || msg !== "undefined") {
908 - $notice.attr('data-balloon', msg);
909 - $notice.addClass('success');
910 - } else {
911 - $notice.attr('data-balloon', 'Done');
912 - $notice.addClass('failed');
913 - }
914 - }
915 - };
916 -
917 - this.queue = function( key, data, step_key ) {
918 - var self = this;
919 - if ( typeof step_key !== 'undefined' ) {
920 - this.log_action( 'start', step_key );
921 - }
922 -
923 - // execute next queue method
924 - this.queueDeferred.done( this.request( key, data, step_key ) );
925 - lastPromise = self.methodDeferred.promise();
926 - };
927 -
928 - this.request = function( key, step, step_key ) {
929 - var self = this;
930 - // call actual method and wrap output in deferred
931 - //setTimeout( function() {
932 - var data_args = {
933 - action: 'customify_import_step',
934 - step_id: step.id,
935 - step_type: step.type,
936 - option_key: key
937 - };
938 -
939 - if ( typeof step.recall_data !== "undefined" ) {
940 - data_args.recall_data = step.recall_data;
941 - }
942 -
943 - if ( typeof step.recall_type !== "undefined" ) {
944 - data_args.recall_type = step.recall_type;
945 - }
946 -
947 - $.ajax( {
948 - url: customify_settings.import_rest_url + 'customify/1.0/import',
949 - method: 'POST',
950 - beforeSend: function( xhr ) {
951 - xhr.setRequestHeader( 'X-WP-Nonce', WP_API_Settings.nonce );
952 - },
953 - dataType: 'json',
954 - contentType: 'application/x-www-form-urlencoded; charset=UTF-8',
955 - data: data_args
956 - } ).done( function( response ) {
957 - if ( typeof response.success !== "undefined" && response.success ) {
958 - var results = response.data;
959 - if ( step.type === 'remote' ) {
960 - self.process_remote_step( key, results, step );
961 - }
962 - }
963 -
964 - if ( typeof step_key !== 'undefined' && typeof response.message !== 'undefined' ) {
965 - self.log_action( 'end', step_key, response.message );
966 - }
967 - } );
968 -
969 - self.methodDeferred.resolve();
970 - //}, 3450 );
971 - };
972 -
973 - this.setup = function() {
974 - var self = this;
975 -
976 - self.queueDeferred = $.Deferred();
977 -
978 - // when the previous method returns, resolve this one
979 - $.when( lastPromise ).always( function() {
980 - self.queueDeferred.resolve();
981 - } );
982 -
983 - return self.queueDeferred.promise();
984 - }
985 - };
986 -
987 -})( jQuery, window );
818 + if (!_.isUndefined(vars[name])) {
819 + return vars[name]
820 + }
821 + return false
822 + }
823 +})(jQuery, customify, wp)