/* global jQuery, JSON, _customizePartialRefreshExports, console */ wp.customize.selectiveRefresh = ( function( $, api ) { 'use strict'; var self, Partial, Placement; self = { ready: $.Deferred(), editShortcutVisibility: new api.Value(), data: { partials: {}, renderQueryVar: '', l10n: { shiftClickToEdit: '' } }, currentRequest: null }; _.extend( self, api.Events ); /** * A Customizer Partial. * * A partial provides a rendering of one or more settings according to a template. * * @see PHP class WP_Customize_Partial. * * @class * @augments wp.customize.Class * @since 4.5.0 * * @param {string} id Unique identifier for the control instance. * @param {object} options Options hash for the control instance. * @param {object} options.params * @param {string} options.params.type Type of partial (e.g. nav_menu, widget, etc) * @param {string} options.params.selector jQuery selector to find the container element in the page. * @param {array} options.params.settings The IDs for the settings the partial relates to. * @param {string} options.params.primarySetting The ID for the primary setting the partial renders. * @param {bool} options.params.fallbackRefresh Whether to refresh the entire preview in case of a partial refresh failure. */ Partial = self.Partial = api.Class.extend({ id: null, /** * Constructor. * * @since 4.5.0 * * @param {string} id - Partial ID. * @param {Object} options * @param {Object} options.params */ initialize: function( id, options ) { var partial = this; options = options || {}; partial.id = id; partial.params = _.extend( { selector: null, settings: [], primarySetting: null, containerInclusive: false, fallbackRefresh: true // Note this needs to be false in a front-end editing context. }, options.params || {} ); partial.deferred = {}; partial.deferred.ready = $.Deferred(); partial.deferred.ready.done( function() { partial.ready(); } ); }, /** * Set up the partial. * * @since 4.5.0 */ ready: function() { var partial = this; _.each( partial.placements(), function( placement ) { $( placement.container ).attr( 'title', self.data.l10n.shiftClickToEdit ); partial.createEditShortcutForPlacement( placement ); } ); $( document ).on( 'click', partial.params.selector, function( e ) { if ( ! e.shiftKey ) { return; } e.preventDefault(); _.each( partial.placements(), function( placement ) { if ( $( placement.container ).is( e.currentTarget ) ) { partial.showControl(); } } ); } ); }, /** * Create and show the edit shortcut for a given partial placement container. * * @since 4.7 * * @param {Placement} placement The placement container element. * @returns {void} */ createEditShortcutForPlacement: function( placement ) { var partial = this, $shortcut, $placementContainer; if ( ! placement.container ) { return; } $placementContainer = $( placement.container ); if ( ! $placementContainer.length ) { return; } $shortcut = partial.createEditShortcut(); partial.positionEditShortcut( placement, $shortcut ); $shortcut.on( 'click', function( event ) { event.preventDefault(); event.stopPropagation(); partial.showControl(); } ); }, /** * Position an edit shortcut for the placement container. * * The shortcut must already be created and added to the page. * * @since 4.7 * * @param {Placement} placement The placement for the partial. * @param {jQuery} $editShortcut The shortcut element as a jQuery object. * @returns {void} */ positionEditShortcut: function( placement, $editShortcut ) { var $placementContainer = $( placement.container ); $placementContainer.prepend( $editShortcut ); if ( ! $placementContainer.is( ':visible' ) || 'none' === $placementContainer.css( 'display' ) ) { $editShortcut.addClass( 'customize-partial-edit-shortcut-hidden' ); } $editShortcut.toggleClass( 'customize-partial-edit-shortcut-left-margin', $editShortcut.offset().left < 1 ); }, /** * Return the unique class name for the edit shortcut button for this partial. * * @since 4.7 * * @return {string} Partial ID converted into a class name for use in shortcut. */ getEditShortcutClassName: function() { var partial = this, cleanId; cleanId = partial.id.replace( /]/g, '' ).replace( /\[/g, '-' ); return 'customize-partial-edit-shortcut-' + cleanId; }, /** * Return the appropriate translated string for the edit shortcut button. * * @since 4.7 * * @return {string} Tooltip for edit shortcut. */ getEditShortcutTitle: function() { var partial = this, l10n = self.data.l10n; switch ( partial.getType() ) { case 'widget': return l10n.clickEditWidget; case 'blogname': return l10n.clickEditTitle; case 'blogdescription': return l10n.clickEditTitle; case 'nav_menu': return l10n.clickEditMenu; default: return l10n.clickEditMisc; } }, /** * Return the type of this partial * * Will use `params.type` if set, but otherwise will try to infer type from settingId. * * @since 4.7 * * @return {string} Type of partial derived from type param or the related setting ID. */ getType: function() { var partial = this, settingId; settingId = partial.params.primarySetting || _.first( partial.settings() ) || 'unknown'; if ( partial.params.type ) { return partial.params.type; } if ( settingId.match( /^nav_menu_instance\[/ ) ) { return 'nav_menu'; } if ( settingId.match( /^widget_.+\[\d+]$/ ) ) { return 'widget'; } return settingId; }, /** * Create an edit shortcut button for this partial. * * @since 4.7 * * @return {jQuery} The edit shortcut button element. */ createEditShortcut: function() { var partial = this, shortcutTitle; shortcutTitle = partial.getEditShortcutTitle(); return $( '' ); $editShortcutVisibilityButton.text( buttonText ); $editShortcutVisibilityButton.on( 'click', function() { api.selectiveRefresh.editShortcutVisibility.set( 'visible' === api.selectiveRefresh.editShortcutVisibility.get() ? 'hidden' : 'visible' ); } ); body.prepend( $editShortcutVisibilityButton ); } // Make all partials ready. self.partial.each( function( partial ) { partial.deferred.ready.resolve(); } ); // Make all partials added henceforth as ready upon add. self.partial.bind( 'add', function( partial ) { partial.deferred.ready.resolve(); } ); body.on( 'click', function( event ) { if ( $( event.target ).is( '.customize-partial-edit-shortcut, :input, a[href]' ) || 0 !== $( event.target ).closest( 'a' ).length ) { return; // Don't toggle shortcuts on form, link, or link child clicks. } api.selectiveRefresh.editShortcutVisibility.set( 'visible' === api.selectiveRefresh.editShortcutVisibility.get() ? 'hidden' : 'visible' ); api.preview.send( 'edit-shortcut-visibility', api.selectiveRefresh.editShortcutVisibility.get() ); } ); } ); } ); return self; }( jQuery, wp.customize ) );