~canonical-sysadmins/wordpress/4.8.3

« back to all changes in this revision

Viewing changes to wp-includes/js/customize-preview-nav-menus.js

  • Committer: Ryan Finnie
  • Date: 2015-08-31 16:09:47 UTC
  • mfrom: (1.1.9 upstream)
  • Revision ID: ryan.finnie@canonical.com-20150831160947-1h6rfxby9z1ec62u
Merge WP4.3 from upstream

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* global JSON, _wpCustomizePreviewNavMenusExports */
 
2
 
 
3
( function( $, _, wp ) {
 
4
        'use strict';
 
5
 
 
6
        if ( ! wp || ! wp.customize ) { return; }
 
7
 
 
8
        var api = wp.customize,
 
9
                currentRefreshDebounced = {},
 
10
                refreshDebounceDelay = 200,
 
11
                settings = {},
 
12
                defaultSettings = {
 
13
                        renderQueryVar: null,
 
14
                        renderNonceValue: null,
 
15
                        renderNoncePostKey: null,
 
16
                        previewCustomizeNonce: null,
 
17
                        requestUri: '/',
 
18
                        theme: {
 
19
                                active: false,
 
20
                                stylesheet: ''
 
21
                        },
 
22
                        navMenuInstanceArgs: {}
 
23
                };
 
24
 
 
25
        api.MenusCustomizerPreview = {
 
26
                /**
 
27
                 * Bootstrap functionality.
 
28
                 */
 
29
                init : function() {
 
30
                        var self = this, initializedSettings = {};
 
31
 
 
32
                        settings = _.extend( {}, defaultSettings );
 
33
                        if ( 'undefined' !== typeof _wpCustomizePreviewNavMenusExports ) {
 
34
                                _.extend( settings, _wpCustomizePreviewNavMenusExports );
 
35
                        }
 
36
 
 
37
                        api.each( function( setting, id ) {
 
38
                                setting.id = id;
 
39
                                initializedSettings[ setting.id ] = true;
 
40
                                self.bindListener( setting );
 
41
                        } );
 
42
 
 
43
                        api.preview.bind( 'setting', function( args ) {
 
44
                                var id, value, setting;
 
45
                                args = args.slice();
 
46
                                id = args.shift();
 
47
                                value = args.shift();
 
48
 
 
49
                                setting = api( id );
 
50
                                if ( ! setting ) {
 
51
                                        // Currently customize-preview.js is not creating settings for dynamically-created settings in the pane, so we have to do it.
 
52
                                        setting = api.create( id, value ); // @todo This should be in core
 
53
                                }
 
54
                                if ( ! setting.id ) {
 
55
                                        // Currently customize-preview.js doesn't set the id property for each setting, like customize-controls.js does.
 
56
                                        setting.id = id;
 
57
                                }
 
58
 
 
59
                                if ( ! initializedSettings[ setting.id ] ) {
 
60
                                        initializedSettings[ setting.id ] = true;
 
61
                                        if ( self.bindListener( setting ) ) {
 
62
                                                setting.callbacks.fireWith( setting, [ setting(), null ] );
 
63
                                        }
 
64
                                }
 
65
                        } );
 
66
                },
 
67
 
 
68
                /**
 
69
                 *
 
70
                 * @param {wp.customize.Value} setting
 
71
                 * @returns {boolean} Whether the setting was bound.
 
72
                 */
 
73
                bindListener : function( setting ) {
 
74
                        var matches, themeLocation;
 
75
 
 
76
                        matches = setting.id.match( /^nav_menu\[(-?\d+)]$/ );
 
77
                        if ( matches ) {
 
78
                                setting.navMenuId = parseInt( matches[1], 10 );
 
79
                                setting.bind( this.onChangeNavMenuSetting );
 
80
                                return true;
 
81
                        }
 
82
 
 
83
                        matches = setting.id.match( /^nav_menu_item\[(-?\d+)]$/ );
 
84
                        if ( matches ) {
 
85
                                setting.navMenuItemId = parseInt( matches[1], 10 );
 
86
                                setting.bind( this.onChangeNavMenuItemSetting );
 
87
                                return true;
 
88
                        }
 
89
 
 
90
                        matches = setting.id.match( /^nav_menu_locations\[(.+?)]/ );
 
91
                        if ( matches ) {
 
92
                                themeLocation = matches[1];
 
93
                                setting.bind( _.bind( function() {
 
94
                                        this.refreshMenuLocation( themeLocation );
 
95
                                }, this ) );
 
96
                                return true;
 
97
                        }
 
98
 
 
99
                        return false;
 
100
                },
 
101
 
 
102
                /**
 
103
                 * Handle changing of a nav_menu setting.
 
104
                 *
 
105
                 * @this {wp.customize.Setting}
 
106
                 */
 
107
                onChangeNavMenuSetting : function() {
 
108
                        var setting = this;
 
109
                        if ( ! setting.navMenuId ) {
 
110
                                throw new Error( 'Expected navMenuId property to be set.' );
 
111
                        }
 
112
                        api.MenusCustomizerPreview.refreshMenu( setting.navMenuId );
 
113
                },
 
114
 
 
115
                /**
 
116
                 * Handle changing of a nav_menu_item setting.
 
117
                 *
 
118
                 * @this {wp.customize.Setting}
 
119
                 * @param {object} to
 
120
                 * @param {object} from
 
121
                 */
 
122
                onChangeNavMenuItemSetting : function( to, from ) {
 
123
                        if ( from && from.nav_menu_term_id && ( ! to || from.nav_menu_term_id !== to.nav_menu_term_id ) ) {
 
124
                                api.MenusCustomizerPreview.refreshMenu( from.nav_menu_term_id );
 
125
                        }
 
126
                        if ( to && to.nav_menu_term_id ) {
 
127
                                api.MenusCustomizerPreview.refreshMenu( to.nav_menu_term_id );
 
128
                        }
 
129
                },
 
130
 
 
131
                /**
 
132
                 * Update a given menu rendered in the preview.
 
133
                 *
 
134
                 * @param {int} menuId
 
135
                 */
 
136
                refreshMenu : function( menuId ) {
 
137
                        var assignedLocations = [];
 
138
 
 
139
                        api.each(function( setting, id ) {
 
140
                                var matches = id.match( /^nav_menu_locations\[(.+?)]/ );
 
141
                                if ( matches && menuId === setting() ) {
 
142
                                        assignedLocations.push( matches[1] );
 
143
                                }
 
144
                        });
 
145
 
 
146
                        _.each( settings.navMenuInstanceArgs, function( navMenuArgs, instanceNumber ) {
 
147
                                if ( menuId === navMenuArgs.menu || -1 !== _.indexOf( assignedLocations, navMenuArgs.theme_location ) ) {
 
148
                                        this.refreshMenuInstanceDebounced( instanceNumber );
 
149
                                }
 
150
                        }, this );
 
151
                },
 
152
 
 
153
                /**
 
154
                 * Refresh the menu(s) associated with a given nav menu location.
 
155
                 *
 
156
                 * @param {string} location
 
157
                 */
 
158
                refreshMenuLocation : function( location ) {
 
159
                        var foundInstance = false;
 
160
                        _.each( settings.navMenuInstanceArgs, function( navMenuArgs, instanceNumber ) {
 
161
                                if ( location === navMenuArgs.theme_location ) {
 
162
                                        this.refreshMenuInstanceDebounced( instanceNumber );
 
163
                                        foundInstance = true;
 
164
                                }
 
165
                        }, this );
 
166
                        if ( ! foundInstance ) {
 
167
                                api.preview.send( 'refresh' );
 
168
                        }
 
169
                },
 
170
 
 
171
                /**
 
172
                 * Update a specific instance of a given menu on the page.
 
173
                 *
 
174
                 * @param {int} instanceNumber
 
175
                 */
 
176
                refreshMenuInstance : function( instanceNumber ) {
 
177
                        var data, menuId, customized, container, request, wpNavMenuArgs, instance, containerInstanceClassName;
 
178
 
 
179
                        if ( ! settings.navMenuInstanceArgs[ instanceNumber ] ) {
 
180
                                throw new Error( 'unknown_instance_number' );
 
181
                        }
 
182
                        instance = settings.navMenuInstanceArgs[ instanceNumber ];
 
183
 
 
184
                        containerInstanceClassName = 'partial-refreshable-nav-menu-' + String( instanceNumber );
 
185
                        container = $( '.' + containerInstanceClassName );
 
186
 
 
187
                        if ( _.isNumber( instance.menu ) ) {
 
188
                                menuId = instance.menu;
 
189
                        } else if ( instance.theme_location && api.has( 'nav_menu_locations[' + instance.theme_location + ']' ) ) {
 
190
                                menuId = api( 'nav_menu_locations[' + instance.theme_location + ']' ).get();
 
191
                        }
 
192
 
 
193
                        if ( ! menuId || ! instance.can_partial_refresh || 0 === container.length ) {
 
194
                                api.preview.send( 'refresh' );
 
195
                                return;
 
196
                        }
 
197
                        menuId = parseInt( menuId, 10 );
 
198
 
 
199
                        data = {
 
200
                                nonce: settings.previewCustomizeNonce, // for Customize Preview
 
201
                                wp_customize: 'on'
 
202
                        };
 
203
                        if ( ! settings.theme.active ) {
 
204
                                data.theme = settings.theme.stylesheet;
 
205
                        }
 
206
                        data[ settings.renderQueryVar ] = '1';
 
207
 
 
208
                        // Gather settings to send in partial refresh request.
 
209
                        customized = {};
 
210
                        api.each( function( setting, id ) {
 
211
                                var value = setting.get(), shouldSend = false;
 
212
                                // @todo Core should propagate the dirty state into the Preview as well so we can use that here.
 
213
 
 
214
                                // Send setting if it is a nav_menu_locations[] setting.
 
215
                                shouldSend = shouldSend || /^nav_menu_locations\[/.test( id );
 
216
 
 
217
                                // Send setting if it is the setting for this menu.
 
218
                                shouldSend = shouldSend || id === 'nav_menu[' + String( menuId ) + ']';
 
219
 
 
220
                                // Send setting if it is one that is associated with this menu, or it is deleted.
 
221
                                shouldSend = shouldSend || ( /^nav_menu_item\[/.test( id ) && ( false === value || menuId === value.nav_menu_term_id ) );
 
222
 
 
223
                                if ( shouldSend ) {
 
224
                                        customized[ id ] = value;
 
225
                                }
 
226
                        } );
 
227
                        data.customized = JSON.stringify( customized );
 
228
                        data[ settings.renderNoncePostKey ] = settings.renderNonceValue;
 
229
 
 
230
                        wpNavMenuArgs = $.extend( {}, instance );
 
231
                        data.wp_nav_menu_args_hash = wpNavMenuArgs.args_hash;
 
232
                        delete wpNavMenuArgs.args_hash;
 
233
                        data.wp_nav_menu_args = JSON.stringify( wpNavMenuArgs );
 
234
 
 
235
                        container.addClass( 'customize-partial-refreshing' );
 
236
 
 
237
                        request = wp.ajax.send( null, {
 
238
                                data: data,
 
239
                                url: settings.requestUri
 
240
                        } );
 
241
                        request.done( function( data ) {
 
242
                                // If the menu is now not visible, refresh since the page layout may have changed.
 
243
                                if ( false === data ) {
 
244
                                        api.preview.send( 'refresh' );
 
245
                                        return;
 
246
                                }
 
247
 
 
248
                                var eventParam, previousContainer = container;
 
249
                                container = $( data );
 
250
                                container.addClass( containerInstanceClassName );
 
251
                                container.addClass( 'partial-refreshable-nav-menu customize-partial-refreshing' );
 
252
                                previousContainer.replaceWith( container );
 
253
                                eventParam = {
 
254
                                        instanceNumber: instanceNumber,
 
255
                                        wpNavArgs: wpNavMenuArgs, // @deprecated
 
256
                                        wpNavMenuArgs: wpNavMenuArgs,
 
257
                                        oldContainer: previousContainer,
 
258
                                        newContainer: container
 
259
                                };
 
260
                                container.removeClass( 'customize-partial-refreshing' );
 
261
                                $( document ).trigger( 'customize-preview-menu-refreshed', [ eventParam ] );
 
262
                        } );
 
263
                },
 
264
 
 
265
                refreshMenuInstanceDebounced : function( instanceNumber ) {
 
266
                        if ( currentRefreshDebounced[ instanceNumber ] ) {
 
267
                                clearTimeout( currentRefreshDebounced[ instanceNumber ] );
 
268
                        }
 
269
                        currentRefreshDebounced[ instanceNumber ] = setTimeout(
 
270
                                _.bind( function() {
 
271
                                        this.refreshMenuInstance( instanceNumber );
 
272
                                }, this ),
 
273
                                refreshDebounceDelay
 
274
                        );
 
275
                }
 
276
        };
 
277
 
 
278
        api.bind( 'preview-ready', function() {
 
279
                api.preview.bind( 'active', function() {
 
280
                        api.MenusCustomizerPreview.init();
 
281
                } );
 
282
        } );
 
283
 
 
284
}( jQuery, _, wp ) );