| | |
| | |
| | |
| |
|
| | |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | wp.customize.widgetsPreview = wp.customize.WidgetCustomizerPreview = (function( $, _, wp, api ) { |
| |
|
| | var self; |
| |
|
| | self = { |
| | renderedSidebars: {}, |
| | renderedWidgets: {}, |
| | registeredSidebars: [], |
| | registeredWidgets: {}, |
| | widgetSelectors: [], |
| | preview: null, |
| | l10n: { |
| | widgetTooltip: '' |
| | }, |
| | selectiveRefreshableWidgets: {} |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.init = function() { |
| | var self = this; |
| |
|
| | self.preview = api.preview; |
| | if ( ! _.isEmpty( self.selectiveRefreshableWidgets ) ) { |
| | self.addPartials(); |
| | } |
| |
|
| | self.buildWidgetSelectors(); |
| | self.highlightControls(); |
| |
|
| | self.preview.bind( 'highlight-widget', self.highlightWidget ); |
| |
|
| | api.preview.bind( 'active', function() { |
| | self.highlightControls(); |
| | } ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | api.preview.bind( 'refresh-widget-partial', function( widgetId ) { |
| | var partialId = 'widget[' + widgetId + ']'; |
| | if ( api.selectiveRefresh.partial.has( partialId ) ) { |
| | api.selectiveRefresh.partial( partialId ).refresh(); |
| | } else if ( self.renderedWidgets[ widgetId ] ) { |
| | api.preview.send( 'refresh' ); |
| | } |
| | } ); |
| | }; |
| |
|
| | self.WidgetPartial = api.selectiveRefresh.Partial.extend({ |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | initialize: function( id, options ) { |
| | var partial = this, matches; |
| | matches = id.match( /^widget\[(.+)]$/ ); |
| | if ( ! matches ) { |
| | throw new Error( 'Illegal id for widget partial.' ); |
| | } |
| |
|
| | partial.widgetId = matches[1]; |
| | partial.widgetIdParts = self.parseWidgetId( partial.widgetId ); |
| | options = options || {}; |
| | options.params = _.extend( |
| | { |
| | settings: [ self.getWidgetSettingId( partial.widgetId ) ], |
| | containerInclusive: true |
| | }, |
| | options.params || {} |
| | ); |
| |
|
| | api.selectiveRefresh.Partial.prototype.initialize.call( partial, id, options ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | refresh: function() { |
| | var partial = this, refreshDeferred; |
| | if ( ! self.selectiveRefreshableWidgets[ partial.widgetIdParts.idBase ] ) { |
| | refreshDeferred = $.Deferred(); |
| | refreshDeferred.reject(); |
| | partial.fallback(); |
| | return refreshDeferred.promise(); |
| | } else { |
| | return api.selectiveRefresh.Partial.prototype.refresh.call( partial ); |
| | } |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | renderContent: function( placement ) { |
| | var partial = this; |
| | if ( api.selectiveRefresh.Partial.prototype.renderContent.call( partial, placement ) ) { |
| | api.preview.send( 'widget-updated', partial.widgetId ); |
| | api.selectiveRefresh.trigger( 'widget-updated', partial ); |
| | } |
| | } |
| | }); |
| |
|
| | self.SidebarPartial = api.selectiveRefresh.Partial.extend({ |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | initialize: function( id, options ) { |
| | var partial = this, matches; |
| | matches = id.match( /^sidebar\[(.+)]$/ ); |
| | if ( ! matches ) { |
| | throw new Error( 'Illegal id for sidebar partial.' ); |
| | } |
| | partial.sidebarId = matches[1]; |
| |
|
| | options = options || {}; |
| | options.params = _.extend( |
| | { |
| | settings: [ 'sidebars_widgets[' + partial.sidebarId + ']' ] |
| | }, |
| | options.params || {} |
| | ); |
| |
|
| | api.selectiveRefresh.Partial.prototype.initialize.call( partial, id, options ); |
| |
|
| | if ( ! partial.params.sidebarArgs ) { |
| | throw new Error( 'The sidebarArgs param was not provided.' ); |
| | } |
| | if ( partial.params.settings.length > 1 ) { |
| | throw new Error( 'Expected SidebarPartial to only have one associated setting' ); |
| | } |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ready: function() { |
| | var sidebarPartial = this; |
| |
|
| | |
| | _.each( sidebarPartial.settings(), function( settingId ) { |
| | api( settingId ).bind( _.bind( sidebarPartial.handleSettingChange, sidebarPartial ) ); |
| | } ); |
| |
|
| | |
| | api.selectiveRefresh.bind( 'partial-content-rendered', function( placement ) { |
| | var isAssignedWidgetPartial = ( |
| | placement.partial.extended( self.WidgetPartial ) && |
| | ( -1 !== _.indexOf( sidebarPartial.getWidgetIds(), placement.partial.widgetId ) ) |
| | ); |
| | if ( isAssignedWidgetPartial ) { |
| | api.selectiveRefresh.trigger( 'sidebar-updated', sidebarPartial ); |
| | } |
| | } ); |
| |
|
| | |
| | api.bind( 'change', function( widgetSetting ) { |
| | var widgetId, parsedId; |
| | parsedId = self.parseWidgetSettingId( widgetSetting.id ); |
| | if ( ! parsedId ) { |
| | return; |
| | } |
| | widgetId = parsedId.idBase; |
| | if ( parsedId.number ) { |
| | widgetId += '-' + String( parsedId.number ); |
| | } |
| | if ( -1 !== _.indexOf( sidebarPartial.getWidgetIds(), widgetId ) ) { |
| | sidebarPartial.ensureWidgetPlacementContainers( widgetId ); |
| | } |
| | } ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | findDynamicSidebarBoundaryNodes: function() { |
| | var partial = this, regExp, boundaryNodes = {}, recursiveCommentTraversal; |
| | regExp = /^(dynamic_sidebar_before|dynamic_sidebar_after):(.+):(\d+)$/; |
| | recursiveCommentTraversal = function( childNodes ) { |
| | _.each( childNodes, function( node ) { |
| | var matches; |
| | if ( 8 === node.nodeType ) { |
| | matches = node.nodeValue.match( regExp ); |
| | if ( ! matches || matches[2] !== partial.sidebarId ) { |
| | return; |
| | } |
| | if ( _.isUndefined( boundaryNodes[ matches[3] ] ) ) { |
| | boundaryNodes[ matches[3] ] = { |
| | before: null, |
| | after: null, |
| | instanceNumber: parseInt( matches[3], 10 ) |
| | }; |
| | } |
| | if ( 'dynamic_sidebar_before' === matches[1] ) { |
| | boundaryNodes[ matches[3] ].before = node; |
| | } else { |
| | boundaryNodes[ matches[3] ].after = node; |
| | } |
| | } else if ( 1 === node.nodeType ) { |
| | recursiveCommentTraversal( node.childNodes ); |
| | } |
| | } ); |
| | }; |
| |
|
| | recursiveCommentTraversal( document.body.childNodes ); |
| | return _.values( boundaryNodes ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | placements: function() { |
| | var partial = this; |
| | return _.map( partial.findDynamicSidebarBoundaryNodes(), function( boundaryNodes ) { |
| | return new api.selectiveRefresh.Placement( { |
| | partial: partial, |
| | container: null, |
| | startNode: boundaryNodes.before, |
| | endNode: boundaryNodes.after, |
| | context: { |
| | instanceNumber: boundaryNodes.instanceNumber |
| | } |
| | } ); |
| | } ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | getWidgetIds: function() { |
| | var sidebarPartial = this, settingId, widgetIds; |
| | settingId = sidebarPartial.settings()[0]; |
| | if ( ! settingId ) { |
| | throw new Error( 'Missing associated setting.' ); |
| | } |
| | if ( ! api.has( settingId ) ) { |
| | throw new Error( 'Setting does not exist.' ); |
| | } |
| | widgetIds = api( settingId ).get(); |
| | if ( ! _.isArray( widgetIds ) ) { |
| | throw new Error( 'Expected setting to be array of widget IDs' ); |
| | } |
| | return widgetIds.slice( 0 ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | reflowWidgets: function() { |
| | var sidebarPartial = this, sidebarPlacements, widgetIds, widgetPartials, sortedSidebarContainers = []; |
| | widgetIds = sidebarPartial.getWidgetIds(); |
| | sidebarPlacements = sidebarPartial.placements(); |
| |
|
| | widgetPartials = {}; |
| | _.each( widgetIds, function( widgetId ) { |
| | var widgetPartial = api.selectiveRefresh.partial( 'widget[' + widgetId + ']' ); |
| | if ( widgetPartial ) { |
| | widgetPartials[ widgetId ] = widgetPartial; |
| | } |
| | } ); |
| |
|
| | _.each( sidebarPlacements, function( sidebarPlacement ) { |
| | var sidebarWidgets = [], needsSort = false, thisPosition, lastPosition = -1; |
| |
|
| | |
| | _.each( widgetPartials, function( widgetPartial ) { |
| | _.each( widgetPartial.placements(), function( widgetPlacement ) { |
| |
|
| | if ( sidebarPlacement.context.instanceNumber === widgetPlacement.context.sidebar_instance_number ) { |
| | thisPosition = widgetPlacement.container.index(); |
| | sidebarWidgets.push( { |
| | partial: widgetPartial, |
| | placement: widgetPlacement, |
| | position: thisPosition |
| | } ); |
| | if ( thisPosition < lastPosition ) { |
| | needsSort = true; |
| | } |
| | lastPosition = thisPosition; |
| | } |
| | } ); |
| | } ); |
| |
|
| | if ( needsSort ) { |
| | _.each( sidebarWidgets, function( sidebarWidget ) { |
| | sidebarPlacement.endNode.parentNode.insertBefore( |
| | sidebarWidget.placement.container[0], |
| | sidebarPlacement.endNode |
| | ); |
| |
|
| | |
| | api.selectiveRefresh.trigger( 'partial-content-moved', sidebarWidget.placement ); |
| | } ); |
| |
|
| | sortedSidebarContainers.push( sidebarPlacement ); |
| | } |
| | } ); |
| |
|
| | if ( sortedSidebarContainers.length > 0 ) { |
| | api.selectiveRefresh.trigger( 'sidebar-updated', sidebarPartial ); |
| | } |
| |
|
| | return sortedSidebarContainers; |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | ensureWidgetPlacementContainers: function( widgetId ) { |
| | var sidebarPartial = this, widgetPartial, wasInserted = false, partialId = 'widget[' + widgetId + ']'; |
| | widgetPartial = api.selectiveRefresh.partial( partialId ); |
| | if ( ! widgetPartial ) { |
| | widgetPartial = new self.WidgetPartial( partialId, { |
| | params: {} |
| | } ); |
| | } |
| |
|
| | |
| | _.each( sidebarPartial.placements(), function( sidebarPlacement ) { |
| | var foundWidgetPlacement, widgetContainerElement; |
| |
|
| | foundWidgetPlacement = _.find( widgetPartial.placements(), function( widgetPlacement ) { |
| | return ( widgetPlacement.context.sidebar_instance_number === sidebarPlacement.context.instanceNumber ); |
| | } ); |
| | if ( foundWidgetPlacement ) { |
| | return; |
| | } |
| |
|
| | widgetContainerElement = $( |
| | sidebarPartial.params.sidebarArgs.before_widget.replace( /%1\$s/g, widgetId ).replace( /%2\$s/g, 'widget' ) + |
| | sidebarPartial.params.sidebarArgs.after_widget |
| | ); |
| |
|
| | |
| | if ( ! widgetContainerElement[0] ) { |
| | return; |
| | } |
| |
|
| | widgetContainerElement.attr( 'data-customize-partial-id', widgetPartial.id ); |
| | widgetContainerElement.attr( 'data-customize-partial-type', 'widget' ); |
| | widgetContainerElement.attr( 'data-customize-widget-id', widgetId ); |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | widgetContainerElement.data( 'customize-partial-placement-context', { |
| | 'sidebar_id': sidebarPartial.sidebarId, |
| | 'sidebar_instance_number': sidebarPlacement.context.instanceNumber |
| | } ); |
| |
|
| | sidebarPlacement.endNode.parentNode.insertBefore( widgetContainerElement[0], sidebarPlacement.endNode ); |
| | wasInserted = true; |
| | } ); |
| |
|
| | api.selectiveRefresh.partial.add( widgetPartial ); |
| |
|
| | if ( wasInserted ) { |
| | sidebarPartial.reflowWidgets(); |
| | } |
| |
|
| | return widgetPartial; |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | handleSettingChange: function( newWidgetIds, oldWidgetIds ) { |
| | var sidebarPartial = this, needsRefresh, widgetsRemoved, widgetsAdded, addedWidgetPartials = []; |
| |
|
| | needsRefresh = ( |
| | ( oldWidgetIds.length > 0 && 0 === newWidgetIds.length ) || |
| | ( newWidgetIds.length > 0 && 0 === oldWidgetIds.length ) |
| | ); |
| | if ( needsRefresh ) { |
| | sidebarPartial.fallback(); |
| | return; |
| | } |
| |
|
| | |
| | widgetsRemoved = _.difference( oldWidgetIds, newWidgetIds ); |
| | _.each( widgetsRemoved, function( removedWidgetId ) { |
| | var widgetPartial = api.selectiveRefresh.partial( 'widget[' + removedWidgetId + ']' ); |
| | if ( widgetPartial ) { |
| | _.each( widgetPartial.placements(), function( placement ) { |
| | var isRemoved = ( |
| | placement.context.sidebar_id === sidebarPartial.sidebarId || |
| | ( placement.context.sidebar_args && placement.context.sidebar_args.id === sidebarPartial.sidebarId ) |
| | ); |
| | if ( isRemoved ) { |
| | placement.container.remove(); |
| | } |
| | } ); |
| | } |
| | delete self.renderedWidgets[ removedWidgetId ]; |
| | } ); |
| |
|
| | |
| | widgetsAdded = _.difference( newWidgetIds, oldWidgetIds ); |
| | _.each( widgetsAdded, function( addedWidgetId ) { |
| | var widgetPartial = sidebarPartial.ensureWidgetPlacementContainers( addedWidgetId ); |
| | addedWidgetPartials.push( widgetPartial ); |
| | self.renderedWidgets[ addedWidgetId ] = true; |
| | } ); |
| |
|
| | _.each( addedWidgetPartials, function( widgetPartial ) { |
| | widgetPartial.refresh(); |
| | } ); |
| |
|
| | api.selectiveRefresh.trigger( 'sidebar-updated', sidebarPartial ); |
| | }, |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | refresh: function() { |
| | var partial = this, deferred = $.Deferred(); |
| |
|
| | deferred.fail( function() { |
| | partial.fallback(); |
| | } ); |
| |
|
| | if ( 0 === partial.placements().length ) { |
| | deferred.reject(); |
| | } else { |
| | _.each( partial.reflowWidgets(), function( sidebarPlacement ) { |
| | api.selectiveRefresh.trigger( 'partial-content-rendered', sidebarPlacement ); |
| | } ); |
| | deferred.resolve(); |
| | } |
| |
|
| | return deferred.promise(); |
| | } |
| | }); |
| |
|
| | api.selectiveRefresh.partialConstructor.sidebar = self.SidebarPartial; |
| | api.selectiveRefresh.partialConstructor.widget = self.WidgetPartial; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.addPartials = function() { |
| | _.each( self.registeredSidebars, function( registeredSidebar ) { |
| | var partial, partialId = 'sidebar[' + registeredSidebar.id + ']'; |
| | partial = api.selectiveRefresh.partial( partialId ); |
| | if ( ! partial ) { |
| | partial = new self.SidebarPartial( partialId, { |
| | params: { |
| | sidebarArgs: registeredSidebar |
| | } |
| | } ); |
| | api.selectiveRefresh.partial.add( partial ); |
| | } |
| | } ); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.buildWidgetSelectors = function() { |
| | var self = this; |
| |
|
| | $.each( self.registeredSidebars, function( i, sidebar ) { |
| | var widgetTpl = [ |
| | sidebar.before_widget, |
| | sidebar.before_title, |
| | sidebar.after_title, |
| | sidebar.after_widget |
| | ].join( '' ), |
| | emptyWidget, |
| | widgetSelector, |
| | widgetClasses; |
| |
|
| | emptyWidget = $( widgetTpl ); |
| | widgetSelector = emptyWidget.prop( 'tagName' ) || ''; |
| | widgetClasses = emptyWidget.prop( 'className' ) || ''; |
| |
|
| | |
| | if ( ! widgetClasses ) { |
| | return; |
| | } |
| |
|
| | |
| | widgetClasses = widgetClasses.replace( /\S*%[12]\$s\S*/g, '' ); |
| | widgetClasses = widgetClasses.replace( /^\s+|\s+$/g, '' ); |
| | if ( widgetClasses ) { |
| | widgetSelector += '.' + widgetClasses.split( /\s+/ ).join( '.' ); |
| | } |
| | self.widgetSelectors.push( widgetSelector ); |
| | }); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.highlightWidget = function( widgetId ) { |
| | var $body = $( document.body ), |
| | $widget = $( '#' + widgetId ); |
| |
|
| | $body.find( '.widget-customizer-highlighted-widget' ).removeClass( 'widget-customizer-highlighted-widget' ); |
| |
|
| | $widget.addClass( 'widget-customizer-highlighted-widget' ); |
| | setTimeout( function() { |
| | $widget.removeClass( 'widget-customizer-highlighted-widget' ); |
| | }, 500 ); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.highlightControls = function() { |
| | var self = this, |
| | selector = this.widgetSelectors.join( ',' ); |
| |
|
| | |
| | if ( ! api.settings.channel ) { |
| | return; |
| | } |
| |
|
| | $( selector ).attr( 'title', this.l10n.widgetTooltip ); |
| | |
| | $( document ).on( 'mouseenter', selector, function() { |
| | self.preview.send( 'highlight-widget-control', $( this ).prop( 'id' ) ); |
| | }); |
| |
|
| | |
| | $( document ).on( 'click', selector, function( e ) { |
| | if ( ! e.shiftKey ) { |
| | return; |
| | } |
| | e.preventDefault(); |
| |
|
| | self.preview.send( 'focus-widget-control', $( this ).prop( 'id' ) ); |
| | }); |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.parseWidgetId = function( widgetId ) { |
| | var matches, parsed = { |
| | idBase: '', |
| | number: null |
| | }; |
| |
|
| | matches = widgetId.match( /^(.+)-(\d+)$/ ); |
| | if ( matches ) { |
| | parsed.idBase = matches[1]; |
| | parsed.number = parseInt( matches[2], 10 ); |
| | } else { |
| | parsed.idBase = widgetId; |
| | } |
| |
|
| | return parsed; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.parseWidgetSettingId = function( settingId ) { |
| | var matches, parsed = { |
| | idBase: '', |
| | number: null |
| | }; |
| |
|
| | matches = settingId.match( /^widget_([^\[]+?)(?:\[(\d+)])?$/ ); |
| | if ( ! matches ) { |
| | return null; |
| | } |
| | parsed.idBase = matches[1]; |
| | if ( matches[2] ) { |
| | parsed.number = parseInt( matches[2], 10 ); |
| | } |
| | return parsed; |
| | }; |
| |
|
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | |
| | self.getWidgetSettingId = function( widgetId ) { |
| | var parsed = this.parseWidgetId( widgetId ), settingId; |
| |
|
| | settingId = 'widget_' + parsed.idBase; |
| | if ( parsed.number ) { |
| | settingId += '[' + String( parsed.number ) + ']'; |
| | } |
| |
|
| | return settingId; |
| | }; |
| |
|
| | api.bind( 'preview-ready', function() { |
| | $.extend( self, _wpWidgetCustomizerPreviewSettings ); |
| | self.init(); |
| | }); |
| |
|
| | return self; |
| | })( jQuery, _, wp, wp.customize ); |
| |
|