Skip to content
This repository was archived by the owner on Dec 27, 2022. It is now read-only.

Commit 68e8f34

Browse files
authored
Merge pull request #59 from xwp/feature/refactor
Refactor
2 parents 04c80c0 + 9c56143 commit 68e8f34

23 files changed

+3627
-1645
lines changed

.dev-lib

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,8 @@
11
PATH_INCLUDES='*.* php js css tests'
22
WPCS_GIT_TREE=develop
3-
ASSETS_DIR=wp-assets
3+
ASSETS_DIR=wp-assets
4+
5+
function after_wp_install {
6+
echo "Installing REST API..."
7+
svn export -q https://plugins.svn.wordpress.org/rest-api/trunk/ "$WP_CORE_DIR/src/wp-content/plugins/rest-api"
8+
}

.travis.yml

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ node_js:
1212
- stable
1313

1414
env:
15-
- WP_VERSION=4.5 WP_MULTISITE=0
16-
- WP_VERSION=trunk WP_MULTISITE=1
15+
- WP_VERSION=trunk WP_MULTISITE=0
1716
- WP_VERSION=latest WP_MULTISITE=1
1817

1918
install:

Gruntfile.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -126,7 +126,7 @@ module.exports = function( grunt ) {
126126
command: 'cd ./dev-lib && ./generate-markdown-readme' // Generate the readme.md
127127
},
128128
phpunit: {
129-
command: 'vagrant ssh -c "cd <%= vvv.plugin %> && phpunit"'
129+
command: 'vagrant ssh -c "cd <%= vvv.plugin %> && phpunit"'
130130
},
131131
phpunit_c: {
132132
command: 'vagrant ssh -c "cd <%= vvv.plugin %> && phpunit --coverage-html <%= vvv.coverage %>"'

css/customize-snapshots.css

+4-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
1-
#snapshot-preview-link {
1+
#snapshot-preview-link, #snapshot-edit-link {
22
float: right;
33
margin-top: 13px;
44
margin-right: 4px;
55
color: #656a6f;
66
}
7+
#snapshot-edit-link{
8+
display: block;
9+
}
710

811
#snapshot-preview-link:hover,
912
#snapshot-preview-link:focus,

customize-snapshots.php

+1-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* Plugin Name: Customize Snapshots
44
* Plugin URI: https://github.com/xwp/wp-customize-snapshots
55
* Description: Allow Customizer states to be drafted, and previewed with a private URL.
6-
* Version: 0.4.0
6+
* Version: 0.5.0
77
* Author: XWP
88
* Author URI: https://xwp.co/
99
* License: GPLv2+

js/customize-snapshots.js

+117-90
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* global jQuery, _customizeSnapshots, JSON */
1+
/* global jQuery, _customizeSnapshots */
22
/* eslint-disable no-extra-parens */
33

44
( function( api, $ ) {
@@ -28,11 +28,8 @@
2828
window._wpCustomizeControlsL10n.saved = component.data.i18n.published;
2929

3030
api.bind( 'ready', function() {
31-
if ( ! api.settings.theme.active || ( component.data.theme && component.data.theme !== api.settings.theme.stylesheet ) ) {
32-
return;
33-
}
31+
api.state.create( 'snapshot-exists', component.data.snapshotExists );
3432
api.state.create( 'snapshot-saved', true );
35-
api.state.create( 'snapshot-exists', Boolean( component.data.isPreview ) );
3633
api.state.create( 'snapshot-submitted', true );
3734
api.bind( 'change', function() {
3835
api.state( 'snapshot-saved' ).set( false );
@@ -41,7 +38,7 @@
4138
component.frontendPreviewUrl = new api.Value( api.previewer.previewUrl.get() );
4239
component.frontendPreviewUrl.link( api.previewer.previewUrl );
4340

44-
component.previewerQuery();
41+
component.extendPreviewerQuery();
4542
component.addButtons();
4643

4744
$( '#snapshot-save' ).on( 'click', function( event ) {
@@ -92,26 +89,21 @@
9289
return request;
9390
} );
9491

95-
api.bind( 'saved', function() {
92+
api.bind( 'saved', function( response ) {
9693
var url = window.location.href,
97-
request,
9894
updatedUrl,
9995
urlParts;
10096

101-
// Set the button text back to "Save".
102-
component.changeButton( component.data.i18n.saveButton, component.data.i18n.permsMsg.save );
103-
api.state( 'snapshot-exists' ).set( false );
104-
105-
request = wp.ajax.post( 'customize_get_snapshot_uuid', {
106-
nonce: component.data.nonce,
107-
wp_customize: 'on'
108-
} );
109-
11097
// Update the UUID.
111-
request.done( function( response ) {
112-
component.data.uuid = response.uuid;
98+
if ( response.new_customize_snapshot_uuid ) {
99+
component.data.uuid = response.new_customize_snapshot_uuid;
113100
component.previewLink.attr( 'target', component.data.uuid );
114-
} );
101+
}
102+
if ( response.edit_link ) {
103+
component.data.editLink = response.edit_link;
104+
}
105+
106+
api.state( 'snapshot-exists' ).set( false );
115107

116108
// Replace the history state with an updated Customizer URL that does not include the Snapshot UUID.
117109
urlParts = url.split( '?' );
@@ -132,27 +124,14 @@
132124
*
133125
* @return {void}
134126
*/
135-
component.previewerQuery = function() {
127+
component.extendPreviewerQuery = function() {
136128
var originalQuery = api.previewer.query;
137129

138130
api.previewer.query = function() {
139-
var allCustomized = {},
140-
retval;
141-
142-
retval = originalQuery.apply( this, arguments );
143-
131+
var retval = originalQuery.apply( this, arguments );
144132
if ( api.state( 'snapshot-exists' ).get() ) {
145-
api.each( function( value, key ) {
146-
if ( value._dirty ) {
147-
allCustomized[ key ] = {
148-
'value': value()
149-
};
150-
}
151-
} );
152-
retval.snapshot_customized = JSON.stringify( allCustomized );
153-
retval.snapshot_uuid = component.data.uuid;
133+
retval.customize_snapshot_uuid = component.data.uuid;
154134
}
155-
156135
return retval;
157136
};
158137
};
@@ -180,7 +159,8 @@
180159
component.addButtons = function() {
181160
var header = $( '#customize-header-actions' ),
182161
publishButton = header.find( '#save' ),
183-
snapshotButton, submitButton, data, setPreviewLinkHref;
162+
snapshotEditLinkTemplate = wp.template( 'snapshot-edit-link' ),
163+
snapshotButton, submitButton, data, setPreviewLinkHref, snapshotEditLinkEl;
184164

185165
// Save/update button.
186166
snapshotButton = wp.template( 'snapshot-save' );
@@ -194,6 +174,50 @@
194174
snapshotButton.prop( 'disabled', true );
195175
snapshotButton.insertAfter( publishButton );
196176

177+
snapshotEditLinkEl = $( $.trim( snapshotEditLinkTemplate( component.data ) ) );
178+
snapshotEditLinkEl.insertAfter( snapshotButton );
179+
if ( ! component.data.editLink ) {
180+
snapshotEditLinkEl.hide();
181+
}
182+
api.state.bind( 'change', function() {
183+
snapshotEditLinkEl.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() );
184+
} );
185+
186+
api.state( 'snapshot-saved' ).bind( function( saved ) {
187+
snapshotButton.prop( 'disabled', saved );
188+
if ( saved ) {
189+
snapshotEditLinkEl.attr( 'href', component.data.editLink );
190+
}
191+
} );
192+
193+
api.state( 'saved' ).bind( function( saved ) {
194+
if ( saved ) {
195+
snapshotButton.prop( 'disabled', true );
196+
}
197+
} );
198+
api.bind( 'change', function() {
199+
snapshotButton.prop( 'disabled', false );
200+
} );
201+
202+
api.state( 'snapshot-exists' ).bind( function( exists ) {
203+
var buttonText, permsMsg;
204+
if ( exists ) {
205+
buttonText = component.data.i18n.updateButton;
206+
permsMsg = component.data.i18n.permsMsg.update;
207+
if ( component.data.editLink ) {
208+
snapshotEditLinkEl.attr( 'href', component.data.editLink );
209+
}
210+
} else {
211+
buttonText = component.data.i18n.saveButton;
212+
permsMsg = component.data.i18n.permsMsg.save;
213+
}
214+
215+
snapshotButton.text( buttonText );
216+
if ( ! component.data.currentUserCanPublish ) {
217+
snapshotButton.attr( 'title', permsMsg );
218+
}
219+
} );
220+
197221
// Preview link.
198222
component.previewLink = $( $.trim( wp.template( 'snapshot-preview-link' )() ) );
199223
component.previewLink.toggle( api.state( 'snapshot-saved' ).get() );
@@ -211,7 +235,6 @@
211235
api.bind( 'saved', setPreviewLinkHref );
212236
snapshotButton.after( component.previewLink );
213237
api.state( 'snapshot-saved' ).bind( function( saved ) {
214-
snapshotButton.prop( 'disabled', saved );
215238
component.previewLink.toggle( saved );
216239
} );
217240

@@ -232,24 +255,6 @@
232255
header.addClass( 'button-added' );
233256
};
234257

235-
/**
236-
* Change the snapshot button.
237-
*
238-
* @param {string} buttonText The button text.
239-
* @param {string} permsMsg The permissions message.
240-
* @return {void}
241-
*/
242-
component.changeButton = function( buttonText, permsMsg ) {
243-
var snapshotButton = $( '#customize-header-actions' ).find( '#snapshot-save' );
244-
245-
if ( snapshotButton.length ) {
246-
snapshotButton.text( buttonText );
247-
if ( ! component.data.currentUserCanPublish ) {
248-
snapshotButton.attr( 'title', permsMsg );
249-
}
250-
}
251-
};
252-
253258
/**
254259
* Silently update the saved state to be true without triggering the
255260
* changed event so that the AYS beforeunload dialog won't appear
@@ -276,7 +281,7 @@
276281
*/
277282
component.sendUpdateSnapshotRequest = function( options ) {
278283
var spinner = $( '#customize-header-actions .spinner' ),
279-
request, customized, args;
284+
request, data, args;
280285

281286
args = _.extend(
282287
{
@@ -285,51 +290,49 @@
285290
options
286291
);
287292

288-
spinner.addClass( 'is-active' );
293+
data = _.extend(
294+
{},
295+
api.previewer.query(),
296+
{
297+
nonce: api.settings.nonce.snapshot,
298+
customize_snapshot_uuid: component.data.uuid,
299+
status: args.status
300+
}
301+
);
302+
request = wp.ajax.post( 'customize_update_snapshot', data );
289303

290-
customized = {};
291-
api.each( function( value, key ) {
292-
if ( value._dirty ) {
293-
customized[ key ] = {
294-
'value': value()
295-
};
304+
spinner.addClass( 'is-active' );
305+
request.always( function( response ) {
306+
spinner.removeClass( 'is-active' );
307+
if ( response.edit_link ) {
308+
component.data.editLink = response.edit_link;
296309
}
297-
} );
298310

299-
request = wp.ajax.post( 'customize_update_snapshot', {
300-
nonce: component.data.nonce,
301-
wp_customize: 'on',
302-
snapshot_customized: JSON.stringify( customized ),
303-
customize_snapshot_uuid: component.data.uuid,
304-
status: args.status,
305-
preview: ( api.state( 'snapshot-exists' ).get() ? 'on' : 'off' )
311+
// @todo Remove privateness from _handleSettingValidities in Core.
312+
if ( api._handleSettingValidities && response.setting_validities ) {
313+
api._handleSettingValidities( {
314+
settingValidities: response.setting_validities,
315+
focusInvalidControl: true
316+
} );
317+
}
306318
} );
307319

308-
request.done( function( response ) {
320+
request.done( function() {
309321
var url = api.previewer.previewUrl(),
310322
regex = new RegExp( '([?&])customize_snapshot_uuid=.*?(&|$)', 'i' ),
311323
separator = url.indexOf( '?' ) !== -1 ? '&' : '?',
312324
customizeUrl = window.location.href,
313325
customizeSeparator = customizeUrl.indexOf( '?' ) !== -1 ? '&' : '?';
314326

315-
// Set the UUID.
316-
if ( ! component.data.uuid ) {
317-
component.data.uuid = response.customize_snapshot_uuid;
318-
component.previewLink.attr( 'target', component.data.uuid );
319-
}
320-
321327
if ( url.match( regex ) ) {
322328
url = url.replace( regex, '$1customize_snapshot_uuid=' + encodeURIComponent( component.data.uuid ) + '$2' );
323329
} else {
324330
url = url + separator + 'customize_snapshot_uuid=' + encodeURIComponent( component.data.uuid );
325331
}
326332

327333
// Change the save button text to update.
328-
component.changeButton( component.data.i18n.updateButton, component.data.i18n.permsMsg.update );
329334
api.state( 'snapshot-exists' ).set( true );
330335

331-
spinner.removeClass( 'is-active' );
332-
333336
// Replace the history state with an updated Customizer URL that includes the Snapshot UUID.
334337
if ( history.replaceState && ! customizeUrl.match( regex ) ) {
335338
customizeUrl += customizeSeparator + 'customize_snapshot_uuid=' + encodeURIComponent( component.data.uuid );
@@ -350,25 +353,49 @@
350353
} );
351354
} );
352355

353-
request.fail( function() {
356+
request.fail( function( response ) {
354357
var id = 'snapshot-dialog-error',
355-
snapshotDialogShareError = wp.template( id );
358+
snapshotDialogShareError = wp.template( id ),
359+
messages = component.data.i18n.errorMsg,
360+
invalidityCount = 0,
361+
dialogElement;
362+
363+
if ( response.setting_validities ) {
364+
invalidityCount = _.size( response.setting_validities, function( validity ) {
365+
return true !== validity;
366+
} );
367+
}
368+
369+
/*
370+
* Short-circuit if there are setting validation errors, since the error messages
371+
* will be displayed with the controls themselves. Eventually, once we have
372+
* a global notification area in the Customizer, we can eliminate this
373+
* short-circuit and instead display the messages in there.
374+
* See https://core.trac.wordpress.org/ticket/35210
375+
*/
376+
if ( invalidityCount > 0 ) {
377+
return;
378+
}
379+
380+
if ( response.errors ) {
381+
messages += ' ' + _.pluck( response.errors, 'message' ).join( ' ' );
382+
}
356383

357384
// Insert the snapshot dialog error template.
358-
if ( 0 === $( '#' + id ).length ) {
359-
$( 'body' ).append( snapshotDialogShareError( {
385+
dialogElement = $( '#' + id );
386+
if ( ! dialogElement.length ) {
387+
dialogElement = $( snapshotDialogShareError( {
360388
title: component.data.i18n.errorTitle,
361-
message: component.data.i18n.errorMsg
389+
message: messages
362390
} ) );
391+
$( 'body' ).append( dialogElement );
363392
}
364393

365394
// Open the dialog.
366-
$( '#' + id ).dialog( {
395+
dialogElement.dialog( {
367396
autoOpen: true,
368397
modal: true
369398
} );
370-
371-
spinner.removeClass( 'is-active' );
372399
} );
373400
};
374401

0 commit comments

Comments
 (0)