From 30df6bda6c0ad060c8cbdb8ca670155c4e1e0bcd Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 28 Jul 2016 20:29:12 +0530 Subject: [PATCH 01/59] [WIP] Schedule UI for snapshot in customizer --- css/customize-snapshots.css | 70 +++++++++++++- js/customize-snapshots.js | 32 +++++-- php/class-customize-snapshot-manager.php | 112 ++++++++++++++++++++++- 3 files changed, 202 insertions(+), 12 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 53c8ee3a..ccdb2469 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -1,10 +1,10 @@ -#snapshot-preview-link, #snapshot-edit-link { +#snapshot-preview-link, #snapshot-toggle-button { float: right; margin-top: 13px; margin-right: 4px; color: #656a6f; } -#snapshot-edit-link{ +#snapshot-toggle-button{ display: block; } @@ -53,4 +53,70 @@ margin-top: 6px; margin-right: 6px; } +} + +#customize-snapshot-control select, +#customize-snapshot-control input[type="text"] { + min-width: 10%; + width: auto; +} + +#customize-snapshot-control{ + padding: 5px; +} + +#customize-snapshot-control input[type="text"].error { + border-color: #dc3232 !important; + -webkit-box-shadow: 0 0 2px rgba( 204, 0, 0, 0.8 ); + box-shadow: 0 0 2px rgba( 204, 0, 0, 0.8 ); +} + +#customize-schedule-box{ + background: #fff !important; + margin-bottom: 10px; + padding-bottom: 10px; +} + +#customize-schedule-box .accordion-section-title{ + background: #fff; + color: #555; + border-left: none; + border-right: none; + border-bottom: none; + cursor: default; +} + +#customize-schedule-box .accordion-section-title:after{ + z-index: -1; +} +#customize-schedule-box a{ + position: absolute; + top: 4px; + right: 1px; + width: 20px; + height: 20px; + cursor: pointer; + -webkit-box-shadow: none; + box-shadow: none; + -webkit-appearance: none; + background: transparent; + color: #555; + border: none; + padding: 10px; +} + +#customize-schedule-box span{ + font-size: 13px; + line-height: 24px; +} +#customize-schedule-box .customize-snapshot-control{ + padding: 5px; +} +#customize-schedule-box .accordion-section-title{ + padding: 10px; +} +.in-sub-panel #customize-schedule-box { + left: -100%; + width: 100%; + position: relative; } \ No newline at end of file diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 946b2430..a0fed96b 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -159,8 +159,9 @@ component.addButtons = function() { var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), - snapshotEditLinkTemplate = wp.template( 'snapshot-edit-link' ), - snapshotButton, submitButton, data, setPreviewLinkHref, snapshotEditLinkEl; + snapshotDropDownToggleTemplate = wp.template( 'snapshot-toggle-button' ), + snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), + snapshotScheduleBox, snapshotButton, submitButton, data, setPreviewLinkHref, snapshotDropDownToggle, snapshotEditLink; // Save/update button. snapshotButton = wp.template( 'snapshot-save' ); @@ -174,19 +175,34 @@ snapshotButton.prop( 'disabled', true ); snapshotButton.insertAfter( publishButton ); - snapshotEditLinkEl = $( $.trim( snapshotEditLinkTemplate( component.data ) ) ); - snapshotEditLinkEl.insertAfter( snapshotButton ); + snapshotDropDownToggle = $( $.trim( snapshotDropDownToggleTemplate( {} ) ) ); + snapshotEditLink = snapshotDropDownToggle.find( 'a' ); + + snapshotDropDownToggle.click( function( e ) { + var customizeInfo = $( '#customize-info' ); + if ( ! snapshotScheduleBox ) { + snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); + snapshotScheduleBox.insertBefore( customizeInfo ); + } else { + + // Todo need to update in case of dynamic section. + snapshotScheduleBox.slideToggle(); + } + e.preventDefault(); + } ); + + snapshotDropDownToggle.insertAfter( snapshotButton ); if ( ! component.data.editLink ) { - snapshotEditLinkEl.hide(); + snapshotDropDownToggle.hide(); } api.state.bind( 'change', function() { - snapshotEditLinkEl.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + snapshotDropDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); } ); api.state( 'snapshot-saved' ).bind( function( saved ) { snapshotButton.prop( 'disabled', saved ); if ( saved ) { - snapshotEditLinkEl.attr( 'href', component.data.editLink ); + snapshotEditLink.attr( 'href', component.data.editLink ); } } ); @@ -205,7 +221,7 @@ buttonText = component.data.i18n.updateButton; permsMsg = component.data.i18n.permsMsg.update; if ( component.data.editLink ) { - snapshotEditLinkEl.attr( 'href', component.data.editLink ); + snapshotEditLink.attr( 'href', component.data.editLink ); } } else { buttonText = component.data.i18n.saveButton; diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index b8bd4ebb..ab29e932 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1058,6 +1058,7 @@ public function replace_customize_link( $wp_admin_bar ) { * Underscore (JS) templates for dialog windows. */ public function render_templates() { + $data = $this->data_json(); ?> <script type="text/html" id="tmpl-snapshot-preview-link"> <a href="#" target="frontend-preview" id="snapshot-preview-link" class="dashicons dashicons-welcome-view-site" title="<?php esc_attr_e( 'View on frontend', 'customize-snapshots' ) ?>"> @@ -1065,8 +1066,74 @@ public function render_templates() { </a> </script> - <script type="text/html" id="tmpl-snapshot-edit-link"> - <a href="{{ data.editLink }}" id="snapshot-edit-link" class="dashicons dashicons-calendar-alt" title="<?php esc_attr_e( 'Edit Snapshot','customize-snapshots' ); ?>"></a> + <script type="text/html" id="tmpl-snapshot-toggle-button"> + <a href="#" id="snapshot-toggle-button" class="dashicons dashicons-calendar-alt" title="<?php esc_attr_e( 'Schedule Snapshot','customize-snapshots' ); ?>"></a> + </script> + + <script type="text/html" id="tmpl-snapshot-schedule-accordion"> + <div id="customize-schedule-box" class="accordion-section"> + <div class="accordion-section-title"> + <span class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></span> + <a href={{ data.editLink }} class="dashicons dashicons-edit" aria-expanded="false"></a> + </div> + <div class="customize-snapshot-control"> + <# + _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); + data.input_id_post_date = 'input-' + String( Math.random() ); + data.input_id_post_date_gmt = 'input-' + String( Math.random() ); + #> + <# _.each( data.date_inputs, function( width, type ) { #> + <# if ( 'month' === type ) { #> + <select class="date-input {{ type }}"> + <# _.each( data.month_choices, function( choice ) { #> + <# if ( _.isObject( choice ) && ! _.isUndefined( choice.text ) && ! _.isUndefined( choice.value ) ) { + text = choice.text; + value = choice.value; + } #> + <option value="{{ value }}">{{ text }}</option> + <# } ); #> + </select> + <# } else { #> + <input + type="text" + size="{{ width }}" + maxlength="{{ width }}" + autocomplete="off" + class="date-input {{ type }}" + /> + <# if ( 'year' === type ) { #> + @ + <# } #> + <# } #> + <# }); #> + <input + id="" + type="hidden" + class="post-date" + <# if ( data.setting_property ) { #> + data-customize-setting-property-link="post_date" + <# } #> + /> + <input + id="" + type="hidden" + class="post-date-gmt" + value="" + <# if ( data.setting_property ) { #> + data-customize-setting-property-link="post_date_gmt" + <# } #> + /> + <input + id="" + type="hidden" + class="post-status" + value="" + <# if ( data.setting_property ) { #> + data-customize-setting-property-link="post_status" + <# } #> + /> + </div> + </div> </script> <script type="text/html" id="tmpl-snapshot-save"> @@ -1088,4 +1155,45 @@ public function render_templates() { </script> <?php } + + /** + * Get the data to export to the client via JSON. + * + * @return array Array of parameters passed to the JavaScript. + */ + public function data_json() { + $exported['month_choices'] = $this->get_month_choices(); + // Type / width pairs. + $exported['date_inputs'] = array( + 'month' => null, + 'day' => 2, + 'year' => 4, + 'hour' => 2, + 'min' => 2, + ); + return $exported; + } + + /** + * Generate options for the month Select. + * + * Based on touch_time(). + * + * @see touch_time() + * + * @return array + */ + public function get_month_choices() { + global $wp_locale; + $months = array(); + for ( $i = 1; $i < 13; $i = $i + 1 ) { + $month_number = zeroise( $i, 2 ); + $month_text = $wp_locale->get_month_abbrev( $wp_locale->get_month( $i ) ); + + /* translators: 1: month number (01, 02, etc.), 2: month abbreviation */ + $months[ $i ]['text'] = sprintf( __( '%1$s-%2$s', 'customize-snapshots' ), $month_number, $month_text ); + $months[ $i ]['value'] = $month_number; + } + return $months; + } } From b01a91e8b7bee4e92fa772022627bc82cbec5804 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Fri, 29 Jul 2016 15:14:06 +0530 Subject: [PATCH 02/59] Template and css update --- css/customize-snapshots.css | 18 +++-- php/class-customize-snapshot-manager.php | 97 ++++++------------------ 2 files changed, 35 insertions(+), 80 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index ccdb2469..39d3ef12 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -55,22 +55,24 @@ } } -#customize-snapshot-control select, -#customize-snapshot-control input[type="text"] { +.customize-snapshot-control select, +.customize-snapshot-control input.date-input { min-width: 10%; width: auto; } +.customize-snapshot-control input.date-input { + -moz-appearance: textfield; +} +.customize-snapshot-control input.date-input::-webkit-outer-spin-button, +.customize-snapshot-control input.date-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} #customize-snapshot-control{ padding: 5px; } -#customize-snapshot-control input[type="text"].error { - border-color: #dc3232 !important; - -webkit-box-shadow: 0 0 2px rgba( 204, 0, 0, 0.8 ); - box-shadow: 0 0 2px rgba( 204, 0, 0, 0.8 ); -} - #customize-schedule-box{ background: #fff !important; margin-bottom: 10px; diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index ab29e932..cc4b5959 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -533,6 +533,7 @@ public function enqueue_scripts() { 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), 'editLink' => $this->snapshot ? get_edit_post_link( $this->snapshot->post(), 'raw' ) : '', + 'snapshotPublishDate' => $this->snapshot ? $this->snapshot->post()->post_date_gmt : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), 'i18n' => array( 'saveButton' => __( 'Save', 'customize-snapshots' ), @@ -938,6 +939,7 @@ function( $value ) { $post = $this->snapshot->post(); if ( $post ) { $data['edit_link'] = get_edit_post_link( $post, 'raw' ); + $data['snapshotPublishDate'] = $post->post_date_gmt; } if ( is_wp_error( $r ) ) { @@ -1058,7 +1060,7 @@ public function replace_customize_link( $wp_admin_bar ) { * Underscore (JS) templates for dialog windows. */ public function render_templates() { - $data = $this->data_json(); + $data = $this->get_month_choices(); ?> <script type="text/html" id="tmpl-snapshot-preview-link"> <a href="#" target="frontend-preview" id="snapshot-preview-link" class="dashicons dashicons-welcome-view-site" title="<?php esc_attr_e( 'View on frontend', 'customize-snapshots' ) ?>"> @@ -1074,64 +1076,33 @@ public function render_templates() { <div id="customize-schedule-box" class="accordion-section"> <div class="accordion-section-title"> <span class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></span> + <# if ( data.description ) { #> + <span class="description customize-control-description"> + {{ data.description }} + </span> + <# } #> <a href={{ data.editLink }} class="dashicons dashicons-edit" aria-expanded="false"></a> </div> <div class="customize-snapshot-control"> - <# - _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); + <# _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); data.input_id_post_date = 'input-' + String( Math.random() ); data.input_id_post_date_gmt = 'input-' + String( Math.random() ); #> - <# _.each( data.date_inputs, function( width, type ) { #> - <# if ( 'month' === type ) { #> - <select class="date-input {{ type }}"> - <# _.each( data.month_choices, function( choice ) { #> - <# if ( _.isObject( choice ) && ! _.isUndefined( choice.text ) && ! _.isUndefined( choice.value ) ) { - text = choice.text; - value = choice.value; - } #> - <option value="{{ value }}">{{ text }}</option> - <# } ); #> - </select> - <# } else { #> - <input - type="text" - size="{{ width }}" - maxlength="{{ width }}" - autocomplete="off" - class="date-input {{ type }}" - /> - <# if ( 'year' === type ) { #> - @ - <# } #> - <# } #> - <# }); #> - <input - id="" - type="hidden" - class="post-date" - <# if ( data.setting_property ) { #> - data-customize-setting-property-link="post_date" - <# } #> - /> - <input - id="" - type="hidden" - class="post-date-gmt" - value="" - <# if ( data.setting_property ) { #> - data-customize-setting-property-link="post_date_gmt" - <# } #> - /> - <input - id="" - type="hidden" - class="post-status" - value="" - <# if ( data.setting_property ) { #> - data-customize-setting-property-link="post_status" - <# } #> - /> + <select id="{{ data.input_id }}" class="date-input month" data-component="month"> + <# _.each( data.month_choices, function( choice ) { #> + <# if ( _.isObject( choice ) && ! _.isUndefined( choice.text ) && ! _.isUndefined( choice.value ) ) { + text = choice.text; + value = choice.value; + } + #> + <option value="{{ value }}">{{ text }}</option> + <# } ); #> + </select> + + <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input day" data-component="day" min="1" max="31" />, + <input type="number" size="4" maxlength="4" autocomplete="off" class="date-input year" data-component="year" min="<?php echo esc_attr( date( 'Y' ) ); ?>" max="9999" /> + @ <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input hour" data-component="hour" min="0" max="23" />:<?php + ?><input type="number" size="2" maxlength="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59" /> </div> </div> </script> @@ -1156,24 +1127,6 @@ class="post-status" <?php } - /** - * Get the data to export to the client via JSON. - * - * @return array Array of parameters passed to the JavaScript. - */ - public function data_json() { - $exported['month_choices'] = $this->get_month_choices(); - // Type / width pairs. - $exported['date_inputs'] = array( - 'month' => null, - 'day' => 2, - 'year' => 4, - 'hour' => 2, - 'min' => 2, - ); - return $exported; - } - /** * Generate options for the month Select. * @@ -1194,6 +1147,6 @@ public function get_month_choices() { $months[ $i ]['text'] = sprintf( __( '%1$s-%2$s', 'customize-snapshots' ), $month_number, $month_text ); $months[ $i ]['value'] = $month_number; } - return $months; + return array( 'month_choices' => $months ); } } From 069fbbeb8f2811580ca716e3efaadec608ba1037 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Mon, 1 Aug 2016 17:58:08 +0530 Subject: [PATCH 03/59] Update template, refactor js for slidedown and add js function for date manipulation --- js/customize-snapshots.js | 119 ++++++++++++++++++----- php/class-customize-snapshot-manager.php | 93 +++++++++++++++--- 2 files changed, 177 insertions(+), 35 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index a0fed96b..dc64e5ee 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -40,6 +40,7 @@ component.extendPreviewerQuery(); component.addButtons(); + component.addSlideDown(); $( '#snapshot-save' ).on( 'click', function( event ) { event.preventDefault(); @@ -151,6 +152,32 @@ return a.href; }; + component.dateComponentInputs = {}; + + component.addSlideDown = function slideDown() { + var snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), + snapshotScheduleBox; + component.snapshotSlideDownToggle.click( function( e ) { + var customizeInfo = $( '#customize-info' ); + if ( ! snapshotScheduleBox ) { + component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); + snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); + component.dateInputs = snapshotScheduleBox.find( '.date-input' ); + component.dateInputs.each( function() { + var input = $( this ), componentName; + componentName = input.data( 'component' ); + component.dateComponentInputs[ componentName ] = input; + } ); + snapshotScheduleBox.insertBefore( customizeInfo ); + } else { + + // Todo need to update in case of dynamic section. + snapshotScheduleBox.slideToggle(); + } + e.preventDefault(); + } ); + }; + /** * Create the snapshot buttons. * @@ -159,9 +186,8 @@ component.addButtons = function() { var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), - snapshotDropDownToggleTemplate = wp.template( 'snapshot-toggle-button' ), - snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), - snapshotScheduleBox, snapshotButton, submitButton, data, setPreviewLinkHref, snapshotDropDownToggle, snapshotEditLink; + snapshotSlideDownToggleTemplate = wp.template( 'snapshot-toggle-button' ), + snapshotButton, submitButton, data, setPreviewLinkHref, snapshotSlideDownToggle, snapshotEditLink; // Save/update button. snapshotButton = wp.template( 'snapshot-save' ); @@ -175,28 +201,15 @@ snapshotButton.prop( 'disabled', true ); snapshotButton.insertAfter( publishButton ); - snapshotDropDownToggle = $( $.trim( snapshotDropDownToggleTemplate( {} ) ) ); - snapshotEditLink = snapshotDropDownToggle.find( 'a' ); - - snapshotDropDownToggle.click( function( e ) { - var customizeInfo = $( '#customize-info' ); - if ( ! snapshotScheduleBox ) { - snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); - snapshotScheduleBox.insertBefore( customizeInfo ); - } else { - - // Todo need to update in case of dynamic section. - snapshotScheduleBox.slideToggle(); - } - e.preventDefault(); - } ); - - snapshotDropDownToggle.insertAfter( snapshotButton ); + snapshotSlideDownToggle = $( $.trim( snapshotSlideDownToggleTemplate( {} ) ) ); + snapshotSlideDownToggle.insertAfter( snapshotButton ); + snapshotEditLink = snapshotSlideDownToggle.find( 'a' ); + component.snapshotSlideDownToggle = snapshotSlideDownToggle; if ( ! component.data.editLink ) { - snapshotDropDownToggle.hide(); + snapshotSlideDownToggle.hide(); } api.state.bind( 'change', function() { - snapshotDropDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + snapshotSlideDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); } ); api.state( 'snapshot-saved' ).bind( function( saved ) { @@ -415,6 +428,68 @@ } ); }; + /** + * Get date from inputs. + * + * @returns {Date|null} Date created from inputs or null if invalid date. + */ + component.getDateFromInputs = function getDateFromInputs() { + var control = component, date; + date = new Date( + parseInt( control.dateComponentInputs.year.val(), 10 ), + parseInt( control.dateComponentInputs.month.val(), 10 ) - 1, + parseInt( control.dateComponentInputs.day.val(), 10 ), + parseInt( control.dateComponentInputs.hour.val(), 10 ), + parseInt( control.dateComponentInputs.minute.val(), 10 ) + ); + if ( isNaN( date.valueOf() ) ) { + return null; + } + return date; + }; + + /** + * Parse datetime string. + * + * @param {string} datetime Date/Time string. + * @returns {object|null} Returns object containing date components or null if parse error. + */ + component.parseDateTime = function parseDateTime( datetime ) { + var matches = datetime.match( /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/ ); + if ( ! matches ) { + return null; + } + matches.shift(); + return { + year: matches.shift(), + month: matches.shift(), + day: matches.shift(), + hour: matches.shift(), + minute: matches.shift(), + second: matches.shift() + }; + }; + + /** + * Format a Date Object. Returns 'Y-m-d H:i:s' format. + * + * @param {Date} date A Date object. + * @returns {string} A formatted date String. + */ + component.formatDate = function formatDate( date ) { + var formattedDate, yearLength = 4, nonYearLength = 2; + + // Props: http://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript#comment33639551_10073699 + formattedDate = ( '0000' + date.getFullYear() ).substr( -yearLength, yearLength ); + formattedDate += '-' + ( '00' + ( date.getMonth() + 1 ) ).substr( -nonYearLength, nonYearLength ); + formattedDate += '-' + ( '00' + date.getDate() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ' ' + ( '00' + date.getHours() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ':' + ( '00' + date.getMinutes() ).substr( -nonYearLength, nonYearLength ); + formattedDate += ':' + ( '00' + date.getSeconds() ).substr( -nonYearLength, nonYearLength ); + + return formattedDate; + }; + component.init(); } )( wp.customize, jQuery ); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index cc4b5959..74d8db2c 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -527,13 +527,17 @@ public function enqueue_scripts() { wp_enqueue_style( $this->plugin->slug ); wp_enqueue_script( $this->plugin->slug ); + if ( $this->snapshot ) { + $post = $this->snapshot->post(); + $this->override_post_date_default_data( $post ); + } // Script data array. $exports = apply_filters( 'customize_snapshots_export_data', array( 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), - 'editLink' => $this->snapshot ? get_edit_post_link( $this->snapshot->post(), 'raw' ) : '', - 'snapshotPublishDate' => $this->snapshot ? $this->snapshot->post()->post_date_gmt : '', + 'editLink' => $this->snapshot ? get_edit_post_link( $post, 'raw' ) : '', + 'snapshotPublishDate' => $this->snapshot ? $post->post_date_gmt : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), 'i18n' => array( 'saveButton' => __( 'Save', 'customize-snapshots' ), @@ -1076,11 +1080,25 @@ public function render_templates() { <div id="customize-schedule-box" class="accordion-section"> <div class="accordion-section-title"> <span class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></span> - <# if ( data.description ) { #> - <span class="description customize-control-description"> - {{ data.description }} - </span> - <# } #> + <span class="description customize-control-description"> + <?php + $tz_string = get_option( 'timezone_string' ); + if ( $tz_string ) { + $tz = new \DateTimezone( $tz_string ); + $formatted_gmt_offset = $this->format_gmt_offset( $tz->getOffset( new \DateTime() ) / 3600 ); + $tz_name = str_replace( '_', ' ', $tz->getName() ); + + /* translators: 1: timezone name, 2: gmt offset */ + $date_control_description = sprintf( __( 'This site\'s dates are in the %1$s timezone (currently UTC%2$s).', 'customize-snapshots' ), $tz_name, $formatted_gmt_offset ); + } else { + $formatted_gmt_offset = $this->format_gmt_offset( get_option( 'gmt_offset' ) ); + + /* translators: %s: gmt offset */ + $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); + } + ?> + <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> + </span> <a href={{ data.editLink }} class="dashicons dashicons-edit" aria-expanded="false"></a> </div> <div class="customize-snapshot-control"> @@ -1095,14 +1113,15 @@ public function render_templates() { value = choice.value; } #> - <option value="{{ value }}">{{ text }}</option> + <option value="{{ value }}" <# if (choice.value == data.month) { #> + selected="selected" + <# } #>>{{ text }}</option> <# } ); #> </select> - - <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input day" data-component="day" min="1" max="31" />, - <input type="number" size="4" maxlength="4" autocomplete="off" class="date-input year" data-component="year" min="<?php echo esc_attr( date( 'Y' ) ); ?>" max="9999" /> - @ <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input hour" data-component="hour" min="0" max="23" />:<?php - ?><input type="number" size="2" maxlength="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59" /> + <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input day" data-component="day" min="1" max="31" value="{{ data.day }}" />, + <input type="number" size="4" maxlength="4" autocomplete="off" class="date-input year" data-component="year" min="<?php echo esc_attr( date( 'Y' ) ); ?>" value="{{ data.year }}" max="9999" /> + @ <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input hour" data-component="hour" min="0" max="23" value="{{ data.hour }}" />:<?php + ?><input type="number" size="2" maxlength="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59" value="{{ data.minute }}" /> </div> </div> </script> @@ -1127,6 +1146,28 @@ public function render_templates() { <?php } + + /** + * Format GMT Offset. + * + * @see wp_timezone_choice() + * @param float $offset Offset in hours. + * @return string Formatted offset. + */ + public function format_gmt_offset( $offset ) { + if ( 0 <= $offset ) { + $formatted_offset = '+' . (string) $offset; + } else { + $formatted_offset = (string) $offset; + } + $formatted_offset = str_replace( + array( '.25', '.5', '.75' ), + array( ':15', ':30', ':45' ), + $formatted_offset + ); + return $formatted_offset; + } + /** * Generate options for the month Select. * @@ -1149,4 +1190,30 @@ public function get_month_choices() { } return array( 'month_choices' => $months ); } + + /** + * Override default date values to a post. + * + * @param \WP_Post $post Post. + * @return \WP_Post Object if the post data did not apply. + */ + public function override_post_date_default_data( \WP_Post &$post ) { + if ( ! is_array( $post ) ) { + // Make sure that empty dates are not used in case of setting invalidity. + $empty_date = '0000-00-00 00:00:00'; + if ( $empty_date === $post->post_date ) { + $post->post_date = current_time( 'mysql', false ); + } + if ( $empty_date === $post->post_date_gmt ) { + $post->post_date_gmt = current_time( 'mysql', true ); + } + if ( $empty_date === $post->post_modified ) { + $post->post_modified = current_time( 'mysql', false ); + } + if ( $empty_date === $post->post_modified_gmt ) { + $post->post_modified_gmt = current_time( 'mysql', true ); + } + } + return $post; + } } From c744de879e214ef225a910651c5696ac876340d6 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Tue, 2 Aug 2016 13:25:16 +0530 Subject: [PATCH 04/59] Update publish date from update call and add js update function to update UI --- js/customize-snapshots.js | 57 +++++++++++++++++++----- php/class-customize-snapshot-manager.php | 2 +- 2 files changed, 46 insertions(+), 13 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index dc64e5ee..5efe655a 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -154,21 +154,25 @@ component.dateComponentInputs = {}; + component.snapshotScheduleBox = {}; + component.addSlideDown = function slideDown() { var snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), - snapshotScheduleBox; + snapshotScheduleBox = component.snapshotScheduleBox; component.snapshotSlideDownToggle.click( function( e ) { var customizeInfo = $( '#customize-info' ); - if ( ! snapshotScheduleBox ) { + if ( _.isEmpty( snapshotScheduleBox ) ) { component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); component.dateInputs = snapshotScheduleBox.find( '.date-input' ); component.dateInputs.each( function() { - var input = $( this ), componentName; - componentName = input.data( 'component' ); - component.dateComponentInputs[ componentName ] = input; + var input = $( this ), componentName; + componentName = input.data( 'component' ); + component.dateComponentInputs[componentName] = input; } ); snapshotScheduleBox.insertBefore( customizeInfo ); + component.snapshotScheduleBox = snapshotScheduleBox; + component.snapshotEditLink = snapshotScheduleBox.find( 'a' ); } else { // Todo need to update in case of dynamic section. @@ -176,6 +180,39 @@ } e.preventDefault(); } ); + + api.state( 'snapshot-saved' ).bind( function( saved ) { + if ( saved ) { + component.updateSnapshotScheduleBox(); + } + } ); + + api.state( 'saved' ).bind( function( saved ) { + if ( saved && ! _.isEmpty( component.snapshotScheduleBox ) ) { + component.snapshotScheduleBox.hide(); + } + } ); + + api.state( 'snapshot-exists' ).bind( function( exists ) { + if ( exists && ! _.isEmpty( component.snapshotScheduleBox ) ) { + component.updateSnapshotScheduleBox(); + } + } ); + + }; + + component.updateSnapshotScheduleBox = function updateSnapshotScheduleBox() { + var parsed; + if ( _.isEmpty( component.snapshotScheduleBox ) ) { + return; + } + + // Update date controls. + component.snapshotEditLink.attr( 'href', component.data.editLink ); + parsed = component.parseDateTime( component.data.snapshotPublishDate ); + _.each( component.snapshotScheduleBox, function populateInput( node, component ) { + $( node ).val( parsed[component] ); + } ); }; /** @@ -203,7 +240,6 @@ snapshotSlideDownToggle = $( $.trim( snapshotSlideDownToggleTemplate( {} ) ) ); snapshotSlideDownToggle.insertAfter( snapshotButton ); - snapshotEditLink = snapshotSlideDownToggle.find( 'a' ); component.snapshotSlideDownToggle = snapshotSlideDownToggle; if ( ! component.data.editLink ) { snapshotSlideDownToggle.hide(); @@ -214,9 +250,6 @@ api.state( 'snapshot-saved' ).bind( function( saved ) { snapshotButton.prop( 'disabled', saved ); - if ( saved ) { - snapshotEditLink.attr( 'href', component.data.editLink ); - } } ); api.state( 'saved' ).bind( function( saved ) { @@ -233,9 +266,6 @@ if ( exists ) { buttonText = component.data.i18n.updateButton; permsMsg = component.data.i18n.permsMsg.update; - if ( component.data.editLink ) { - snapshotEditLink.attr( 'href', component.data.editLink ); - } } else { buttonText = component.data.i18n.saveButton; permsMsg = component.data.i18n.permsMsg.save; @@ -336,6 +366,9 @@ if ( response.edit_link ) { component.data.editLink = response.edit_link; } + if ( response.snapshot_publish_date ) { + component.data.snapshotPublishDate = response.snapshot_publish_date; + } // @todo Remove privateness from _handleSettingValidities in Core. if ( api._handleSettingValidities && response.setting_validities ) { diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 74d8db2c..4618ac04 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -943,7 +943,7 @@ function( $value ) { $post = $this->snapshot->post(); if ( $post ) { $data['edit_link'] = get_edit_post_link( $post, 'raw' ); - $data['snapshotPublishDate'] = $post->post_date_gmt; + $data['snapshot_publish_date'] = $post->post_date_gmt; } if ( is_wp_error( $r ) ) { From 9766502d153601c17fc874daa332082a003df8ad Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Tue, 2 Aug 2016 21:37:27 +0530 Subject: [PATCH 05/59] Working prototype for scheduling UI in customizer --- js/customize-snapshots.js | 108 +++++++++++++++++++++-- php/class-customize-snapshot-manager.php | 27 ++++-- php/class-post-type.php | 4 + 3 files changed, 127 insertions(+), 12 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 5efe655a..b5d4c1e8 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -12,7 +12,17 @@ component = api.Snapshots; - component.data = {}; + component.data = { + action: '', + uuid: '', + editLink: '', + snapshotPublishDate: '', + currentUserCanPublish: '', + initialServerDate: '', + initialServerTimestamp: 0, + initialClientTimestamp: ( new Date() ).valueOf(), + i18n: '' + }; if ( 'undefined' !== typeof _customizeSnapshots ) { _.extend( component.data, _customizeSnapshots ); @@ -43,8 +53,19 @@ component.addSlideDown(); $( '#snapshot-save' ).on( 'click', function( event ) { + var scheduleDate; event.preventDefault(); - component.sendUpdateSnapshotRequest( { status: 'draft' } ); + if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleBox ) && component.getDateFromInputs() ) { + + // Todo: If date is in future make status schedule and pass date with it. Or maybe handle that in php? + scheduleDate = component.getDateFromInputs(); + component.sendUpdateSnapshotRequest( { + status: 'future', + publish_date: component.formatDate( scheduleDate ) + } ); + } else { + component.sendUpdateSnapshotRequest( { status: 'draft' } ); + } } ); $( '#snapshot-submit' ).on( 'click', function( event ) { event.preventDefault(); @@ -162,6 +183,9 @@ component.snapshotSlideDownToggle.click( function( e ) { var customizeInfo = $( '#customize-info' ); if ( _.isEmpty( snapshotScheduleBox ) ) { + if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + component.data.snapshotPublishDate = component.getCurrentTime(); + } component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); component.dateInputs = snapshotScheduleBox.find( '.date-input' ); @@ -173,6 +197,22 @@ snapshotScheduleBox.insertBefore( customizeInfo ); component.snapshotScheduleBox = snapshotScheduleBox; component.snapshotEditLink = snapshotScheduleBox.find( 'a' ); + component.dateInputs.on( 'input', function hydrateInputValues() { + var parsed, setComponentInputValue; + + // Todo Check if date is in future?. + if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + parsed = component.parseDateTime( component.getCurrentTime() ); + setComponentInputValue = function( value, inputName ) { + var input = component.dateComponentInputs[inputName]; + if ( input && ! input.is( 'select' ) && '' === input.val() ) { + input.val( value ); + } + }; + _.each( parsed, setComponentInputValue ); + } + component.populateSetting(); + } ); } else { // Todo need to update in case of dynamic section. @@ -206,6 +246,9 @@ if ( _.isEmpty( component.snapshotScheduleBox ) ) { return; } + if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + component.data.snapshotPublishDate = component.getCurrentTime(); + } // Update date controls. component.snapshotEditLink.attr( 'href', component.data.editLink ); @@ -349,14 +392,15 @@ options ); + data = _.extend( args, { + nonce: api.settings.nonce.snapshot, + customize_snapshot_uuid: component.data.uuid + } ); + data = _.extend( {}, api.previewer.query(), - { - nonce: api.settings.nonce.snapshot, - customize_snapshot_uuid: component.data.uuid, - status: args.status - } + data ); request = wp.ajax.post( 'customize_update_snapshot', data ); @@ -523,6 +567,56 @@ return formattedDate; }; + /** + * Populate setting value from the inputs. + * + * @returns {boolean} Whether the date inputs currently represent a valid date. + */ + component.populateSetting = function populateSetting() { + var date, remainingTime, save; + date = component.getDateFromInputs(); + if ( ! date ) { + return false; + } else { + remainingTime = ( new Date( date ) ).valueOf(); + remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); + remainingTime = Math.ceil( remainingTime / 1000 ); + save = $( '#snapshot-save' ); + if ( remainingTime > 0 ) { + + // Change update button to schedule. + if ( save.length ) { + save.html( component.data.i18n.scheduleButton ); + save.prop( 'disabled', false ); + } + } else { + if ( save.length ) { + save.html( component.data.i18n.updateButton ); + + //Todo If snapshot don't have changes make button disable. + } + } + date.setSeconds( 0 ); + component.data.snapshotPublishDate = component.formatDate( date ); + return true; + } + }; + + /** + * Get current date/time in the site's timezone, as does the current_time( 'mysql', false ) function in PHP. + * + * @returns {string} Current datetime string. + */ + component.getCurrentTime = function getCurrentTime() { + var currentDate, currentTimestamp, timestampDifferential; + currentTimestamp = ( new Date() ).valueOf(); + currentDate = new Date( component.data.initialServerDate ); + timestampDifferential = currentTimestamp - component.data.initialClientTimestamp; + timestampDifferential += component.data.initialClientTimestamp - component.data.initialServerTimestamp; + currentDate.setTime( currentDate.getTime() + timestampDifferential ); + return component.formatDate( currentDate ); + }; + component.init(); } )( wp.customize, jQuery ); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 4618ac04..6d8179d9 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -537,11 +537,14 @@ public function enqueue_scripts() { 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), 'editLink' => $this->snapshot ? get_edit_post_link( $post, 'raw' ) : '', - 'snapshotPublishDate' => $this->snapshot ? $post->post_date_gmt : '', + 'snapshotPublishDate' => $this->snapshot ? $post->post_date : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), + 'initialServerDate' => current_time( 'mysql', false ), + 'initialServerTimestamp' => floor( microtime( true ) * 1000 ), 'i18n' => array( 'saveButton' => __( 'Save', 'customize-snapshots' ), 'updateButton' => __( 'Update', 'customize-snapshots' ), + 'scheduleButton' => __( 'Schedule', 'customize-snapshots' ), 'submit' => __( 'Submit', 'customize-snapshots' ), 'submitted' => __( 'Submitted', 'customize-snapshots' ), 'publish' => __( 'Publish', 'customize-snapshots' ), @@ -886,10 +889,19 @@ public function handle_update_snapshot_request() { } else { $status = 'draft'; } - if ( ! in_array( $status, array( 'draft', 'pending' ), true ) ) { + if ( ! in_array( $status, array( 'draft', 'pending', 'future' ), true ) ) { status_header( 400 ); wp_send_json_error( 'bad_status' ); } + $publish_date = isset( $_POST['publish_date'] ) ? $_POST['publish_date'] : ''; + if ( 'future' === $status ) { + $publish_date_obj = new \DateTime( $publish_date ); + $current_date = new \DateTime(); + if ( empty( $publish_date ) || ! $publish_date_obj || $publish_date > $current_date ) { + status_header( 400 ); + wp_send_json_error( 'bad_schedule_time' ); + } + } // Prevent attempting to modify a "locked" snapshot (a published one). $post = $this->snapshot->post(); @@ -935,10 +947,15 @@ function( $value ) { $data['errors'] = $this->prepare_errors_for_response( $r['errors'] ); wp_send_json_error( $data ); } - - $r = $this->snapshot->save( array( + $args = array( 'status' => $status, - ) ); + ); + + if ( isset( $publish_date_obj ) && 'future' === $status ) { + $args['post_date'] = $publish_date_obj->format( 'Y-m-d H:i:s' ); + $args['edit_date'] = current_time( 'mysql' ); + } + $r = $this->snapshot->save( $args ); $post = $this->snapshot->post(); if ( $post ) { diff --git a/php/class-post-type.php b/php/class-post-type.php index e137b988..575cf48a 100644 --- a/php/class-post-type.php +++ b/php/class-post-type.php @@ -508,6 +508,10 @@ public function save( array $args ) { ), ); if ( ! empty( $args['status'] ) ) { + if ( isset( $args['post_date'], $post_arr['edit_date'] ) && 'future' === $args['status'] ) { + $post_arr['post_date'] = $args['post_date']; + $post_arr['edit_date'] = $args['edit_date']; + } if ( ! get_post_status_object( $args['status'] ) ) { return new \WP_Error( 'bad_status' ); } From 95e05739734418a5c7ab640d1fb8b30ef9f11ac6 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Tue, 2 Aug 2016 21:47:59 +0530 Subject: [PATCH 06/59] Fix scheduling edit_date issue --- php/class-post-type.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-post-type.php b/php/class-post-type.php index 575cf48a..349f6b6a 100644 --- a/php/class-post-type.php +++ b/php/class-post-type.php @@ -508,7 +508,7 @@ public function save( array $args ) { ), ); if ( ! empty( $args['status'] ) ) { - if ( isset( $args['post_date'], $post_arr['edit_date'] ) && 'future' === $args['status'] ) { + if ( isset( $args['post_date'], $args['edit_date'] ) && 'future' === $args['status'] ) { $post_arr['post_date'] = $args['post_date']; $post_arr['edit_date'] = $args['edit_date']; } From 6492b665c31cc152f738715e1ae18ca3d85561d9 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 16:38:07 +0530 Subject: [PATCH 07/59] Disable update button if snapshot schedule date changed --- js/customize-snapshots.js | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index b5d4c1e8..1706f292 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -21,7 +21,8 @@ initialServerDate: '', initialServerTimestamp: 0, initialClientTimestamp: ( new Date() ).valueOf(), - i18n: '' + i18n: {}, + snapshotHaveChange: false }; if ( 'undefined' !== typeof _customizeSnapshots ) { @@ -227,6 +228,10 @@ } } ); + api.bind( 'change', function() { + component.data.snapshotHaveChange = true; + } ); + api.state( 'saved' ).bind( function( saved ) { if ( saved && ! _.isEmpty( component.snapshotScheduleBox ) ) { component.snapshotScheduleBox.hide(); @@ -592,8 +597,7 @@ } else { if ( save.length ) { save.html( component.data.i18n.updateButton ); - - //Todo If snapshot don't have changes make button disable. + save.prop( 'disabled', ! component.data.snapshotHaveChange ); } } date.setSeconds( 0 ); From 7deb45669e2ce1a91b80dc625ef69b2b18c94c65 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 16:57:01 +0530 Subject: [PATCH 08/59] Schedule request only if schedule date is in future --- js/customize-snapshots.js | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 1706f292..5e900342 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -56,9 +56,7 @@ $( '#snapshot-save' ).on( 'click', function( event ) { var scheduleDate; event.preventDefault(); - if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleBox ) && component.getDateFromInputs() ) { - - // Todo: If date is in future make status schedule and pass date with it. Or maybe handle that in php? + if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleBox ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { scheduleDate = component.getDateFromInputs(); component.sendUpdateSnapshotRequest( { status: 'future', @@ -578,16 +576,13 @@ * @returns {boolean} Whether the date inputs currently represent a valid date. */ component.populateSetting = function populateSetting() { - var date, remainingTime, save; + var date, save; date = component.getDateFromInputs(); if ( ! date ) { return false; } else { - remainingTime = ( new Date( date ) ).valueOf(); - remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); - remainingTime = Math.ceil( remainingTime / 1000 ); save = $( '#snapshot-save' ); - if ( remainingTime > 0 ) { + if ( component.isScheduleDateFuture() ) { // Change update button to schedule. if ( save.length ) { @@ -606,6 +601,22 @@ } }; + /** + * Check if snapshot schedule date is in future date + * @returns {boolean} + */ + component.isScheduleDateFuture = function isScheduleDateFuture() { + var date, remainingTime; + date = component.getDateFromInputs(); + if ( ! date ) { + return false; + } + remainingTime = ( new Date( date ) ).valueOf(); + remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); + remainingTime = Math.ceil( remainingTime / 1000 ); + return remainingTime > 0; + }; + /** * Get current date/time in the site's timezone, as does the current_time( 'mysql', false ) function in PHP. * From 136ed7d808094d667099de854f1d6af57dbc7bd9 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 16:59:11 +0530 Subject: [PATCH 09/59] rename variable to isSnapshotHasUnsavedChanges --- js/customize-snapshots.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 5e900342..3c458c15 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -22,7 +22,7 @@ initialServerTimestamp: 0, initialClientTimestamp: ( new Date() ).valueOf(), i18n: {}, - snapshotHaveChange: false + isSnapshotHasUnsavedChanges: false }; if ( 'undefined' !== typeof _customizeSnapshots ) { @@ -227,7 +227,7 @@ } ); api.bind( 'change', function() { - component.data.snapshotHaveChange = true; + component.data.isSnapshotHasUnsavedChanges = true; } ); api.state( 'saved' ).bind( function( saved ) { @@ -592,7 +592,7 @@ } else { if ( save.length ) { save.html( component.data.i18n.updateButton ); - save.prop( 'disabled', ! component.data.snapshotHaveChange ); + save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); } } date.setSeconds( 0 ); From 9e043955514ee464f037845010b18c0ee39b8ebf Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 18:22:05 +0530 Subject: [PATCH 10/59] Add populateInputs and refactor populateSetting --- js/customize-snapshots.js | 42 +++++++++++++++++++++++++-------------- 1 file changed, 27 insertions(+), 15 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 3c458c15..05767780 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -197,21 +197,11 @@ component.snapshotScheduleBox = snapshotScheduleBox; component.snapshotEditLink = snapshotScheduleBox.find( 'a' ); component.dateInputs.on( 'input', function hydrateInputValues() { - var parsed, setComponentInputValue; - - // Todo Check if date is in future?. - if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { - parsed = component.parseDateTime( component.getCurrentTime() ); - setComponentInputValue = function( value, inputName ) { - var input = component.dateComponentInputs[inputName]; - if ( input && ! input.is( 'select' ) && '' === input.val() ) { - input.val( value ); - } - }; - _.each( parsed, setComponentInputValue ); - } component.populateSetting(); } ); + component.dateInputs.on( 'blur', function hydrateInputValues() { + component.populateInputs(); + } ); } else { // Todo need to update in case of dynamic section. @@ -570,6 +560,30 @@ return formattedDate; }; + /** + * Populate inputs from the setting value, if none of them are currently focused. + * + * @returns {boolean} Whether the inputs were populated. + */ + component.populateInputs = function populateInputs() { + var parsed, setComponentInputValue; + if ( component.dateInputs.is( ':focus' ) || '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + return false; + } + parsed = component.parseDateTime( component.data.snapshotPublishDate ); + if ( ! parsed ) { + return false; + } + setComponentInputValue = function( value, inputName ) { + var input = component.dateComponentInputs[inputName]; + if ( input && ! input.is( 'select' ) && '' === input.val() ) { + input.val( value ); + } + }; + _.each( parsed, setComponentInputValue ); + return true; + }; + /** * Populate setting value from the inputs. * @@ -596,8 +610,6 @@ } } date.setSeconds( 0 ); - component.data.snapshotPublishDate = component.formatDate( date ); - return true; } }; From 132dc8a1c7dec506d2927c8ad4c8ad047c75cb21 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 20:23:56 +0530 Subject: [PATCH 11/59] Change button text to schedule if snapshot post status is schedule --- js/customize-snapshots.js | 14 ++++++++++++-- php/class-customize-snapshot-manager.php | 1 + 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 05767780..d44ecaed 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -17,6 +17,7 @@ uuid: '', editLink: '', snapshotPublishDate: '', + snapshotStatus: '', currentUserCanPublish: '', initialServerDate: '', initialServerTimestamp: 0, @@ -260,12 +261,21 @@ var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), snapshotSlideDownToggleTemplate = wp.template( 'snapshot-toggle-button' ), - snapshotButton, submitButton, data, setPreviewLinkHref, snapshotSlideDownToggle, snapshotEditLink; + snapshotButton, submitButton, data, setPreviewLinkHref, snapshotSlideDownToggle, snapshotButtonText; // Save/update button. snapshotButton = wp.template( 'snapshot-save' ); + if ( api.state( 'snapshot-exists' ).get() ) { + if ( 'future' === component.data.snapshotStatus ) { + snapshotButtonText = component.data.i18n.scheduleButton; + } else { + snapshotButtonText = component.data.i18n.updateButton; + } + } else { + snapshotButtonText = component.data.i18n.saveButton; + } data = { - buttonText: api.state( 'snapshot-exists' ).get() ? component.data.i18n.updateButton : component.data.i18n.saveButton + buttonText: snapshotButtonText }; snapshotButton = $( $.trim( snapshotButton( data ) ) ); if ( ! component.data.currentUserCanPublish ) { diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 6d8179d9..aaba0dbb 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -538,6 +538,7 @@ public function enqueue_scripts() { 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), 'editLink' => $this->snapshot ? get_edit_post_link( $post, 'raw' ) : '', 'snapshotPublishDate' => $this->snapshot ? $post->post_date : '', + 'snapshotStatus' => $this->snapshot ? $post->post_status : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), 'initialServerDate' => current_time( 'mysql', false ), 'initialServerTimestamp' => floor( microtime( true ) * 1000 ), From 8f20ab70e55870ec689c5a62cb662449a6c61b75 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 3 Aug 2016 23:58:51 +0530 Subject: [PATCH 12/59] Add remain time to publish text --- css/customize-snapshots.css | 5 +++- js/customize-snapshots.js | 30 ++++++++++++++++++++++-- php/class-customize-snapshot-manager.php | 26 ++++++++++++++++++-- 3 files changed, 56 insertions(+), 5 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 39d3ef12..6a02926a 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -107,7 +107,7 @@ padding: 10px; } -#customize-schedule-box span{ +#customize-schedule-box div.preview-notice{ font-size: 13px; line-height: 24px; } @@ -121,4 +121,7 @@ left: -100%; width: 100%; position: relative; +} +#customize-schedule-box .snapshot-description{ + font-style: normal; } \ No newline at end of file diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index d44ecaed..fb5384d2 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -188,21 +188,25 @@ } component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); + snapshotScheduleBox.insertBefore( customizeInfo ); component.dateInputs = snapshotScheduleBox.find( '.date-input' ); + component.scheduledCountdownContainer = snapshotScheduleBox.find( '.scheduled-countdown' ); + component.scheduledCountdownTemplate = wp.template( 'snapshot-scheduled-countdown' ); + component.snapshotScheduleBox = snapshotScheduleBox; component.dateInputs.each( function() { var input = $( this ), componentName; componentName = input.data( 'component' ); component.dateComponentInputs[componentName] = input; } ); - snapshotScheduleBox.insertBefore( customizeInfo ); - component.snapshotScheduleBox = snapshotScheduleBox; component.snapshotEditLink = snapshotScheduleBox.find( 'a' ); component.dateInputs.on( 'input', function hydrateInputValues() { component.populateSetting(); } ); component.dateInputs.on( 'blur', function hydrateInputValues() { component.populateInputs(); + component.populateSetting(); } ); + component.updateScheduledCountdown(); } else { // Todo need to update in case of dynamic section. @@ -619,6 +623,7 @@ save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); } } + component.updateScheduledCountdown(); date.setSeconds( 0 ); } }; @@ -654,6 +659,27 @@ return component.formatDate( currentDate ); }; + /** + * Update the scheduled countdown. + * + * Hides countdown if post_status is not already future. + * Toggles the countdown if there is no remaining time. + * + * @returns {void} + */ + component.updateScheduledCountdown = function updateScheduledCountdown() { + var remainingTime; + remainingTime = component.getDateFromInputs().valueOf(); + remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); + remainingTime = Math.ceil( remainingTime / 1000 ); + if ( remainingTime > 0 ) { + component.scheduledCountdownContainer.text( component.scheduledCountdownTemplate( { remainingTime: remainingTime } ) ); + component.scheduledCountdownContainer.show(); + } else { + component.scheduledCountdownContainer.hide(); + } + }; + component.init(); } )( wp.customize, jQuery ); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index aaba0dbb..0500af30 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1097,8 +1097,8 @@ public function render_templates() { <script type="text/html" id="tmpl-snapshot-schedule-accordion"> <div id="customize-schedule-box" class="accordion-section"> <div class="accordion-section-title"> - <span class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></span> - <span class="description customize-control-description"> + <div class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></div> + <span class="description snapshot-description"> <?php $tz_string = get_option( 'timezone_string' ); if ( $tz_string ) { @@ -1115,6 +1115,7 @@ public function render_templates() { $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); } ?> + <span class="scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> <a href={{ data.editLink }} class="dashicons dashicons-edit" aria-expanded="false"></a> @@ -1144,6 +1145,27 @@ public function render_templates() { </div> </script> + <script id="tmpl-snapshot-scheduled-countdown" type="text/html"> + <# if ( data.remainingTime < 2 * 60 ) { #> + <?php esc_html_e( 'This is scheduled for publishing in about a minute.', 'customize-snapshots' ); ?> + <# } else if ( data.remainingTime < 60 * 60 ) { #> + <?php + /* translators: %s is a placeholder for the Underscore template var */ + echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s minutes.', 'customize-snapshots' ), '{{ Math.ceil( data.remainingTime / 60 ) }}' ); + ?> + <# } else if ( data.remainingTime < 24 * 60 * 60 ) { #> + <?php + /* translators: %s is a placeholder for the Underscore template var */ + echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s hours.', 'customize-snapshots' ), '{{ Math.round( data.remainingTime / 60 / 60 * 10 ) / 10 }}' ); + ?> + <# } else { #> + <?php + /* translators: %s is a placeholder for the Underscore template var */ + echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s days.', 'customize-snapshots' ), '{{ Math.round( data.remainingTime / 60 / 60 / 24 * 10 ) / 10 }}' ); + ?> + <# } #> + </script> + <script type="text/html" id="tmpl-snapshot-save"> <button id="snapshot-save" class="button button-secondary"> {{ data.buttonText }} From 0eba8996e73df3a1cd38def6e72ad7bb55a5f8ac Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 00:45:28 +0530 Subject: [PATCH 13/59] Add rest button --- css/customize-snapshots.css | 7 ++++++- js/customize-snapshots.js | 23 ++++++++++++++++++++--- php/class-customize-snapshot-manager.php | 7 +++++-- 3 files changed, 31 insertions(+), 6 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 6a02926a..d06ecb62 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -91,7 +91,7 @@ #customize-schedule-box .accordion-section-title:after{ z-index: -1; } -#customize-schedule-box a{ +#customize-schedule-box a.snapshot-edit-link{ position: absolute; top: 4px; right: 1px; @@ -124,4 +124,9 @@ } #customize-schedule-box .snapshot-description{ font-style: normal; +} + +#customize-schedule-box .wrap-reset-time{ + font-weight: normal; + font-size: 75%; } \ No newline at end of file diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index fb5384d2..5feb6eab 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -191,6 +191,8 @@ snapshotScheduleBox.insertBefore( customizeInfo ); component.dateInputs = snapshotScheduleBox.find( '.date-input' ); component.scheduledCountdownContainer = snapshotScheduleBox.find( '.scheduled-countdown' ); + component.resetTimeButton = snapshotScheduleBox.find( '.reset-time' ); + component.resetTimeWrap = snapshotScheduleBox.find( '.wrap-reset-time' ); component.scheduledCountdownTemplate = wp.template( 'snapshot-scheduled-countdown' ); component.snapshotScheduleBox = snapshotScheduleBox; component.dateInputs.each( function() { @@ -207,6 +209,11 @@ component.populateSetting(); } ); component.updateScheduledCountdown(); + component.resetTimeButton.on( 'click', function( e ) { + component.updateSnapshotScheduleBox(); + component.resetTimeWrap.hide(); + e.preventDefault(); + } ); } else { // Todo need to update in case of dynamic section. @@ -251,7 +258,7 @@ // Update date controls. component.snapshotEditLink.attr( 'href', component.data.editLink ); parsed = component.parseDateTime( component.data.snapshotPublishDate ); - _.each( component.snapshotScheduleBox, function populateInput( node, component ) { + _.each( component.dateComponentInputs, function populateInput( node, component ) { $( node ).val( parsed[component] ); } ); }; @@ -604,18 +611,23 @@ * @returns {boolean} Whether the date inputs currently represent a valid date. */ component.populateSetting = function populateSetting() { - var date, save; + var date, save, isScheduleDateUpdated; date = component.getDateFromInputs(); if ( ! date ) { return false; } else { save = $( '#snapshot-save' ); + isScheduleDateUpdated = component.formatDate( date ) !== component.data.snapshotPublishDate; if ( component.isScheduleDateFuture() ) { // Change update button to schedule. if ( save.length ) { save.html( component.data.i18n.scheduleButton ); - save.prop( 'disabled', false ); + if ( isScheduleDateUpdated || component.data.isSnapshotHasUnsavedChanges ) { + save.prop( 'disabled', false ); + } else { + save.prop( 'disabled', true ); + } } } else { if ( save.length ) { @@ -625,6 +637,11 @@ } component.updateScheduledCountdown(); date.setSeconds( 0 ); + if ( isScheduleDateUpdated ) { + component.resetTimeWrap.show(); + } else { + component.resetTimeWrap.hide(); + } } }; diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 0500af30..7f1a0d58 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1097,7 +1097,10 @@ public function render_templates() { <script type="text/html" id="tmpl-snapshot-schedule-accordion"> <div id="customize-schedule-box" class="accordion-section"> <div class="accordion-section-title"> - <div class="preview-notice"><strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong></div> + <div class="preview-notice"> + <strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong> + <span class="wrap-reset-time">(<a href="#" class="reset-time"><?php esc_html_e( 'Reset', 'customize-posts' ) ?></a>)</span> + </div> <span class="description snapshot-description"> <?php $tz_string = get_option( 'timezone_string' ); @@ -1118,7 +1121,7 @@ public function render_templates() { <span class="scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> - <a href={{ data.editLink }} class="dashicons dashicons-edit" aria-expanded="false"></a> + <a href={{ data.editLink }} class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> </div> <div class="customize-snapshot-control"> <# _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); From d1fa9d52f6defa68c315497dc77f6b22774e8ba2 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 3 Aug 2016 22:09:32 -0700 Subject: [PATCH 14/59] Fix text domain --- php/class-customize-snapshot-manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 7f1a0d58..50dfc48a 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1099,7 +1099,7 @@ public function render_templates() { <div class="accordion-section-title"> <div class="preview-notice"> <strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong> - <span class="wrap-reset-time">(<a href="#" class="reset-time"><?php esc_html_e( 'Reset', 'customize-posts' ) ?></a>)</span> + <span class="wrap-reset-time">(<a href="#" class="reset-time"><?php esc_html_e( 'Reset', 'customize-snapshots' ) ?></a>)</span> </div> <span class="description snapshot-description"> <?php From 26399a1b4b5149b58c97a800cdcb44fdb95cf7ba Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 3 Aug 2016 22:21:49 -0700 Subject: [PATCH 15/59] Install eslint so checks can run --- package.json | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 3ad081a1..086a2aa9 100644 --- a/package.json +++ b/package.json @@ -1,22 +1,23 @@ { - "name": "customize-snapshots", - "title": "Customize Snapshots", - "homepage": "https://github.com/xwp/wp-customize-snapshots", - "repository": { - "type": "git", - "url": "https://github.com/xwp/wp-customize-snapshots.git" - }, - "author": "XWP", - "license": "GPL-2.0+", - "devDependencies": { - "grunt": "~0.4.5", - "grunt-checktextdomain": "~1.0.0", - "grunt-contrib-clean": "~1.0.0", - "grunt-contrib-copy": "~1.0.0", - "grunt-contrib-cssmin": "~1.0.1", - "grunt-contrib-jshint": "~1.0.0", - "grunt-contrib-uglify": "~1.0.1", - "grunt-shell": "~1.3.0", - "grunt-wp-deploy": "^1.1.0" - } + "name": "customize-snapshots", + "title": "Customize Snapshots", + "homepage": "https://github.com/xwp/wp-customize-snapshots", + "repository": { + "type": "git", + "url": "https://github.com/xwp/wp-customize-snapshots.git" + }, + "author": "XWP", + "license": "GPL-2.0+", + "devDependencies": { + "eslint": "^3.2.2", + "grunt": "~0.4.5", + "grunt-checktextdomain": "~1.0.0", + "grunt-contrib-clean": "~1.0.0", + "grunt-contrib-copy": "~1.0.0", + "grunt-contrib-cssmin": "~1.0.1", + "grunt-contrib-jshint": "~1.0.0", + "grunt-contrib-uglify": "~1.0.1", + "grunt-shell": "~1.3.0", + "grunt-wp-deploy": "^1.1.0" + } } From 94d234b8b3eaea80db336c94bc7b3f8334a5f506 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 3 Aug 2016 22:28:04 -0700 Subject: [PATCH 16/59] Bump node.js to 5.x on Travis for sake of ESLint --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index 003dcbac..276d86e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,6 +4,9 @@ language: - php - node_js +node_js: + - 5 + php: - 5.3 - 7.0 From 6460b48d07fb3fcb496c2b4d78aea848952f0aec Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 3 Aug 2016 22:37:23 -0700 Subject: [PATCH 17/59] Add nvm use 4 to Travis --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 276d86e3..afd32eaf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,9 +4,6 @@ language: - php - node_js -node_js: - - 5 - php: - 5.3 - 7.0 @@ -19,6 +16,7 @@ env: - WP_VERSION=latest WP_MULTISITE=1 install: + - nvm use 4 - export DEV_LIB_PATH=dev-lib - if [ ! -e "$DEV_LIB_PATH" ] && [ -L .travis.yml ]; then export DEV_LIB_PATH=$( dirname $( readlink .travis.yml ) ); fi - source $DEV_LIB_PATH/travis.install.sh From 345294a25c388cea88ae25a18b9bb2c96e73a689 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 3 Aug 2016 22:43:21 -0700 Subject: [PATCH 18/59] Do nvm install before nvm use --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index afd32eaf..1dbd3883 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,7 +16,7 @@ env: - WP_VERSION=latest WP_MULTISITE=1 install: - - nvm use 4 + - nvm install 4 && nvm use 4 - export DEV_LIB_PATH=dev-lib - if [ ! -e "$DEV_LIB_PATH" ] && [ -L .travis.yml ]; then export DEV_LIB_PATH=$( dirname $( readlink .travis.yml ) ); fi - source $DEV_LIB_PATH/travis.install.sh From 6311e36085d8e4951bd4888dd22644089d6bba38 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 12:22:12 +0530 Subject: [PATCH 19/59] Fix eslint issues --- js/customize-snapshots.js | 74 ++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 5feb6eab..232227d8 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -1,5 +1,7 @@ /* global jQuery, _customizeSnapshots */ /* eslint-disable no-extra-parens */ +/* eslint no-magic-numbers: ["error", { "ignore": [-1,0,1,1000] }] */ +/* eslint complexity: ["error", 7] */ ( function( api, $ ) { 'use strict'; @@ -52,7 +54,7 @@ component.extendPreviewerQuery(); component.addButtons(); - component.addSlideDown(); + component.addSnapshotScheduleBox(); $( '#snapshot-save' ).on( 'click', function( event ) { var scheduleDate; @@ -177,7 +179,12 @@ component.snapshotScheduleBox = {}; - component.addSlideDown = function slideDown() { + /** + * Renders Snapshot Schedule Box and handles it's events. + * + * @returns {void} + */ + component.addSnapshotScheduleBox = function addSnapshotScheduleBox() { var snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), snapshotScheduleBox = component.snapshotScheduleBox; component.snapshotSlideDownToggle.click( function( e ) { @@ -209,10 +216,10 @@ component.populateSetting(); } ); component.updateScheduledCountdown(); - component.resetTimeButton.on( 'click', function( e ) { + component.resetTimeButton.on( 'click', function( event ) { component.updateSnapshotScheduleBox(); component.resetTimeWrap.hide(); - e.preventDefault(); + event.preventDefault(); } ); } else { @@ -246,6 +253,11 @@ }; + /** + * Updates snapshot schedule box with component.data + * + * @returns {void} + */ component.updateSnapshotScheduleBox = function updateSnapshotScheduleBox() { var parsed; if ( _.isEmpty( component.snapshotScheduleBox ) ) { @@ -258,8 +270,8 @@ // Update date controls. component.snapshotEditLink.attr( 'href', component.data.editLink ); parsed = component.parseDateTime( component.data.snapshotPublishDate ); - _.each( component.dateComponentInputs, function populateInput( node, component ) { - $( node ).val( parsed[component] ); + _.each( component.dateComponentInputs, function populateInput( node, fieldName ) { + $( node ).val( parsed[fieldName] ); } ); }; @@ -615,39 +627,37 @@ date = component.getDateFromInputs(); if ( ! date ) { return false; - } else { - save = $( '#snapshot-save' ); - isScheduleDateUpdated = component.formatDate( date ) !== component.data.snapshotPublishDate; - if ( component.isScheduleDateFuture() ) { - - // Change update button to schedule. - if ( save.length ) { - save.html( component.data.i18n.scheduleButton ); - if ( isScheduleDateUpdated || component.data.isSnapshotHasUnsavedChanges ) { - save.prop( 'disabled', false ); - } else { - save.prop( 'disabled', true ); - } - } - } else { - if ( save.length ) { - save.html( component.data.i18n.updateButton ); - save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); - } - } - component.updateScheduledCountdown(); - date.setSeconds( 0 ); - if ( isScheduleDateUpdated ) { - component.resetTimeWrap.show(); + } + save = $( '#snapshot-save' ); + isScheduleDateUpdated = component.formatDate( date ) !== component.data.snapshotPublishDate; + if ( component.isScheduleDateFuture() && save.length ) { + + // Change update button to schedule. + save.html( component.data.i18n.scheduleButton ); + if ( isScheduleDateUpdated || component.data.isSnapshotHasUnsavedChanges ) { + save.prop( 'disabled', false ); } else { - component.resetTimeWrap.hide(); + save.prop( 'disabled', true ); } + } else if ( save.length ) { + save.html( component.data.i18n.updateButton ); + save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); } + component.updateScheduledCountdown(); + date.setSeconds( 0 ); + if ( isScheduleDateUpdated ) { + component.resetTimeWrap.show(); + } else { + component.resetTimeWrap.hide(); + } + return true; + }; /** * Check if snapshot schedule date is in future date - * @returns {boolean} + * + * @returns {boolean} if date in input controls is of future */ component.isScheduleDateFuture = function isScheduleDateFuture() { var date, remainingTime; From a6c381dde8acc23313a62ad4c3b8a818c1defbf8 Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Thu, 4 Aug 2016 00:21:54 -0700 Subject: [PATCH 20/59] Fix control visbility --- css/customize-snapshots.css | 92 ++++++++-------- js/customize-snapshots.js | 131 +++++++++++++---------- php/class-customize-snapshot-manager.php | 20 ++-- 3 files changed, 129 insertions(+), 114 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index d06ecb62..8108f9cf 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -1,10 +1,12 @@ -#snapshot-preview-link, #snapshot-toggle-button { +#snapshot-preview-link, +#snapshot-schedule-button { float: right; margin-top: 13px; margin-right: 4px; color: #656a6f; } -#snapshot-toggle-button{ + +#snapshot-schedule-button { display: block; } @@ -55,43 +57,27 @@ } } -.customize-snapshot-control select, -.customize-snapshot-control input.date-input { - min-width: 10%; - width: auto; -} -.customize-snapshot-control input.date-input { - -moz-appearance: textfield; -} -.customize-snapshot-control input.date-input::-webkit-outer-spin-button, -.customize-snapshot-control input.date-input::-webkit-inner-spin-button { - -webkit-appearance: none; - margin: 0; -} - -#customize-snapshot-control{ - padding: 5px; -} - -#customize-schedule-box{ +#snapshot-schedule-section { background: #fff !important; - margin-bottom: 10px; - padding-bottom: 10px; + border-bottom: 1px solid #ddd; + line-height: 1.5; + left: 0; + top: 46px; + position: absolute; + width: 100%; + box-shadow: 0 5px 0 0 rgba(0,0,0,0.05); } -#customize-schedule-box .accordion-section-title{ - background: #fff; +#snapshot-schedule-section .snapshot-schedule-title { color: #555; - border-left: none; - border-right: none; - border-bottom: none; - cursor: default; + padding: 10px 10px 0; } -#customize-schedule-box .accordion-section-title:after{ - z-index: -1; +#snapshot-schedule-section .snapshot-schedule-title h3 { + margin: .2em 2em .75em 0; } -#customize-schedule-box a.snapshot-edit-link{ + +#snapshot-schedule-section a.snapshot-edit-link { position: absolute; top: 4px; right: 1px; @@ -107,26 +93,34 @@ padding: 10px; } -#customize-schedule-box div.preview-notice{ - font-size: 13px; - line-height: 24px; -} -#customize-schedule-box .customize-snapshot-control{ - padding: 5px; +#snapshot-schedule-section .snapshot-schedule-control { + padding: 10px; } -#customize-schedule-box .accordion-section-title{ + +#snapshot-schedule-section .accordion-section-title { padding: 10px; } -.in-sub-panel #customize-schedule-box { - left: -100%; - width: 100%; - position: relative; + +#snapshot-schedule-section .wrap-reset-time { + font-weight: normal; + font-size: 80%; + display: none; } -#customize-schedule-box .snapshot-description{ - font-style: normal; + +.snapshot-schedule-control select.date-input { + height: 28px; } -#customize-schedule-box .wrap-reset-time{ - font-weight: normal; - font-size: 75%; -} \ No newline at end of file +.snapshot-schedule-control select, +.snapshot-schedule-control input.date-input { + min-width: 10%; + width: auto; +} +.snapshot-schedule-control input.date-input { + -moz-appearance: textfield; +} +.snapshot-schedule-control input.date-input::-webkit-outer-spin-button, +.snapshot-schedule-control input.date-input::-webkit-inner-spin-button { + -webkit-appearance: none; + margin: 0; +} diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 5feb6eab..12668647 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -52,12 +52,12 @@ component.extendPreviewerQuery(); component.addButtons(); - component.addSlideDown(); + component.addSnapshotScheduleSection(); $( '#snapshot-save' ).on( 'click', function( event ) { var scheduleDate; event.preventDefault(); - if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleBox ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { + if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleSection ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { scheduleDate = component.getDateFromInputs(); component.sendUpdateSnapshotRequest( { status: 'future', @@ -175,56 +175,73 @@ component.dateComponentInputs = {}; - component.snapshotScheduleBox = {}; + component.snapshotScheduleSection = {}; - component.addSlideDown = function slideDown() { - var snapshotScheduleBoxTemplate = wp.template( 'snapshot-schedule-accordion' ), - snapshotScheduleBox = component.snapshotScheduleBox; - component.snapshotSlideDownToggle.click( function( e ) { - var customizeInfo = $( '#customize-info' ); - if ( _.isEmpty( snapshotScheduleBox ) ) { - if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { - component.data.snapshotPublishDate = component.getCurrentTime(); - } - component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); - snapshotScheduleBox = $( $.trim( snapshotScheduleBoxTemplate( component.data ) ) ); - snapshotScheduleBox.insertBefore( customizeInfo ); - component.dateInputs = snapshotScheduleBox.find( '.date-input' ); - component.scheduledCountdownContainer = snapshotScheduleBox.find( '.scheduled-countdown' ); - component.resetTimeButton = snapshotScheduleBox.find( '.reset-time' ); - component.resetTimeWrap = snapshotScheduleBox.find( '.wrap-reset-time' ); - component.scheduledCountdownTemplate = wp.template( 'snapshot-scheduled-countdown' ); - component.snapshotScheduleBox = snapshotScheduleBox; - component.dateInputs.each( function() { - var input = $( this ), componentName; - componentName = input.data( 'component' ); - component.dateComponentInputs[componentName] = input; - } ); - component.snapshotEditLink = snapshotScheduleBox.find( 'a' ); - component.dateInputs.on( 'input', function hydrateInputValues() { - component.populateSetting(); - } ); - component.dateInputs.on( 'blur', function hydrateInputValues() { - component.populateInputs(); - component.populateSetting(); - } ); - component.updateScheduledCountdown(); - component.resetTimeButton.on( 'click', function( e ) { - component.updateSnapshotScheduleBox(); - component.resetTimeWrap.hide(); - e.preventDefault(); - } ); - } else { + component.snapshotScheduleSlideToggle = function snapshotScheduleSlideToggle() { + component.snapshotScheduleSection.slideToggle( 'fast', function() { + $( this ).parent().toggleClass( 'schedule-section-open' ); + } ); + }; - // Todo need to update in case of dynamic section. - snapshotScheduleBox.slideToggle(); + /** + * Renders Snapshot Schedule Section and handles it's events. + * + * @returns {void} + */ + component.addSnapshotScheduleSection = function addSnapshotScheduleSection() { + var snapshotScheduleSectionTemplate = wp.template( 'snapshot-schedule-accordion' ); + + // Inject the UI. + if ( _.isEmpty( component.snapshotScheduleSection ) ) { + if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + component.data.snapshotPublishDate = component.getCurrentTime(); } - e.preventDefault(); + + component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); + + component.snapshotScheduleSection = $( $.trim( snapshotScheduleSectionTemplate( component.data ) ) ); + component.snapshotScheduleSection.hide().appendTo( $( '#customize-header-actions' ) ); + + component.dateInputs = component.snapshotScheduleSection.find( '.date-input' ); + component.scheduledCountdownContainer = component.snapshotScheduleSection.find( '.snapshot-scheduled-countdown' ); + component.resetTimeButton = component.snapshotScheduleSection.find( '.reset-time' ); + component.resetTimeWrap = component.snapshotScheduleSection.find( '.wrap-reset-time' ); + component.scheduledCountdownTemplate = wp.template( 'snapshot-scheduled-countdown' ); + + component.dateInputs.each( function() { + var input = $( this ), componentName; + componentName = input.data( 'component' ); + component.dateComponentInputs[componentName] = input; + } ); + + component.snapshotEditLink = component.snapshotScheduleSection.find( 'a' ); + component.dateInputs.on( 'input', function hydrateInputValues() { + component.populateSetting(); + } ); + + component.dateInputs.on( 'blur', function hydrateInputValues() { + component.populateInputs(); + component.populateSetting(); + } ); + + component.updateScheduledCountdown(); + component.resetTimeButton.on( 'click', function( event ) { + component.updateSnapshotScheduleSection(); + component.resetTimeWrap.hide(); + // @todo reset button back to save or update and set disabled prop and remove scheduled text. + event.preventDefault(); + } ); + } + + // Listen for click events. + component.snapshotSlideDownToggle.on( 'click', function( event ) { + event.preventDefault(); + component.snapshotScheduleSection.toggle(); } ); api.state( 'snapshot-saved' ).bind( function( saved ) { if ( saved ) { - component.updateSnapshotScheduleBox(); + component.updateSnapshotScheduleSection(); } } ); @@ -233,22 +250,26 @@ } ); api.state( 'saved' ).bind( function( saved ) { - if ( saved && ! _.isEmpty( component.snapshotScheduleBox ) ) { - component.snapshotScheduleBox.hide(); + if ( saved && ! _.isEmpty( component.snapshotScheduleSection ) ) { + component.snapshotScheduleSection.hide(); } } ); api.state( 'snapshot-exists' ).bind( function( exists ) { - if ( exists && ! _.isEmpty( component.snapshotScheduleBox ) ) { - component.updateSnapshotScheduleBox(); + if ( exists && ! _.isEmpty( component.snapshotScheduleSection ) ) { + component.updateSnapshotScheduleSection(); } } ); - }; - component.updateSnapshotScheduleBox = function updateSnapshotScheduleBox() { + /** + * Updates snapshot schedule section with `component.data`. + * + * @return {void} + */ + component.updateSnapshotScheduleSection = function updateSnapshotScheduleSection() { var parsed; - if ( _.isEmpty( component.snapshotScheduleBox ) ) { + if ( _.isEmpty( component.snapshotScheduleSection ) ) { return; } if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { @@ -258,8 +279,8 @@ // Update date controls. component.snapshotEditLink.attr( 'href', component.data.editLink ); parsed = component.parseDateTime( component.data.snapshotPublishDate ); - _.each( component.dateComponentInputs, function populateInput( node, component ) { - $( node ).val( parsed[component] ); + _.each( component.dateComponentInputs, function populateInput( node, fieldName ) { + $( node ).val( parsed[fieldName] ); } ); }; @@ -271,7 +292,7 @@ component.addButtons = function() { var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), - snapshotSlideDownToggleTemplate = wp.template( 'snapshot-toggle-button' ), + snapshotSlideDownToggleTemplate = wp.template( 'snapshot-schedule-button' ), snapshotButton, submitButton, data, setPreviewLinkHref, snapshotSlideDownToggle, snapshotButtonText; // Save/update button. diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 7f1a0d58..88c0396f 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1090,18 +1090,18 @@ public function render_templates() { </a> </script> - <script type="text/html" id="tmpl-snapshot-toggle-button"> - <a href="#" id="snapshot-toggle-button" class="dashicons dashicons-calendar-alt" title="<?php esc_attr_e( 'Schedule Snapshot','customize-snapshots' ); ?>"></a> + <script type="text/html" id="tmpl-snapshot-schedule-button"> + <a href="#" id="snapshot-schedule-button" class="dashicons dashicons-calendar-alt" title="<?php esc_attr_e( 'Schedule Snapshot','customize-snapshots' ); ?>"></a> </script> <script type="text/html" id="tmpl-snapshot-schedule-accordion"> - <div id="customize-schedule-box" class="accordion-section"> - <div class="accordion-section-title"> - <div class="preview-notice"> - <strong class="panel-title site-title"><?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?></strong> + <div id="snapshot-schedule-section" class="accordion-section"> + <div class="snapshot-schedule-title"> + <h3> + <?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?> <span class="wrap-reset-time">(<a href="#" class="reset-time"><?php esc_html_e( 'Reset', 'customize-posts' ) ?></a>)</span> - </div> - <span class="description snapshot-description"> + </h3> + <span class="snapshot-schedule-description"> <?php $tz_string = get_option( 'timezone_string' ); if ( $tz_string ) { @@ -1118,12 +1118,12 @@ public function render_templates() { $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); } ?> - <span class="scheduled-countdown"></span> + <span class="snapshot-scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> <a href={{ data.editLink }} class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> </div> - <div class="customize-snapshot-control"> + <div class="snapshot-schedule-control"> <# _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); data.input_id_post_date = 'input-' + String( Math.random() ); data.input_id_post_date_gmt = 'input-' + String( Math.random() ); From d8a1edb8d7a85c636ae256e70ae450ab3f22aa45 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 14:05:36 +0530 Subject: [PATCH 21/59] Fix error on updateScheduledCountdown when controls are not initialized --- js/customize-snapshots.js | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 4af70578..7533dbfd 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -697,11 +697,15 @@ * Hides countdown if post_status is not already future. * Toggles the countdown if there is no remaining time. * - * @returns {void} + * @returns {boolean} if date input have valid time. */ component.updateScheduledCountdown = function updateScheduledCountdown() { - var remainingTime; - remainingTime = component.getDateFromInputs().valueOf(); + var remainingTime, dateTimeFromInput; + dateTimeFromInput = component.getDateFromInputs(); + if ( ! dateTimeFromInput ) { + return false; + } + remainingTime = dateTimeFromInput.valueOf(); remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); remainingTime = Math.ceil( remainingTime / 1000 ); if ( remainingTime > 0 ) { @@ -710,6 +714,7 @@ } else { component.scheduledCountdownContainer.hide(); } + return true; }; component.init(); From 08a217116279a9421503b45a74dc3f879e785ad3 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 14:33:41 +0530 Subject: [PATCH 22/59] On reset update UI settings --- js/customize-snapshots.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 7533dbfd..d413418f 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -223,7 +223,8 @@ component.updateScheduledCountdown(); component.resetTimeButton.on( 'click', function( event ) { component.updateSnapshotScheduleSection(); - component.resetTimeWrap.hide(); + component.populateSetting(); + // @todo reset button back to save or update and set disabled prop and remove scheduled text. event.preventDefault(); } ); @@ -553,6 +554,7 @@ if ( isNaN( date.valueOf() ) ) { return null; } + date.setSeconds( 0 ); return date; }; @@ -634,6 +636,7 @@ return false; } save = $( '#snapshot-save' ); + date.setSeconds( 0 ); isScheduleDateUpdated = component.formatDate( date ) !== component.data.snapshotPublishDate; if ( component.isScheduleDateFuture() && save.length ) { @@ -649,7 +652,6 @@ save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); } component.updateScheduledCountdown(); - date.setSeconds( 0 ); if ( isScheduleDateUpdated ) { component.resetTimeWrap.show(); } else { From 4ef7d54c002d908d0ac5c96be04c7857d38c2dad Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 15:23:34 +0530 Subject: [PATCH 23/59] On snapshot change schedule icon should be visible --- js/customize-snapshots.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index d413418f..f9ebfa26 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -319,9 +319,6 @@ if ( ! component.data.editLink ) { snapshotSlideDownToggle.hide(); } - api.state.bind( 'change', function() { - snapshotSlideDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); - } ); api.state( 'snapshot-saved' ).bind( function( saved ) { snapshotButton.prop( 'disabled', saved ); From c2281d0eec70a292407c8ff1801e60cb727353b0 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 16:15:11 +0530 Subject: [PATCH 24/59] Visibility of schedule toggle icon fix on publish and normalize date with sec as zeros --- js/customize-snapshots.js | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index f9ebfa26..f71cea00 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -1,6 +1,6 @@ /* global jQuery, _customizeSnapshots */ /* eslint-disable no-extra-parens */ -/* eslint no-magic-numbers: ["error", { "ignore": [-1,0,1,1000] }] */ +/* eslint no-magic-numbers: ["error", { "ignore": [-2,-1,0,1,1000] }] */ /* eslint complexity: ["error", 7] */ ( function( api, $ ) { @@ -193,6 +193,9 @@ component.data.snapshotPublishDate = component.getCurrentTime(); } + // Normalize date with secs set as zeros removed. + component.data.snapshotPublishDate = component.data.snapshotPublishDate.slice( 0, -2 ) + '00'; + component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); component.snapshotScheduleSection = $( $.trim( snapshotScheduleSectionTemplate( component.data ) ) ); @@ -255,6 +258,8 @@ api.state( 'snapshot-exists' ).bind( function( exists ) { if ( exists && ! _.isEmpty( component.snapshotScheduleSection ) ) { component.updateSnapshotScheduleSection(); + } else { + component.snapshotScheduleSection.hide(); } } ); }; @@ -273,6 +278,9 @@ component.data.snapshotPublishDate = component.getCurrentTime(); } + // Normalize date with secs removed. + component.data.snapshotPublishDate = component.data.snapshotPublishDate.slice( 0, -2 ) + '00'; + // Update date controls. component.snapshotEditLink.attr( 'href', component.data.editLink ); parsed = component.parseDateTime( component.data.snapshotPublishDate ); @@ -320,6 +328,14 @@ snapshotSlideDownToggle.hide(); } + api.state( 'change', function() { + snapshotSlideDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + } ); + + api.state( 'snapshot-exists' ).bind( function( exist ) { + snapshotSlideDownToggle.toggle( exist ); + } ); + api.state( 'snapshot-saved' ).bind( function( saved ) { snapshotButton.prop( 'disabled', saved ); } ); From 9a58741e3d9e7331f851d55cdbf1dcaba6371867 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 16:48:11 +0530 Subject: [PATCH 25/59] Fix edit link not visible on snapshot create --- js/customize-snapshots.js | 2 +- php/class-customize-snapshot-manager.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index f71cea00..15fd6006 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -213,7 +213,7 @@ component.dateComponentInputs[componentName] = input; } ); - component.snapshotEditLink = component.snapshotScheduleSection.find( 'a' ); + component.snapshotEditLink = component.snapshotScheduleSection.find( 'a.snapshot-edit-link' ); component.dateInputs.on( 'input', function hydrateInputValues() { component.populateSetting(); } ); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 038bc614..2f5e6331 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1121,7 +1121,7 @@ public function render_templates() { <span class="snapshot-scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> - <a href={{ data.editLink }} class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> + <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> </div> <div class="snapshot-schedule-control"> <# _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); From 73c18177898ce50cc0efce403e8c835bbeb0a960 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 17:23:29 +0530 Subject: [PATCH 26/59] Fix unit test --- tests/php/test-class-ajax-customize-snapshot-manager.php | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index 660486ba..99c085f5 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -334,6 +334,7 @@ function data_update_snapshot_cap_check() { 'setting_validities' => array( 'anyonecanedit' => true, ), + 'snapshot_publish_date' => '0000-00-00 00:00:00', ), ), ); From a8a614c5cfe430fc5477d32bcf0b272ebdbed37d Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 17:34:41 +0530 Subject: [PATCH 27/59] Code reivew changes --- js/customize-snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 15fd6006..b8bab412 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -59,7 +59,7 @@ $( '#snapshot-save' ).on( 'click', function( event ) { var scheduleDate; event.preventDefault(); - if ( $( this ).html() === component.data.i18n.scheduleButton && ! _.isEmpty( component.snapshotScheduleSection ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { + if ( ! _.isEmpty( component.snapshotScheduleSection ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { scheduleDate = component.getDateFromInputs(); component.sendUpdateSnapshotRequest( { status: 'future', From 0d21f51f46459e266ff066982968cded9539a6f2 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 18:17:53 +0530 Subject: [PATCH 28/59] Fix date issue on snapshot update after scheduling --- js/customize-snapshots.js | 6 +++++- php/class-customize-snapshot-manager.php | 7 +++++-- php/class-post-type.php | 3 ++- tests/php/test-class-ajax-customize-snapshot-manager.php | 3 ++- 4 files changed, 14 insertions(+), 5 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index b8bab412..091c9f6d 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -662,7 +662,11 @@ } } else if ( save.length ) { save.html( component.data.i18n.updateButton ); - save.prop( 'disabled', ! component.data.isSnapshotHasUnsavedChanges ); + if ( component.data.isSnapshotHasUnsavedChanges || isScheduleDateUpdated ) { + save.prop( 'disabled', false ); + } else { + save.prop( 'disabled', true ); + } } component.updateScheduledCountdown(); if ( isScheduleDateUpdated ) { diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 2f5e6331..a8424329 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -951,17 +951,20 @@ function( $value ) { $args = array( 'status' => $status, ); + $args['edit_date'] = current_time( 'mysql' ); if ( isset( $publish_date_obj ) && 'future' === $status ) { $args['post_date'] = $publish_date_obj->format( 'Y-m-d H:i:s' ); - $args['edit_date'] = current_time( 'mysql' ); + $args['post_date_gmt'] = '0000-00-00 00:00:00'; + } else { + $args['post_date_gmt'] = $args['post_date'] = '0000-00-00 00:00:00'; } $r = $this->snapshot->save( $args ); $post = $this->snapshot->post(); if ( $post ) { $data['edit_link'] = get_edit_post_link( $post, 'raw' ); - $data['snapshot_publish_date'] = $post->post_date_gmt; + $data['snapshot_publish_date'] = $post->post_date; } if ( is_wp_error( $r ) ) { diff --git a/php/class-post-type.php b/php/class-post-type.php index 349f6b6a..b085465a 100644 --- a/php/class-post-type.php +++ b/php/class-post-type.php @@ -508,9 +508,10 @@ public function save( array $args ) { ), ); if ( ! empty( $args['status'] ) ) { - if ( isset( $args['post_date'], $args['edit_date'] ) && 'future' === $args['status'] ) { + if ( isset( $args['post_date'], $args['edit_date'], $args['post_date_gmt'] ) ) { $post_arr['post_date'] = $args['post_date']; $post_arr['edit_date'] = $args['edit_date']; + $post_arr['post_date_gmt'] = $args['post_date_gmt']; } if ( ! get_post_status_object( $args['status'] ) ) { return new \WP_Error( 'bad_status' ); diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index 99c085f5..e263f42e 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -275,7 +275,9 @@ function test_ajax_update_snapshot_cap_check( $role, $expected_results ) { if ( $response['success'] ) { $this->assertNotEmpty( $response['data']['edit_link'] ); + $this->assertNotEmpty( $response['data']['snapshot_publish_date'] ); unset( $response['data']['edit_link'] ); + unset( $response['data']['snapshot_publish_date'] ); } $this->assertSame( $expected_results, $response ); } @@ -334,7 +336,6 @@ function data_update_snapshot_cap_check() { 'setting_validities' => array( 'anyonecanedit' => true, ), - 'snapshot_publish_date' => '0000-00-00 00:00:00', ), ), ); From 1ee150a33f1f210e829aaeabf06890dcd3409ef9 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 18:27:58 +0530 Subject: [PATCH 29/59] Fix eslint complexity --- js/customize-snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 091c9f6d..81f3d884 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -1,7 +1,7 @@ /* global jQuery, _customizeSnapshots */ /* eslint-disable no-extra-parens */ /* eslint no-magic-numbers: ["error", { "ignore": [-2,-1,0,1,1000] }] */ -/* eslint complexity: ["error", 7] */ +/* eslint complexity: ["error", 9] */ ( function( api, $ ) { 'use strict'; From 256f7b6bc9f1bcc061b3b8069e3934a79470de62 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 4 Aug 2016 18:55:50 +0530 Subject: [PATCH 30/59] On snapshot schedule/update call populateSetting to update UI --- js/customize-snapshots.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 81f3d884..e716a3e6 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -287,6 +287,7 @@ _.each( component.dateComponentInputs, function populateInput( node, fieldName ) { $( node ).val( parsed[fieldName] ); } ); + component.populateSetting(); }; /** @@ -458,6 +459,8 @@ if ( response.snapshot_publish_date ) { component.data.snapshotPublishDate = response.snapshot_publish_date; } + component.updateSnapshotScheduleSection(); + component.data.isSnapshotHasUnsavedChanges = false; // @todo Remove privateness from _handleSettingValidities in Core. if ( api._handleSettingValidities && response.setting_validities ) { From 96cba79ca7f35948d511c3dedc390a3e1a460e66 Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 02:08:44 -0700 Subject: [PATCH 31/59] Refactor --- css/customize-snapshots.css | 38 +- js/customize-snapshots.js | 466 +++++++++++++---------- php/class-customize-snapshot-manager.php | 84 ++-- 3 files changed, 333 insertions(+), 255 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 8108f9cf..5a872a12 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -57,7 +57,7 @@ } } -#snapshot-schedule-section { +#snapshot-schedule { background: #fff !important; border-bottom: 1px solid #ddd; line-height: 1.5; @@ -68,16 +68,16 @@ box-shadow: 0 5px 0 0 rgba(0,0,0,0.05); } -#snapshot-schedule-section .snapshot-schedule-title { +#snapshot-schedule .snapshot-schedule-title { color: #555; padding: 10px 10px 0; } -#snapshot-schedule-section .snapshot-schedule-title h3 { +#snapshot-schedule .snapshot-schedule-title h3 { margin: .2em 2em .75em 0; } -#snapshot-schedule-section a.snapshot-edit-link { +#snapshot-schedule a.snapshot-edit-link { position: absolute; top: 4px; right: 1px; @@ -93,15 +93,39 @@ padding: 10px; } -#snapshot-schedule-section .snapshot-schedule-control { +#snapshot-schedule a.snapshot-edit-link:focus, +#snapshot-schedule a.snapshot-edit-link:hover { + color: #0073aa; + +} + +#snapshot-schedule a.snapshot-edit-link:before { + padding: 4px; + position: absolute; + top: 5px; + left: 6px; + -webkit-border-radius: 100%; + border-radius: 100%; +} + +#snapshot-schedule a.snapshot-edit-link:focus:before { + -webkit-box-shadow: + 0 0 0 1px #5b9dd9, + 0 0 2px 1px rgba(30, 140, 190, .8); + box-shadow: + 0 0 0 1px #5b9dd9, + 0 0 2px 1px rgba(30, 140, 190, .8); +} + +#snapshot-schedule .snapshot-schedule-control { padding: 10px; } -#snapshot-schedule-section .accordion-section-title { +#snapshot-schedule .accordion-section-title { padding: 10px; } -#snapshot-schedule-section .wrap-reset-time { +#snapshot-schedule .reset-time { font-weight: normal; font-size: 80%; display: none; diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index e716a3e6..24c6865f 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -1,7 +1,4 @@ /* global jQuery, _customizeSnapshots */ -/* eslint-disable no-extra-parens */ -/* eslint no-magic-numbers: ["error", { "ignore": [-2,-1,0,1,1000] }] */ -/* eslint complexity: ["error", 9] */ ( function( api, $ ) { 'use strict'; @@ -14,18 +11,20 @@ component = api.Snapshots; + component.schedule = {}; + component.data = { action: '', uuid: '', editLink: '', - snapshotPublishDate: '', - snapshotStatus: '', + publishDate: '', + postStatus: '', currentUserCanPublish: '', initialServerDate: '', initialServerTimestamp: 0, - initialClientTimestamp: ( new Date() ).valueOf(), + initialClientTimestamp: 0, i18n: {}, - isSnapshotHasUnsavedChanges: false + dirty: false }; if ( 'undefined' !== typeof _customizeSnapshots ) { @@ -41,6 +40,9 @@ window._wpCustomizeControlsL10n.save = component.data.i18n.publish; window._wpCustomizeControlsL10n.saved = component.data.i18n.published; + // Set the initial client timestamp. + component.data.initialClientTimestamp = component.dateValueOf(); + api.bind( 'ready', function() { api.state.create( 'snapshot-exists', component.data.snapshotExists ); api.state.create( 'snapshot-saved', true ); @@ -54,12 +56,12 @@ component.extendPreviewerQuery(); component.addButtons(); - component.addSnapshotScheduleSection(); + component.addSchedule(); $( '#snapshot-save' ).on( 'click', function( event ) { var scheduleDate; event.preventDefault(); - if ( ! _.isEmpty( component.snapshotScheduleSection ) && component.getDateFromInputs() && component.isScheduleDateFuture() ) { + if ( ! _.isEmpty( component.schedule.template ) && component.isFutureDate() ) { scheduleDate = component.getDateFromInputs(); component.sendUpdateSnapshotRequest( { status: 'future', @@ -175,121 +177,6 @@ return a.href; }; - component.dateComponentInputs = {}; - - component.snapshotScheduleSection = {}; - - /** - * Renders Snapshot Schedule Section and handles it's events. - * - * @returns {void} - */ - component.addSnapshotScheduleSection = function addSnapshotScheduleSection() { - var snapshotScheduleSectionTemplate = wp.template( 'snapshot-schedule-accordion' ); - - // Inject the UI. - if ( _.isEmpty( component.snapshotScheduleSection ) ) { - if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { - component.data.snapshotPublishDate = component.getCurrentTime(); - } - - // Normalize date with secs set as zeros removed. - component.data.snapshotPublishDate = component.data.snapshotPublishDate.slice( 0, -2 ) + '00'; - - component.data = _.extend( component.data, component.parseDateTime( component.data.snapshotPublishDate ) ); - - component.snapshotScheduleSection = $( $.trim( snapshotScheduleSectionTemplate( component.data ) ) ); - component.snapshotScheduleSection.hide().appendTo( $( '#customize-header-actions' ) ); - - component.dateInputs = component.snapshotScheduleSection.find( '.date-input' ); - component.scheduledCountdownContainer = component.snapshotScheduleSection.find( '.snapshot-scheduled-countdown' ); - component.resetTimeButton = component.snapshotScheduleSection.find( '.reset-time' ); - component.resetTimeWrap = component.snapshotScheduleSection.find( '.wrap-reset-time' ); - component.scheduledCountdownTemplate = wp.template( 'snapshot-scheduled-countdown' ); - - component.dateInputs.each( function() { - var input = $( this ), componentName; - componentName = input.data( 'component' ); - component.dateComponentInputs[componentName] = input; - } ); - - component.snapshotEditLink = component.snapshotScheduleSection.find( 'a.snapshot-edit-link' ); - component.dateInputs.on( 'input', function hydrateInputValues() { - component.populateSetting(); - } ); - - component.dateInputs.on( 'blur', function hydrateInputValues() { - component.populateInputs(); - component.populateSetting(); - } ); - - component.updateScheduledCountdown(); - component.resetTimeButton.on( 'click', function( event ) { - component.updateSnapshotScheduleSection(); - component.populateSetting(); - - // @todo reset button back to save or update and set disabled prop and remove scheduled text. - event.preventDefault(); - } ); - } - - // Listen for click events. - component.snapshotSlideDownToggle.on( 'click', function( event ) { - event.preventDefault(); - component.snapshotScheduleSection.toggle(); - } ); - - api.state( 'snapshot-saved' ).bind( function( saved ) { - if ( saved ) { - component.updateSnapshotScheduleSection(); - } - } ); - - api.bind( 'change', function() { - component.data.isSnapshotHasUnsavedChanges = true; - } ); - - api.state( 'saved' ).bind( function( saved ) { - if ( saved && ! _.isEmpty( component.snapshotScheduleSection ) ) { - component.snapshotScheduleSection.hide(); - } - } ); - - api.state( 'snapshot-exists' ).bind( function( exists ) { - if ( exists && ! _.isEmpty( component.snapshotScheduleSection ) ) { - component.updateSnapshotScheduleSection(); - } else { - component.snapshotScheduleSection.hide(); - } - } ); - }; - - /** - * Updates snapshot schedule section with `component.data`. - * - * @return {void} - */ - component.updateSnapshotScheduleSection = function updateSnapshotScheduleSection() { - var parsed; - if ( _.isEmpty( component.snapshotScheduleSection ) ) { - return; - } - if ( '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { - component.data.snapshotPublishDate = component.getCurrentTime(); - } - - // Normalize date with secs removed. - component.data.snapshotPublishDate = component.data.snapshotPublishDate.slice( 0, -2 ) + '00'; - - // Update date controls. - component.snapshotEditLink.attr( 'href', component.data.editLink ); - parsed = component.parseDateTime( component.data.snapshotPublishDate ); - _.each( component.dateComponentInputs, function populateInput( node, fieldName ) { - $( node ).val( parsed[fieldName] ); - } ); - component.populateSetting(); - }; - /** * Create the snapshot buttons. * @@ -298,13 +185,12 @@ component.addButtons = function() { var header = $( '#customize-header-actions' ), publishButton = header.find( '#save' ), - snapshotSlideDownToggleTemplate = wp.template( 'snapshot-schedule-button' ), - snapshotButton, submitButton, data, setPreviewLinkHref, snapshotSlideDownToggle, snapshotButtonText; + snapshotButton, scheduleButton, submitButton, data, setPreviewLinkHref, snapshotButtonText; // Save/update button. snapshotButton = wp.template( 'snapshot-save' ); if ( api.state( 'snapshot-exists' ).get() ) { - if ( 'future' === component.data.snapshotStatus ) { + if ( 'future' === component.data.postStatus ) { snapshotButtonText = component.data.i18n.scheduleButton; } else { snapshotButtonText = component.data.i18n.updateButton; @@ -322,19 +208,21 @@ snapshotButton.prop( 'disabled', true ); snapshotButton.insertAfter( publishButton ); - snapshotSlideDownToggle = $( $.trim( snapshotSlideDownToggleTemplate( {} ) ) ); - snapshotSlideDownToggle.insertAfter( snapshotButton ); - component.snapshotSlideDownToggle = snapshotSlideDownToggle; + // Schedule button. + scheduleButton = wp.template( 'snapshot-schedule-button' ); + scheduleButton = $( $.trim( scheduleButton( {} ) ) ); + scheduleButton.insertAfter( snapshotButton ); + if ( ! component.data.editLink ) { - snapshotSlideDownToggle.hide(); + scheduleButton.hide(); } api.state( 'change', function() { - snapshotSlideDownToggle.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); + scheduleButton.toggle( api.state( 'snapshot-saved' ).get() && api.state( 'snapshot-exists' ).get() ); } ); api.state( 'snapshot-exists' ).bind( function( exist ) { - snapshotSlideDownToggle.toggle( exist ); + scheduleButton.toggle( exist ); } ); api.state( 'snapshot-saved' ).bind( function( saved ) { @@ -403,6 +291,154 @@ header.addClass( 'button-added' ); }; + /** + * Renders snapshot schedule and handles it's events. + * + * @returns {void} + */ + component.addSchedule = function addSchedule() { + var sliceBegin = 0, + sliceEnd = -2; + + // Inject the UI. + if ( _.isEmpty( component.schedule.template ) ) { + if ( '0000-00-00 00:00:00' === component.data.publishDate ) { + component.data.publishDate = component.getCurrentTime(); + } + + // Normalize date with secs set as zeros removed. + component.data.publishDate = component.data.publishDate.slice( sliceBegin, sliceEnd ) + '00'; + + // Extend the components data object and add the parsed datetime strings. + component.data = _.extend( component.data, component.parseDateTime( component.data.publishDate ) ); + + // Add the template to the DOM. + component.schedule.template = $( $.trim( wp.template( 'snapshot-schedule' )( component.data ) ) ); + component.schedule.template.hide().appendTo( $( '#customize-header-actions' ) ); + + // Store the date inputs. + component.schedule.inputs = component.schedule.template.find( '.date-input' ); + + component.schedule.inputs.on( 'input', function() { + component.populateSetting(); + } ); + + component.schedule.inputs.on( 'blur', function() { + component.populateInputs(); + component.populateSetting(); + } ); + + component.updateCountdown(); + + component.schedule.template.find( '.reset-time a' ).on( 'click', function( event ) { + event.preventDefault(); + + component.updateSchedule(); + component.populateSetting(); + } ); + } + + // Listen for click events. + $( '#snapshot-schedule-button' ).on( 'click', function( event ) { + event.preventDefault(); + component.schedule.template.toggle(); + } ); + + api.state( 'snapshot-saved' ).bind( function( saved ) { + if ( saved ) { + component.updateSchedule(); + } + } ); + + api.bind( 'change', function() { + component.data.dirty = true; + } ); + + api.state( 'saved' ).bind( function( saved ) { + if ( saved && ! _.isEmpty( component.schedule.template ) ) { + component.schedule.template.hide(); + } + } ); + + api.state( 'snapshot-exists' ).bind( function( exists ) { + if ( exists && ! _.isEmpty( component.schedule.template ) ) { + component.updateSchedule(); + } else { + component.schedule.template.hide(); + } + } ); + }; + + /** + * Updates snapshot schedule with `component.data`. + * + * @return {void} + */ + component.updateSchedule = function updateSchedule() { + var parsed, + sliceBegin = 0, + sliceEnd = -2; + + if ( _.isEmpty( component.schedule.template ) ) { + return; + } + + if ( '0000-00-00 00:00:00' === component.data.publishDate ) { + component.data.publishDate = component.getCurrentTime(); + } + + // Normalize date with seconds removed. + component.data.publishDate = component.data.publishDate.slice( sliceBegin, sliceEnd ) + '00'; + + // Update date controls. + component.schedule.template.find( 'a.snapshot-edit-link' ).attr( 'href', component.data.editLink ); + parsed = component.parseDateTime( component.data.publishDate ); + + component.schedule.inputs.each( function() { + var input = $( this ), + fieldName = input.data( 'date-input' ); + + $( this ).val( parsed[fieldName] ); + } ); + + component.populateSetting(); + }; + + /** + * Update the scheduled countdown text. + * + * Hides countdown if post_status is not already future. + * Toggles the countdown if there is no remaining time. + * + * @returns {boolean} True if date inputs are valid. + */ + component.updateCountdown = function updateCountdown() { + var countdown = component.schedule.template.find( '.snapshot-scheduled-countdown' ), + countdownTemplate = wp.template( 'snapshot-scheduled-countdown' ), + dateTimeFromInput = component.getDateFromInputs(), + millisecondsDivider = 1000, + remainingTime; + + if ( ! dateTimeFromInput ) { + return false; + } + + remainingTime = dateTimeFromInput.valueOf(); + remainingTime -= component.dateValueOf( component.getCurrentTime() ); + remainingTime = Math.ceil( remainingTime / millisecondsDivider ); + + if ( 0 < remainingTime ) { + countdown.text( countdownTemplate( { + remainingTime: remainingTime + } ) ); + countdown.show(); + } else { + countdown.hide(); + } + + return true; + }; + /** * Silently update the saved state to be true without triggering the * changed event so that the AYS beforeunload dialog won't appear @@ -457,10 +493,10 @@ component.data.editLink = response.edit_link; } if ( response.snapshot_publish_date ) { - component.data.snapshotPublishDate = response.snapshot_publish_date; + component.data.publishDate = response.snapshot_publish_date; } - component.updateSnapshotScheduleSection(); - component.data.isSnapshotHasUnsavedChanges = false; + component.updateSchedule(); + component.data.dirty = false; // @todo Remove privateness from _handleSettingValidities in Core. if ( api._handleSettingValidities && response.setting_validities ) { @@ -474,9 +510,10 @@ request.done( function() { var url = api.previewer.previewUrl(), regex = new RegExp( '([?&])customize_snapshot_uuid=.*?(&|$)', 'i' ), - separator = url.indexOf( '?' ) !== -1 ? '&' : '?', + notFound = -1, + separator = url.indexOf( '?' ) !== notFound ? '&' : '?', customizeUrl = window.location.href, - customizeSeparator = customizeUrl.indexOf( '?' ) !== -1 ? '&' : '?'; + customizeSeparator = customizeUrl.indexOf( '?' ) !== notFound ? '&' : '?'; if ( url.match( regex ) ) { url = url.replace( regex, '$1customize_snapshot_uuid=' + encodeURIComponent( component.data.uuid ) + '$2' ); @@ -559,18 +596,24 @@ * @returns {Date|null} Date created from inputs or null if invalid date. */ component.getDateFromInputs = function getDateFromInputs() { - var control = component, date; + var template = component.schedule.template, + monthOffset = 1, + date; + date = new Date( - parseInt( control.dateComponentInputs.year.val(), 10 ), - parseInt( control.dateComponentInputs.month.val(), 10 ) - 1, - parseInt( control.dateComponentInputs.day.val(), 10 ), - parseInt( control.dateComponentInputs.hour.val(), 10 ), - parseInt( control.dateComponentInputs.minute.val(), 10 ) + parseInt( template.find( '[data-date-input="year"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="month"]' ).val(), 10 ) - monthOffset, + parseInt( template.find( '[data-date-input="day"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="hour"]' ).val(), 10 ), + parseInt( template.find( '[data-date-input="minute"]' ).val(), 10 ) ); + if ( isNaN( date.valueOf() ) ) { return null; } + date.setSeconds( 0 ); + return date; }; @@ -582,10 +625,13 @@ */ component.parseDateTime = function parseDateTime( datetime ) { var matches = datetime.match( /^(\d\d\d\d)-(\d\d)-(\d\d) (\d\d):(\d\d):(\d\d)$/ ); + if ( ! matches ) { return null; } + matches.shift(); + return { year: matches.shift(), month: matches.shift(), @@ -599,15 +645,19 @@ /** * Format a Date Object. Returns 'Y-m-d H:i:s' format. * + * @props http://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript#comment33639551_10073699 + * * @param {Date} date A Date object. * @returns {string} A formatted date String. */ component.formatDate = function formatDate( date ) { - var formattedDate, yearLength = 4, nonYearLength = 2; + var formattedDate, + yearLength = 4, + nonYearLength = 2, + monthOffset = 1; - // Props: http://stackoverflow.com/questions/10073699/pad-a-number-with-leading-zeros-in-javascript#comment33639551_10073699 formattedDate = ( '0000' + date.getFullYear() ).substr( -yearLength, yearLength ); - formattedDate += '-' + ( '00' + ( date.getMonth() + 1 ) ).substr( -nonYearLength, nonYearLength ); + formattedDate += '-' + ( '00' + ( date.getMonth() + monthOffset ) ).substr( -nonYearLength, nonYearLength ); formattedDate += '-' + ( '00' + date.getDate() ).substr( -nonYearLength, nonYearLength ); formattedDate += ' ' + ( '00' + date.getHours() ).substr( -nonYearLength, nonYearLength ); formattedDate += ':' + ( '00' + date.getMinutes() ).substr( -nonYearLength, nonYearLength ); @@ -622,21 +672,25 @@ * @returns {boolean} Whether the inputs were populated. */ component.populateInputs = function populateInputs() { - var parsed, setComponentInputValue; - if ( component.dateInputs.is( ':focus' ) || '0000-00-00 00:00:00' === component.data.snapshotPublishDate ) { + var parsed; + + if ( component.schedule.inputs.is( ':focus' ) || '0000-00-00 00:00:00' === component.data.publishDate ) { return false; } - parsed = component.parseDateTime( component.data.snapshotPublishDate ); + + parsed = component.parseDateTime( component.data.publishDate ); if ( ! parsed ) { return false; } - setComponentInputValue = function( value, inputName ) { - var input = component.dateComponentInputs[inputName]; - if ( input && ! input.is( 'select' ) && '' === input.val() ) { - input.val( value ); + + component.schedule.inputs.each( function() { + var input = $( this ), + fieldName = input.data( 'date-input' ); + + if ( ! $( this ).is( 'select' ) && '' === $( this ).val() ) { + $( this ).val( parsed[fieldName] ); } - }; - _.each( parsed, setComponentInputValue ); + } ); return true; }; @@ -646,97 +700,95 @@ * @returns {boolean} Whether the date inputs currently represent a valid date. */ component.populateSetting = function populateSetting() { - var date, save, isScheduleDateUpdated; - date = component.getDateFromInputs(); + var date = component.getDateFromInputs(), + save = $( '#snapshot-save' ), + scheduled; + if ( ! date ) { return false; } - save = $( '#snapshot-save' ); + date.setSeconds( 0 ); - isScheduleDateUpdated = component.formatDate( date ) !== component.data.snapshotPublishDate; - if ( component.isScheduleDateFuture() && save.length ) { + scheduled = component.formatDate( date ) !== component.data.publishDate; + + if ( save.length ) { // Change update button to schedule. - save.html( component.data.i18n.scheduleButton ); - if ( isScheduleDateUpdated || component.data.isSnapshotHasUnsavedChanges ) { - save.prop( 'disabled', false ); + if ( component.isFutureDate() ) { + save.html( component.data.i18n.scheduleButton ); } else { - save.prop( 'disabled', true ); + save.html( component.data.i18n.updateButton ); } - } else if ( save.length ) { - save.html( component.data.i18n.updateButton ); - if ( component.data.isSnapshotHasUnsavedChanges || isScheduleDateUpdated ) { + + if ( scheduled || component.data.dirty ) { save.prop( 'disabled', false ); } else { save.prop( 'disabled', true ); } } - component.updateScheduledCountdown(); - if ( isScheduleDateUpdated ) { - component.resetTimeWrap.show(); - } else { - component.resetTimeWrap.hide(); - } - return true; + component.updateCountdown(); + component.schedule.template.find( '.reset-time' ).toggle( scheduled ); + + return true; }; /** - * Check if snapshot schedule date is in future date + * Check if the schedule date is in the future. * - * @returns {boolean} if date in input controls is of future + * @returns {boolean} True if future date. */ - component.isScheduleDateFuture = function isScheduleDateFuture() { - var date, remainingTime; - date = component.getDateFromInputs(); + component.isFutureDate = function isFutureDate() { + var date = component.getDateFromInputs(), + millisecondsDivider = 1000, + remainingTime; + if ( ! date ) { return false; } - remainingTime = ( new Date( date ) ).valueOf(); - remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); - remainingTime = Math.ceil( remainingTime / 1000 ); - return remainingTime > 0; + + remainingTime = component.dateValueOf( date ); + remainingTime -= component.dateValueOf( component.getCurrentTime() ); + remainingTime = Math.ceil( remainingTime / millisecondsDivider ); + + return ( 0 < remainingTime ); }; /** - * Get current date/time in the site's timezone, as does the current_time( 'mysql', false ) function in PHP. + * Get current date/time in the site's timezone. + * + * Same functionality as the `current_time( 'mysql', false )` function in PHP. * * @returns {string} Current datetime string. */ component.getCurrentTime = function getCurrentTime() { - var currentDate, currentTimestamp, timestampDifferential; - currentTimestamp = ( new Date() ).valueOf(); - currentDate = new Date( component.data.initialServerDate ); + var currentDate = new Date( component.data.initialServerDate ), + currentTimestamp = component.dateValueOf(), + timestampDifferential; + timestampDifferential = currentTimestamp - component.data.initialClientTimestamp; timestampDifferential += component.data.initialClientTimestamp - component.data.initialServerTimestamp; currentDate.setTime( currentDate.getTime() + timestampDifferential ); + return component.formatDate( currentDate ); }; /** - * Update the scheduled countdown. - * - * Hides countdown if post_status is not already future. - * Toggles the countdown if there is no remaining time. + * Get the primitive value of a Date object. * - * @returns {boolean} if date input have valid time. + * @param {string} dateString The post status for the snapshot. + * @return {string} */ - component.updateScheduledCountdown = function updateScheduledCountdown() { - var remainingTime, dateTimeFromInput; - dateTimeFromInput = component.getDateFromInputs(); - if ( ! dateTimeFromInput ) { - return false; - } - remainingTime = dateTimeFromInput.valueOf(); - remainingTime -= ( new Date( component.getCurrentTime() ) ).valueOf(); - remainingTime = Math.ceil( remainingTime / 1000 ); - if ( remainingTime > 0 ) { - component.scheduledCountdownContainer.text( component.scheduledCountdownTemplate( { remainingTime: remainingTime } ) ); - component.scheduledCountdownContainer.show(); + component.dateValueOf = function( dateString ) { + var date; + + if ( _.isUndefined( dateString ) ) { + date = new Date(); } else { - component.scheduledCountdownContainer.hide(); + date = new Date( dateString ); } - return true; + + return date.valueOf(); }; component.init(); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index a8424329..20db2d7e 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -537,8 +537,8 @@ public function enqueue_scripts() { 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), 'editLink' => $this->snapshot ? get_edit_post_link( $post, 'raw' ) : '', - 'snapshotPublishDate' => $this->snapshot ? $post->post_date : '', - 'snapshotStatus' => $this->snapshot ? $post->post_status : '', + 'publishDate' => $this->snapshot ? $post->post_date : '', + 'postStatus' => $this->snapshot ? $post->post_status : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), 'initialServerDate' => current_time( 'mysql', false ), 'initialServerTimestamp' => floor( microtime( true ) * 1000 ), @@ -1086,6 +1086,21 @@ public function replace_customize_link( $wp_admin_bar ) { */ public function render_templates() { $data = $this->get_month_choices(); + + $tz_string = get_option( 'timezone_string' ); + if ( $tz_string ) { + $tz = new \DateTimezone( $tz_string ); + $formatted_gmt_offset = $this->format_gmt_offset( $tz->getOffset( new \DateTime() ) / 3600 ); + $tz_name = str_replace( '_', ' ', $tz->getName() ); + + /* translators: 1: timezone name, 2: gmt offset */ + $date_control_description = sprintf( __( 'This site\'s dates are in the %1$s timezone (currently UTC%2$s).', 'customize-snapshots' ), $tz_name, $formatted_gmt_offset ); + } else { + $formatted_gmt_offset = $this->format_gmt_offset( get_option( 'gmt_offset' ) ); + + /* translators: %s: gmt offset */ + $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); + } ?> <script type="text/html" id="tmpl-snapshot-preview-link"> <a href="#" target="frontend-preview" id="snapshot-preview-link" class="dashicons dashicons-welcome-view-site" title="<?php esc_attr_e( 'View on frontend', 'customize-snapshots' ) ?>"> @@ -1097,56 +1112,43 @@ public function render_templates() { <a href="#" id="snapshot-schedule-button" class="dashicons dashicons-calendar-alt" title="<?php esc_attr_e( 'Schedule Snapshot','customize-snapshots' ); ?>"></a> </script> - <script type="text/html" id="tmpl-snapshot-schedule-accordion"> - <div id="snapshot-schedule-section" class="accordion-section"> + <script type="text/html" id="tmpl-snapshot-schedule"> + <div id="snapshot-schedule"> <div class="snapshot-schedule-title"> <h3> <?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?> - <span class="wrap-reset-time">(<a href="#" class="reset-time"><?php esc_html_e( 'Reset', 'customize-snapshots' ) ?></a>)</span> + <span class="reset-time">(<a href="#"><?php esc_html_e( 'Reset', 'customize-snapshots' ) ?></a>)</span> </h3> <span class="snapshot-schedule-description"> - <?php - $tz_string = get_option( 'timezone_string' ); - if ( $tz_string ) { - $tz = new \DateTimezone( $tz_string ); - $formatted_gmt_offset = $this->format_gmt_offset( $tz->getOffset( new \DateTime() ) / 3600 ); - $tz_name = str_replace( '_', ' ', $tz->getName() ); - - /* translators: 1: timezone name, 2: gmt offset */ - $date_control_description = sprintf( __( 'This site\'s dates are in the %1$s timezone (currently UTC%2$s).', 'customize-snapshots' ), $tz_name, $formatted_gmt_offset ); - } else { - $formatted_gmt_offset = $this->format_gmt_offset( get_option( 'gmt_offset' ) ); - - /* translators: %s: gmt offset */ - $date_control_description = sprintf( __( 'Dates are in UTC%s.', 'customize-snapshots' ), $formatted_gmt_offset ); - } - ?> <span class="snapshot-scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> </div> <div class="snapshot-schedule-control"> - <# _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); - data.input_id_post_date = 'input-' + String( Math.random() ); - data.input_id_post_date_gmt = 'input-' + String( Math.random() ); - #> - <select id="{{ data.input_id }}" class="date-input month" data-component="month"> - <# _.each( data.month_choices, function( choice ) { #> - <# if ( _.isObject( choice ) && ! _.isUndefined( choice.text ) && ! _.isUndefined( choice.value ) ) { - text = choice.text; - value = choice.value; - } - #> - <option value="{{ value }}" <# if (choice.value == data.month) { #> - selected="selected" - <# } #>>{{ text }}</option> - <# } ); #> - </select> - <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input day" data-component="day" min="1" max="31" value="{{ data.day }}" />, - <input type="number" size="4" maxlength="4" autocomplete="off" class="date-input year" data-component="year" min="<?php echo esc_attr( date( 'Y' ) ); ?>" value="{{ data.year }}" max="9999" /> - @ <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input hour" data-component="hour" min="0" max="23" value="{{ data.hour }}" />:<?php - ?><input type="number" size="2" maxlength="2" autocomplete="off" class="date-input minute" data-component="minute" min="0" max="59" value="{{ data.minute }}" /> + <# + _.defaults( data, <?php echo wp_json_encode( $data ) ?> ); + data.input_id_post_date = 'input-' + String( Math.random() ); + data.input_id_post_date_gmt = 'input-' + String( Math.random() ); + #> + <select id="{{ data.input_id }}" class="date-input month" data-date-input="month"> + <# _.each( data.month_choices, function( choice ) { #> + <# if ( _.isObject( choice ) && ! _.isUndefined( choice.text ) && ! _.isUndefined( choice.value ) ) { + text = choice.text; + value = choice.value; + } #> + <option value="{{ value }}" + <# if (choice.value == data.month) { #> + selected="selected" + <# } #>> + {{ text }} + </option> + <# } ); #> + </select> + <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input day" data-date-input="day" min="1" max="31" value="{{ data.day }}" />, + <input type="number" size="4" maxlength="4" autocomplete="off" class="date-input year" data-date-input="year" min="<?php echo esc_attr( date( 'Y' ) ); ?>" value="{{ data.year }}" max="9999" /> @ + <input type="number" size="2" maxlength="2" autocomplete="off" class="date-input hour" data-date-input="hour" min="0" max="23" value="{{ data.hour }}" />:<?php + ?><input type="number" size="2" maxlength="2" autocomplete="off" class="date-input minute" data-date-input="minute" min="0" max="59" value="{{ data.minute }}" /> </div> </div> </script> From d7848cf09ba19c5e1dc0da0d84d34a88cf376ccc Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 02:16:13 -0700 Subject: [PATCH 32/59] Fix eslint issues --- js/customize-snapshots.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 24c6865f..04bc255c 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -751,7 +751,7 @@ remainingTime -= component.dateValueOf( component.getCurrentTime() ); remainingTime = Math.ceil( remainingTime / millisecondsDivider ); - return ( 0 < remainingTime ); + return 0 < remainingTime; }; /** @@ -777,7 +777,7 @@ * Get the primitive value of a Date object. * * @param {string} dateString The post status for the snapshot. - * @return {string} + * @return {object|string} The primitive value or date object. */ component.dateValueOf = function( dateString ) { var date; From 0f5634de9009fa32dd4c1d98c4f017d8f2cc645b Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 02:16:53 -0700 Subject: [PATCH 33/59] Fix typo --- js/customize-snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 04bc255c..81036ae6 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -777,7 +777,7 @@ * Get the primitive value of a Date object. * * @param {string} dateString The post status for the snapshot. - * @return {object|string} The primitive value or date object. + * @returns {object|string} The primitive value or date object. */ component.dateValueOf = function( dateString ) { var date; From 2772725d5f93a1b189dd01b5869620167b66172f Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Fri, 5 Aug 2016 16:43:03 +0530 Subject: [PATCH 34/59] Reset schedule variables when snapshot publish --- js/customize-snapshots.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 81036ae6..d33ef980 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -357,6 +357,8 @@ api.state( 'saved' ).bind( function( saved ) { if ( saved && ! _.isEmpty( component.schedule.template ) ) { component.schedule.template.hide(); + component.data.publishDate = '0000-00-00 00:00:00'; + component.data.dirty = false; } } ); From ccf7a869644bbcb0b208e5843ec2b716c43b0516 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Fri, 5 Aug 2016 19:17:17 +0530 Subject: [PATCH 35/59] Add unit-test for schedule snapshot --- ...-class-ajax-customize-snapshot-manager.php | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index e263f42e..096482ad 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -418,4 +418,44 @@ function make_save_snapshot_ajax_call() { unset( $e ); } } + + /** + * Testing schedule Snapshot + */ + function test_ajax_update_snapshot_schedule() { + unset( $GLOBALS['wp_customize'] ); + remove_all_actions( 'wp_ajax_' . Customize_Snapshot_Manager::AJAX_ACTION ); + + $setting_key = 'anyonecanedit'; + $tomorrow = date( 'Y-m-d H:i:s', time() + 86400 ); + $this->set_current_user( 'administrator' ); + $this->set_input_vars( array( + 'action' => Customize_Snapshot_Manager::AJAX_ACTION, + 'nonce' => wp_create_nonce( Customize_Snapshot_Manager::AJAX_ACTION ), + 'customize_snapshot_uuid' => self::UUID, + 'customized' => wp_json_encode( array( $setting_key => 'Hello' ) ), + 'status' => 'future', + 'publish_date' => $tomorrow, // Tomorrow. + ) ); + + $this->plugin = new Plugin(); + $this->plugin->init(); + $this->add_setting(); + + $this->make_ajax_call( Customize_Snapshot_Manager::AJAX_ACTION ); + $post_id = get_plugin_instance()->customize_snapshot_manager->post_type->find_post( self::UUID ); + $expected_results = array( + 'success' => true, + 'data' => array( + 'errors' => null, + 'setting_validities' => array( $setting_key => true ), + 'edit_link' => get_edit_post_link( $post_id, 'raw' ), + 'snapshot_publish_date' => $tomorrow, + ), + ); + // Get the results. + $response = json_decode( $this->_last_response, true ); + $this->assertSame( $expected_results, $response ); + $this->assertEquals( 'future', get_post_status( $post_id ) ); + } } From ee64c74db859bdba99f7b05969e536bbfcb43d7a Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Fri, 5 Aug 2016 20:03:37 +0530 Subject: [PATCH 36/59] Fix unit test for multisite --- tests/php/test-class-ajax-customize-snapshot-manager.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index 096482ad..d21ca720 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -453,6 +453,10 @@ function test_ajax_update_snapshot_schedule() { 'snapshot_publish_date' => $tomorrow, ), ); + require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; + if ( ! method_exists( 'WP_Customize_Manager', 'prepare_setting_validity_for_js' ) ) { + unset( $expected_results['data']['errors'], $expected_results['data']['setting_validities'] ); + } // Get the results. $response = json_decode( $this->_last_response, true ); $this->assertSame( $expected_results, $response ); From 5640162f8ad77f916ced078e0cefaab030c7ef8b Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Fri, 5 Aug 2016 20:11:30 +0530 Subject: [PATCH 37/59] Fix unit test for multisite for real --- tests/php/test-class-ajax-customize-snapshot-manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/php/test-class-ajax-customize-snapshot-manager.php b/tests/php/test-class-ajax-customize-snapshot-manager.php index d21ca720..5e8b6d0a 100644 --- a/tests/php/test-class-ajax-customize-snapshot-manager.php +++ b/tests/php/test-class-ajax-customize-snapshot-manager.php @@ -455,7 +455,7 @@ function test_ajax_update_snapshot_schedule() { ); require_once ABSPATH . WPINC . '/class-wp-customize-manager.php'; if ( ! method_exists( 'WP_Customize_Manager', 'prepare_setting_validity_for_js' ) ) { - unset( $expected_results['data']['errors'], $expected_results['data']['setting_validities'] ); + unset( $expected_results['data']['setting_validities'] ); } // Get the results. $response = json_decode( $this->_last_response, true ); From 976c740cc262f71f6b58d6a5cd2145d25858df18 Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 17:36:49 -0700 Subject: [PATCH 38/59] Ensure a scheduled Snapshot is published after the Customizer is saved --- js/customize-snapshots.js | 5 ++--- php/class-customize-snapshot-manager.php | 13 +++++++++++-- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index d33ef980..cd030633 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -332,9 +332,7 @@ component.schedule.template.find( '.reset-time a' ).on( 'click', function( event ) { event.preventDefault(); - component.updateSchedule(); - component.populateSetting(); } ); } @@ -356,8 +354,9 @@ api.state( 'saved' ).bind( function( saved ) { if ( saved && ! _.isEmpty( component.schedule.template ) ) { + component.data.publishDate = component.getCurrentTime(); + component.updateSchedule(); component.schedule.template.hide(); - component.data.publishDate = '0000-00-00 00:00:00'; component.data.dirty = false; } } ); diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 20db2d7e..32be9564 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -626,9 +626,18 @@ function( $value ) { } if ( ! $this->snapshot->post() || 'publish' !== $this->snapshot->post()->post_status ) { - $r = $this->snapshot->save( array( + $args = array( 'status' => 'publish', - ) ); + ); + + // Ensure a scheduled Snapshot is published. + if ( 'future' === $this->snapshot->post()->post_status ) { + $args['edit_date'] = true; + $args['post_date'] = current_time( 'mysql', false ); + $args['post_date_gmt'] = current_time( 'mysql', true ); + } + + $r = $this->snapshot->save( $args ); if ( is_wp_error( $r ) ) { add_filter( 'customize_save_response', function( $response ) use ( $r, $that ) { $response['snapshot_errors'] = $that->prepare_errors_for_response( $r ); From 7d1a8ccbb6fda0eb15df26d306563e6e8a3e8c7d Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 17:44:21 -0700 Subject: [PATCH 39/59] Fix tests --- php/class-customize-snapshot-manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 32be9564..0312eeb4 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -631,7 +631,7 @@ function( $value ) { ); // Ensure a scheduled Snapshot is published. - if ( 'future' === $this->snapshot->post()->post_status ) { + if ( $this->snapshot->post() && 'future' === $this->snapshot->post()->post_status ) { $args['edit_date'] = true; $args['post_date'] = current_time( 'mysql', false ); $args['post_date_gmt'] = current_time( 'mysql', true ); From a5294bd839025ac19edcae9be342b465d7018558 Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Fri, 5 Aug 2016 18:24:52 -0700 Subject: [PATCH 40/59] Format template output --- php/class-customize-snapshot-manager.php | 24 ++++++++++++++---------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 0312eeb4..bf854973 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1164,23 +1164,27 @@ public function render_templates() { <script id="tmpl-snapshot-scheduled-countdown" type="text/html"> <# if ( data.remainingTime < 2 * 60 ) { #> - <?php esc_html_e( 'This is scheduled for publishing in about a minute.', 'customize-snapshots' ); ?> + <?php esc_html_e( 'This is scheduled for publishing in about a minute.', 'customize-snapshots' ); ?> + <# } else if ( data.remainingTime < 60 * 60 ) { #> - <?php - /* translators: %s is a placeholder for the Underscore template var */ - echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s minutes.', 'customize-snapshots' ), '{{ Math.ceil( data.remainingTime / 60 ) }}' ); - ?> + <?php + /* translators: %s is a placeholder for the Underscore template var */ + echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s minutes.', 'customize-snapshots' ), '{{ Math.ceil( data.remainingTime / 60 ) }}' ); + ?> + <# } else if ( data.remainingTime < 24 * 60 * 60 ) { #> - <?php - /* translators: %s is a placeholder for the Underscore template var */ - echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s hours.', 'customize-snapshots' ), '{{ Math.round( data.remainingTime / 60 / 60 * 10 ) / 10 }}' ); - ?> + <?php + /* translators: %s is a placeholder for the Underscore template var */ + echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s hours.', 'customize-snapshots' ), '{{ Math.round( data.remainingTime / 60 / 60 * 10 ) / 10 }}' ); + ?> + <# } else { #> <?php /* translators: %s is a placeholder for the Underscore template var */ echo sprintf( esc_html__( 'This snapshot is scheduled for publishing in about %s days.', 'customize-snapshots' ), '{{ Math.round( data.remainingTime / 60 / 60 / 24 * 10 ) / 10 }}' ); ?> - <# } #> + + <# } #> </script> <script type="text/html" id="tmpl-snapshot-save"> From f0391dd5655b3a464a12b2543765f615d8044375 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Mon, 8 Aug 2016 12:06:12 +0530 Subject: [PATCH 41/59] Fix edit link visiblity issue on dirty snapshot state --- js/customize-snapshots.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index cd030633..7b3132db 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -350,6 +350,7 @@ api.bind( 'change', function() { component.data.dirty = true; + component.schedule.template.find( 'a.snapshot-edit-link' ).hide(); } ); api.state( 'saved' ).bind( function( saved ) { @@ -392,7 +393,9 @@ component.data.publishDate = component.data.publishDate.slice( sliceBegin, sliceEnd ) + '00'; // Update date controls. - component.schedule.template.find( 'a.snapshot-edit-link' ).attr( 'href', component.data.editLink ); + component.schedule.template.find( 'a.snapshot-edit-link' ) + .attr( 'href', component.data.editLink ) + .show(); parsed = component.parseDateTime( component.data.publishDate ); component.schedule.inputs.each( function() { From 00a674cab2ddd981ed5bf9721fb4b67c54f4aa1b Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Mon, 8 Aug 2016 23:30:55 +0530 Subject: [PATCH 42/59] Optimize extend in js --- js/customize-snapshots.js | 20 +++++++------------- 1 file changed, 7 insertions(+), 13 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 7b3132db..636ca6b7 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -469,24 +469,18 @@ */ component.sendUpdateSnapshotRequest = function( options ) { var spinner = $( '#customize-header-actions .spinner' ), - request, data, args; + request, data; - args = _.extend( + data = _.extend( { status: 'draft' }, - options - ); - - data = _.extend( args, { - nonce: api.settings.nonce.snapshot, - customize_snapshot_uuid: component.data.uuid - } ); - - data = _.extend( - {}, api.previewer.query(), - data + options, + { + nonce: api.settings.nonce.snapshot, + customize_snapshot_uuid: component.data.uuid + } ); request = wp.ajax.post( 'customize_update_snapshot', data ); From 1daff6cbeadc75ba08526c1db1472f03cb33135b Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Mon, 8 Aug 2016 23:54:11 +0530 Subject: [PATCH 43/59] Fix error args not undefine --- js/customize-snapshots.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 636ca6b7..40cf91e2 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -529,7 +529,7 @@ } api.state( 'snapshot-saved' ).set( true ); - if ( 'pending' === args.status ) { + if ( 'pending' === data.status ) { api.state( 'snapshot-submitted' ).set( true ); } component.resetSavedStateQuietly(); From 2f3fa54fc0df22164e2c0701b74f9e311d2383d7 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Tue, 9 Aug 2016 11:25:41 +0530 Subject: [PATCH 44/59] Fix UI issue --- css/customize-snapshots.css | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 5a872a12..208f56a6 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -148,3 +148,7 @@ -webkit-appearance: none; margin: 0; } +.wp-full-overlay-sidebar .wp-full-overlay-header{ + padding-left: 15px !important; + z-index: 1000001; !important; +} \ No newline at end of file From 11b5acdee5dbead2d8f7e50a112683fa229e99aa Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Tue, 9 Aug 2016 11:39:36 +0530 Subject: [PATCH 45/59] Remove extra semicolon --- css/customize-snapshots.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index 208f56a6..ffabe742 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -150,5 +150,5 @@ } .wp-full-overlay-sidebar .wp-full-overlay-header{ padding-left: 15px !important; - z-index: 1000001; !important; + z-index: 1000001 !important; } \ No newline at end of file From e98c6f1f04488c5adba427b64b58d3dd11f76049 Mon Sep 17 00:00:00 2001 From: Derek Herman <derek@valendesigns.com> Date: Tue, 9 Aug 2016 21:24:23 -0700 Subject: [PATCH 46/59] Simplify the z-index issue, only slightly --- css/customize-snapshots.css | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/css/customize-snapshots.css b/css/customize-snapshots.css index ffabe742..ddb771d6 100644 --- a/css/customize-snapshots.css +++ b/css/customize-snapshots.css @@ -15,11 +15,13 @@ #snapshot-preview-link:active { color: #191e23; } + #snapshot-save { float: right; margin-top: 9px; margin-right: 9px; } + #customize-header-actions:not(.button-added) .button#save { visibility: hidden; } @@ -140,15 +142,22 @@ min-width: 10%; width: auto; } + .snapshot-schedule-control input.date-input { -moz-appearance: textfield; } + .snapshot-schedule-control input.date-input::-webkit-outer-spin-button, .snapshot-schedule-control input.date-input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0; } -.wp-full-overlay-sidebar .wp-full-overlay-header{ - padding-left: 15px !important; - z-index: 1000001 !important; -} \ No newline at end of file + +.wp-full-overlay .wp-full-overlay-sidebar .wp-full-overlay-header { + padding-left: 15px; + z-index: 500101; +} + +.select2-container { + z-index: 500100 !important; +} From 096d44cf6323021531336ca48f793c5ad7eb849c Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 10 Aug 2016 12:56:07 +0530 Subject: [PATCH 47/59] Add unit-test for get_month_choices and override_post_date_default_data --- .../test-class-customize-snapshot-manager.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 24854795..93abb875 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -931,4 +931,31 @@ public function test_render_templates() { $this->assertContains( 'tmpl-snapshot-save', $templates ); $this->assertContains( 'tmpl-snapshot-dialog-error', $templates ); } + + /** + * Test month choices + * + * @covers Customize_Snapshot_Manager::get_month_choices() + */ + public function test_get_month_choices() { + $data = $this->manager->get_month_choices(); + $this->assertArrayHasKey( 'month_choices', $data ); + $this->assertCount( 12, $data['month_choices'] ); + } + + /** + * Test override post date if empty. + * + * @covers Customize_Snapshot_Manager::override_post_date_default_data() + */ + public function test_override_post_date_default_data() { + $post_id = $this->factory()->post->create(); + $post = get_post( $post_id ); + $post->post_date = $post->post_date_gmt = $post->post_modified = $post->post_modified_gmt = '0000-00-00 00:00:00'; + $this->manager->override_post_date_default_data( $post ); + $this->assertNotEquals( $post->post_date, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_date_gmt, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_modified, '0000-00-00 00:00:00' ); + $this->assertNotEquals( $post->post_modified_gmt, '0000-00-00 00:00:00' ); + } } From add9311ab1dbbb8f624812eab32ad1d0e860d4d9 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 10 Aug 2016 13:10:49 +0530 Subject: [PATCH 48/59] Title and screen reader text add --- php/class-customize-snapshot-manager.php | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 80640577..a11e01cb 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1390,13 +1390,14 @@ public function render_templates() { <div class="snapshot-schedule-title"> <h3> <?php esc_html_e( 'Schedule Snapshot', 'customize-snapshots' ); ?> - <span class="reset-time">(<a href="#"><?php esc_html_e( 'Reset', 'customize-snapshots' ) ?></a>)</span> + <span class="reset-time">(<a href="#" title="<?php esc_attr_e( 'Reset schedule date to original or current date', 'customize-snapshots' ); ?>"><?php esc_html_e( 'Reset', 'customize-snapshots' ) ?></a>)</span> </h3> <span class="snapshot-schedule-description"> <span class="snapshot-scheduled-countdown"></span> <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> - <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" aria-expanded="false"></a> + <?php $edit_snapshot_text = __( 'Edit Snapshot', 'customize-snapshots' ); ?> + <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" title="<?php echo esc_attr( $edit_snapshot_text ); ?>" aria-expanded="false"><span class="screen-reader-text"><?php echo esc_html( $edit_snapshot_text ); ?></span></a> </div> <div class="snapshot-schedule-control"> <# From 00857ba7089d585f8ffcab775147787c00d778a8 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 10 Aug 2016 13:19:58 +0530 Subject: [PATCH 49/59] Check post exists check more readable --- php/class-customize-snapshot-manager.php | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index a11e01cb..441e3d9f 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -643,9 +643,9 @@ public function enqueue_controls_scripts() { $exports = apply_filters( 'customize_snapshots_export_data', array( 'action' => self::AJAX_ACTION, 'uuid' => $this->snapshot ? $this->snapshot->uuid() : self::generate_uuid(), - 'editLink' => $this->snapshot ? get_edit_post_link( $post, 'raw' ) : '', - 'publishDate' => $this->snapshot ? $post->post_date : '', - 'postStatus' => $this->snapshot ? $post->post_status : '', + 'editLink' => isset( $post ) ? get_edit_post_link( $post, 'raw' ) : '', + 'publishDate' => isset( $post->post_date ) ? $post->post_date : '', + 'postStatus' => isset( $post->post_status ) ? $post->post_status : '', 'currentUserCanPublish' => current_user_can( 'customize_publish' ), 'initialServerDate' => current_time( 'mysql', false ), 'initialServerTimestamp' => floor( microtime( true ) * 1000 ), From ae7189dbce89e3c49f9f4756b1aab290dded9e47 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 10 Aug 2016 13:37:37 +0530 Subject: [PATCH 50/59] Fix js dateValueOf function --- js/customize-snapshots.js | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/js/customize-snapshots.js b/js/customize-snapshots.js index 40cf91e2..3934d407 100644 --- a/js/customize-snapshots.js +++ b/js/customize-snapshots.js @@ -774,16 +774,18 @@ /** * Get the primitive value of a Date object. * - * @param {string} dateString The post status for the snapshot. + * @param {string|Date} dateString The post status for the snapshot. * @returns {object|string} The primitive value or date object. */ component.dateValueOf = function( dateString ) { var date; - if ( _.isUndefined( dateString ) ) { - date = new Date(); - } else { + if ( 'string' === typeof dateString ) { date = new Date( dateString ); + } else if ( dateString instanceof Date ) { + date = dateString; + } else { + date = new Date(); } return date.valueOf(); From 59a74848369fc61745862430db45a72a66fa305a Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Wed, 10 Aug 2016 14:40:03 +0530 Subject: [PATCH 51/59] Update unit-test --- .../test-class-customize-snapshot-manager.php | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 93abb875..c2fd4d16 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -921,7 +921,7 @@ public function test_add_post_edit_and_exit_links() { /** * Test render templates. * - * @see Customize_Snapshot_Manager::render_templates() + * @covers Customize_Snapshot_Manager::render_templates() */ public function test_render_templates() { ob_start(); @@ -930,6 +930,21 @@ public function test_render_templates() { ob_end_clean(); $this->assertContains( 'tmpl-snapshot-save', $templates ); $this->assertContains( 'tmpl-snapshot-dialog-error', $templates ); + $this->assertContains( 'tmpl-snapshot-preview-link', $templates ); + $this->assertContains( 'tmpl-snapshot-schedule-button', $templates ); + $this->assertContains( 'tmpl-snapshot-schedule', $templates ); + $this->assertContains( 'tmpl-snapshot-scheduled-countdown', $templates ); + $this->assertContains( 'tmpl-snapshot-submit', $templates ); + } + + /** + * Test format_gmt_offset + * + * @covers Customize_Snapshot_Manager::format_gmt_offset() + */ + public function test_format_gmt_offset() { + $offset = $this->manager->format_gmt_offset( 7.0 ); + $this->assertEquals( '+7', $offset ); } /** From f825bea8a543c4d13cd01163cac01303b11f814e Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 17:50:21 -0700 Subject: [PATCH 52/59] Add test for Customize_Snapshot_Manager::preview_snapshot_settings(); fix cover phpdoc tag --- .../test-class-customize-snapshot-manager.php | 104 +++++++++++------- tests/php/test-class-post-type.php | 12 +- tests/test-customize-snapshots.php | 4 +- 3 files changed, 72 insertions(+), 48 deletions(-) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index c2fd4d16..1513e3e1 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -190,7 +190,7 @@ function test_construct_with_customize_bootstrapped() { /** * Tests init hooks. * - * @covers Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() */ public function test_init_hooks() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -219,8 +219,8 @@ public function test_init_hooks() { /** * Tests init hooks. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::read_current_snapshot_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::read_current_snapshot_uuid() */ public function test_read_current_snapshot_uuid() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -244,8 +244,8 @@ public function test_read_current_snapshot_uuid() { /** * Tests load_snapshot. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::load_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::load_snapshot() */ public function test_load_snapshot() { global $wp_actions; @@ -272,8 +272,8 @@ public function test_load_snapshot() { /** * Tests setup_preview_ajax_requests. * - * @covers Customize_Snapshot_Manager::init() - * @covers Customize_Snapshot_Manager::setup_preview_ajax_requests() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::setup_preview_ajax_requests() */ public function test_setup_preview_ajax_requests() { wp_set_current_user( $this->user_id ); @@ -293,7 +293,7 @@ public function test_setup_preview_ajax_requests() { /** * Tests override_request_method. * - * @covers Customize_Snapshot_Manager::override_request_method() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::override_request_method() */ public function test_override_request_method() { global $wp; @@ -328,7 +328,7 @@ public function test_override_request_method() { /** * Tests doing_customize_save_ajax. * - * @covers Customize_Snapshot_Manager::doing_customize_save_ajax() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::doing_customize_save_ajax() */ public function test_doing_customize_save_ajax() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -344,7 +344,7 @@ public function test_doing_customize_save_ajax() { /** * Tests ensure_customize_manager. * - * @covers Customize_Snapshot_Manager::ensure_customize_manager() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::ensure_customize_manager() */ public function test_ensure_customize_manager() { global $wp_customize; @@ -359,7 +359,7 @@ public function test_ensure_customize_manager() { /** * Tests is_theme_active. * - * @covers Customize_Snapshot_Manager::is_theme_active() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_theme_active() */ public function test_is_theme_active() { global $wp_customize; @@ -374,7 +374,7 @@ public function test_is_theme_active() { /** * Tests should_import_and_preview_snapshot. * - * @covers Customize_Snapshot_Manager::should_import_and_preview_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::should_import_and_preview_snapshot() */ public function test_should_import_and_preview_snapshot() { global $pagenow, $wp_customize; @@ -431,7 +431,7 @@ public function test_should_import_and_preview_snapshot() { /** * Tests is_previewing_settings. * - * @covers Customize_Snapshot_Manager::is_previewing_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_previewing_settings() */ public function test_is_previewing_settings() { $_REQUEST['customize_snapshot_uuid'] = self::UUID; @@ -448,7 +448,7 @@ public function test_is_previewing_settings() { /** * Tests is_previewing_settings. * - * @covers Customize_Snapshot_Manager::is_previewing_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_previewing_settings() */ public function test_is_previewing_settings_via_preview_init() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -460,16 +460,40 @@ public function test_is_previewing_settings_via_preview_init() { /** * Tests preview_snapshot_settings. * - * @covers Customize_Snapshot_Manager::preview_snapshot_settings() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_snapshot_settings() */ public function test_preview_snapshot_settings() { - $this->markTestIncomplete(); + global $wp_actions; + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + 'blogname' => array( 'value' => 'Hello' ), + ), + 'status' => 'draft', + ) ); + + // Prevent init from calling preview_snapshot_settings straight away. + unset( $wp_actions['wp_loaded'] ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + $manager->ensure_customize_manager(); + do_action( 'customize_register', $manager->customize_manager ); + $manager->customize_manager->set_post_value( 'blogname', 'Hello' ); + $this->assertFalse( $manager->is_previewing_settings() ); + $this->assertFalse( $manager->customize_manager->get_setting( 'blogname' )->dirty ); + $this->assertNotEquals( 'Hello', get_option( 'blogname' ) ); + $manager->preview_snapshot_settings(); + $this->assertEquals( 'Hello', get_option( 'blogname' ) ); + $this->assertTrue( $manager->customize_manager->get_setting( 'blogname' )->dirty ); } /** * Tests import_snapshot_data. * - * @covers Customize_Snapshot_Manager::import_snapshot_data() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::import_snapshot_data() */ public function test_import_snapshot_data() { $this->markTestIncomplete(); @@ -478,7 +502,7 @@ public function test_import_snapshot_data() { /** * Tests add_widget_setting_preview_filters. * - * @covers Customize_Snapshot_Manager::add_widget_setting_preview_filters() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_widget_setting_preview_filters() */ public function test_add_widget_setting_preview_filters() { $this->markTestIncomplete(); @@ -487,7 +511,7 @@ public function test_add_widget_setting_preview_filters() { /** * Tests add_nav_menu_setting_preview_filters. * - * @covers Customize_Snapshot_Manager::add_nav_menu_setting_preview_filters() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_nav_menu_setting_preview_filters() */ public function test_add_nav_menu_setting_preview_filters() { $this->markTestIncomplete(); @@ -496,7 +520,7 @@ public function test_add_nav_menu_setting_preview_filters() { /** * Tests preview_early_nav_menus_in_customizer. * - * @covers Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() */ public function test_preview_early_nav_menus_in_customizer() { $this->markTestIncomplete(); @@ -523,7 +547,7 @@ public function test_add_snapshot_uuid_to_return_url() { /** * Tests show_theme_switch_error. * - * @covers Customize_Snapshot_Manager::show_theme_switch_error() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::show_theme_switch_error() */ function test_show_theme_switch_error() { $this->markTestIncomplete(); @@ -532,7 +556,7 @@ function test_show_theme_switch_error() { /** * Tests get_theme_switch_error. * - * @covers Customize_Snapshot_Manager::get_theme_switch_error() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::get_theme_switch_error() */ function test_get_theme_switch_error() { $this->markTestIncomplete(); @@ -541,7 +565,7 @@ function test_get_theme_switch_error() { /** * Tests check_customize_publish_authorization. * - * @covers Customize_Snapshot_Manager::check_customize_publish_authorization() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::check_customize_publish_authorization() */ function test_check_customize_publish_authorization() { $this->markTestIncomplete(); @@ -600,7 +624,7 @@ function test_enqueue_frontend_scripts() { /** * Test filter_customize_refresh_nonces. * - * @covers Customize_Snapshot_Manager::filter_customize_refresh_nonces() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::filter_customize_refresh_nonces() */ function test_filter_customize_refresh_nonces() { $this->markTestIncomplete(); @@ -621,7 +645,7 @@ function test_snapshot() { /** * Test publish snapshot with customize_save_after. * - * @covers Customize_Snapshot_Manager::publish_snapshot_with_customize_save_after() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::publish_snapshot_with_customize_save_after() */ function test_publish_snapshot_with_customize_save_after() { wp_set_current_user( $this->user_id ); @@ -645,7 +669,7 @@ function test_publish_snapshot_with_customize_save_after() { /** * Test prepare_snapshot_post_content_for_publish. * - * @covers Customize_Snapshot_Manager::prepare_snapshot_post_content_for_publish() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::prepare_snapshot_post_content_for_publish() */ public function test_prepare_snapshot_post_content_for_publish() { $snapshot_manager = get_plugin_instance()->customize_snapshot_manager; @@ -676,7 +700,7 @@ public function test_prepare_snapshot_post_content_for_publish() { /** * Test save_settings_with_publish_snapshot. * - * @covers Customize_Snapshot_Manager::save_settings_with_publish_snapshot() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::save_settings_with_publish_snapshot() */ public function test_save_settings_with_publish_snapshot() { $post_type = $this->manager->post_type; @@ -740,7 +764,7 @@ public function test_save_settings_with_publish_snapshot() { /** * Test prepare_errors_for_response. * - * @covers Customize_Snapshot_Manager::prepare_errors_for_response() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::prepare_errors_for_response() */ public function test_prepare_errors_for_response() { $this->markTestIncomplete(); @@ -749,7 +773,7 @@ public function test_prepare_errors_for_response() { /** * Tests generate_uuid. * - * @covers Customize_Snapshot_Manager::generate_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::generate_uuid() */ public function test_generate_uuid() { $this->markTestIncomplete(); @@ -758,7 +782,7 @@ public function test_generate_uuid() { /** * Tests is_valid_uuid. * - * @covers Customize_Snapshot_Manager::is_valid_uuid() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::is_valid_uuid() */ public function test_is_valid_uuid() { $this->markTestIncomplete(); @@ -814,7 +838,7 @@ public function test_customize_menu_return() { /** * Tests print_admin_bar_styles. * - * @covers Customize_Snapshot_Manager::print_admin_bar_styles() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::print_admin_bar_styles() */ public function test_print_admin_bar_styles() { $manager = new Customize_Snapshot_Manager( $this->plugin ); @@ -828,7 +852,7 @@ public function test_print_admin_bar_styles() { /** * Test replace_customize_link. * - * @covers Customize_Snapshot_Manager::replace_customize_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::replace_customize_link() */ public function test_replace_customize_link() { global $wp_admin_bar; @@ -871,10 +895,10 @@ public function test_replace_customize_link() { /** * Test misc admin bar extensions. * - * @covers Customize_Snapshot_Manager::add_post_edit_screen_link() - * @covers Customize_Snapshot_Manager::add_snapshot_exit_link() - * @covers Customize_Snapshot_Manager::add_resume_snapshot_link() - * @covers Customize_Snapshot_Manager::remove_all_non_snapshot_admin_bar_links() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_post_edit_screen_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_snapshot_exit_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::add_resume_snapshot_link() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::remove_all_non_snapshot_admin_bar_links() */ public function test_add_post_edit_and_exit_links() { global $wp_admin_bar; @@ -921,7 +945,7 @@ public function test_add_post_edit_and_exit_links() { /** * Test render templates. * - * @covers Customize_Snapshot_Manager::render_templates() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::render_templates() */ public function test_render_templates() { ob_start(); @@ -940,7 +964,7 @@ public function test_render_templates() { /** * Test format_gmt_offset * - * @covers Customize_Snapshot_Manager::format_gmt_offset() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::format_gmt_offset() */ public function test_format_gmt_offset() { $offset = $this->manager->format_gmt_offset( 7.0 ); @@ -950,7 +974,7 @@ public function test_format_gmt_offset() { /** * Test month choices * - * @covers Customize_Snapshot_Manager::get_month_choices() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::get_month_choices() */ public function test_get_month_choices() { $data = $this->manager->get_month_choices(); @@ -961,7 +985,7 @@ public function test_get_month_choices() { /** * Test override post date if empty. * - * @covers Customize_Snapshot_Manager::override_post_date_default_data() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::override_post_date_default_data() */ public function test_override_post_date_default_data() { $post_id = $this->factory()->post->create(); diff --git a/tests/php/test-class-post-type.php b/tests/php/test-class-post-type.php index b2027887..773c6209 100644 --- a/tests/php/test-class-post-type.php +++ b/tests/php/test-class-post-type.php @@ -63,7 +63,7 @@ public function test_register() { /** * Test filter_post_type_link. * - * @covers Post_Type::filter_post_type_link() + * @covers CustomizeSnapshots\Post_Type::filter_post_type_link() */ function test_filter_post_type_link() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -382,7 +382,7 @@ public function test_find_post() { /** * Test getting the snapshot array out of the post_content. * - * @covers Post_Type::get_post_content() + * @covers CustomizeSnapshots\Post_Type::get_post_content() * @expectedException \PHPUnit_Framework_Error_Warning */ public function test_get_post_content() { @@ -626,7 +626,7 @@ function test_filter_user_has_cap() { /** * Tests display_post_states. * - * @covers Post_Type::display_post_states() + * @covers CustomizeSnapshots\Post_Type::display_post_states() */ public function test_display_post_states() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -646,7 +646,7 @@ public function test_display_post_states() { /** * Tests show_publish_error_admin_notice. * - * @covers Post_Type::show_publish_error_admin_notice() + * @covers CustomizeSnapshots\Post_Type::show_publish_error_admin_notice() */ public function test_show_publish_error_admin_notice() { global $current_screen, $post; @@ -687,7 +687,7 @@ public function test_show_publish_error_admin_notice() { /** * Tests disable_revision_ui_for_published_posts. * - * @covers Post_Type::disable_revision_ui_for_published_posts() + * @covers CustomizeSnapshots\Post_Type::disable_revision_ui_for_published_posts() */ public function test_disable_revision_ui_for_published_posts() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); @@ -716,7 +716,7 @@ public function test_disable_revision_ui_for_published_posts() { /** * Tests hide_disabled_publishing_actions. * - * @covers Post_Type::hide_disabled_publishing_actions() + * @covers CustomizeSnapshots\Post_Type::hide_disabled_publishing_actions() */ public function test_hide_disabled_publishing_actions() { $post_type = new Post_Type( $this->plugin->customize_snapshot_manager ); diff --git a/tests/test-customize-snapshots.php b/tests/test-customize-snapshots.php index bf391a53..0b326566 100644 --- a/tests/test-customize-snapshots.php +++ b/tests/test-customize-snapshots.php @@ -47,7 +47,7 @@ function test_customize_snapshots_php_version_text() { /** * Tests is_previewing_settings(). * - * @covers is_previewing_settings() + * @see is_previewing_settings() */ public function test_is_previewing_settings() { $this->assertFalse( is_previewing_settings() ); @@ -58,7 +58,7 @@ public function test_is_previewing_settings() { /** * Tests current_snapshot_uuid(). * - * @covers current_snapshot_uuid() + * @see current_snapshot_uuid() */ public function test_current_snapshot_uuid() { global $customize_snapshots_plugin; From 4ea308b203bcc1a8da715932d68b5c499fac99cd Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 17:57:20 -0700 Subject: [PATCH 53/59] Add test for Customize_Snapshot_Manager::import_snapshot_data() --- .../test-class-customize-snapshot-manager.php | 31 +++++++++++++++++-- 1 file changed, 28 insertions(+), 3 deletions(-) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 1513e3e1..cddacdc8 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -460,7 +460,6 @@ public function test_is_previewing_settings_via_preview_init() { /** * Tests preview_snapshot_settings. * - * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_snapshot_settings() */ public function test_preview_snapshot_settings() { @@ -481,7 +480,6 @@ public function test_preview_snapshot_settings() { $manager->init(); $manager->ensure_customize_manager(); do_action( 'customize_register', $manager->customize_manager ); - $manager->customize_manager->set_post_value( 'blogname', 'Hello' ); $this->assertFalse( $manager->is_previewing_settings() ); $this->assertFalse( $manager->customize_manager->get_setting( 'blogname' )->dirty ); $this->assertNotEquals( 'Hello', get_option( 'blogname' ) ); @@ -496,7 +494,34 @@ public function test_preview_snapshot_settings() { * @covers CustomizeSnapshots\Customize_Snapshot_Manager::import_snapshot_data() */ public function test_import_snapshot_data() { - $this->markTestIncomplete(); + global $wp_actions; + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + 'blogname' => array( 'value' => 'Hello' ), + 'blogdescription' => array( 'value' => null ), + ), + 'status' => 'draft', + ) ); + + // Prevent init from calling import_snapshot_data straight away. + unset( $wp_actions['setup_theme'] ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + $manager->ensure_customize_manager(); + do_action( 'customize_register', $manager->customize_manager ); + + $this->assertArrayNotHasKey( 'customized', $_POST ); + $this->assertArrayNotHasKey( 'customized', $_REQUEST ); + $this->assertArrayNotHasKey( 'blogname', $manager->customize_manager->unsanitized_post_values() ); + $this->assertArrayNotHasKey( 'blogdescription', $manager->customize_manager->unsanitized_post_values() ); + $manager->import_snapshot_data(); + $this->assertArrayHasKey( 'customized', $_POST ); + $this->assertArrayHasKey( 'customized', $_REQUEST ); + $this->assertArrayHasKey( 'blogname', $manager->customize_manager->unsanitized_post_values() ); + $this->assertArrayNotHasKey( 'blogdescription', $manager->customize_manager->unsanitized_post_values() ); } /** From 85e590c9c454a8e3a4385400e5a114c621062a48 Mon Sep 17 00:00:00 2001 From: Utkarsh Patel <iamutkarsh@live.com> Date: Thu, 11 Aug 2016 12:18:35 +0530 Subject: [PATCH 54/59] Add target blank on snapshot-edit link --- php/class-customize-snapshot-manager.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 441e3d9f..7464791f 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -1397,7 +1397,7 @@ public function render_templates() { <span class="timezone-info"><?php echo esc_html( $date_control_description ); ?></span> </span> <?php $edit_snapshot_text = __( 'Edit Snapshot', 'customize-snapshots' ); ?> - <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" title="<?php echo esc_attr( $edit_snapshot_text ); ?>" aria-expanded="false"><span class="screen-reader-text"><?php echo esc_html( $edit_snapshot_text ); ?></span></a> + <a href="{{ data.editLink }}" class="dashicons dashicons-edit snapshot-edit-link" target="_blank" title="<?php echo esc_attr( $edit_snapshot_text ); ?>" aria-expanded="false"><span class="screen-reader-text"><?php echo esc_html( $edit_snapshot_text ); ?></span></a> </div> <div class="snapshot-schedule-control"> <# From 14572fefe826fa9f4fe5101a83d08250d571d04a Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 23:27:59 -0700 Subject: [PATCH 55/59] Add test for setup_preview_ajax_requests in admin-ajax --- .../test-class-customize-snapshot-manager.php | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index cddacdc8..02aa143f 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -290,6 +290,36 @@ public function test_setup_preview_ajax_requests() { $this->assertEquals( 5, has_action( 'parse_request', array( $manager, 'override_request_method' ) ) ); } + + /** + * Tests setup_preview_ajax_requests for admin_ajax. + * + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::init() + * @covers CustomizeSnapshots\Customize_Snapshot_Manager::setup_preview_ajax_requests() + */ + public function test_setup_preview_ajax_requests_for_admin_ajax() { + global $pagenow; + wp_set_current_user( $this->user_id ); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'GET'; + $pagenow = 'admin-ajax.php'; // WPCS: Global override ok. + set_current_screen( 'admin-ajax' ); + $this->assertTrue( is_admin() ); + + $_REQUEST['wp_customize_preview_ajax'] = 'true'; + $_POST['customized'] = wp_slash( wp_json_encode( array( 'blogname' => 'Foo' ) ) ); + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + do_action( 'admin_init' ); + $this->do_customize_boot_actions( true ); + $this->assertTrue( is_customize_preview() ); + $this->assertFalse( has_action( 'shutdown', array( $this->wp_customize, 'customize_preview_signature' ) ) ); + $this->assertFalse( has_action( 'parse_request', array( $manager, 'override_request_method' ) ) ); + $this->assertEquals( 'GET', $_SERVER['REQUEST_METHOD'] ); + $this->assertEquals( 'Foo', get_option( 'blogname' ) ); + } + /** * Tests override_request_method. * From 4589448fbd447d7ee0b45232925f1690d2acb1b5 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 23:28:36 -0700 Subject: [PATCH 56/59] Test last line of override_request_method --- tests/php/test-class-customize-snapshot-manager.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 02aa143f..554a5907 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -353,6 +353,10 @@ public function test_override_request_method() { $this->assertEquals( 'foo=1&bar=2', $_SERVER['QUERY_STRING'] ); $this->assertArrayHasKey( 'foo', $_GET ); $this->assertArrayHasKey( 'bar', $_GET ); + + $_SERVER['REQUEST_METHOD'] = 'POST'; + $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] = 'PUT'; + $this->assertFalse( $manager->override_request_method() ); } /** From e416cedf76c9a8f446c1fadb703ee064f2f75df1 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 23:29:44 -0700 Subject: [PATCH 57/59] Add test for Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() --- php/class-customize-snapshot-manager.php | 11 +++++++ .../test-class-customize-snapshot-manager.php | 31 ++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/php/class-customize-snapshot-manager.php b/php/class-customize-snapshot-manager.php index 7464791f..d02b4369 100644 --- a/php/class-customize-snapshot-manager.php +++ b/php/class-customize-snapshot-manager.php @@ -525,6 +525,17 @@ public function preview_early_nav_menus_in_customizer() { ); if ( $is_nav_menu_setting ) { $setting->preview(); + + /* + * The following is redundant because it will be done later in + * Customize_Snapshot_Manager::preview_snapshot_settings(). + * Also note that the $setting instance here will likely be + * blown away inside of WP_Customize_Nav_Menus::customize_register(), + * when add_setting is called there. What matters here is that + * preview() is called on the setting _before_ the logic inside + * WP_Customize_Nav_Menus::customize_register() runs, so that + * the nav menu sections will be created. + */ $setting->dirty = true; } } diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 554a5907..1ba34d8a 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -582,7 +582,36 @@ public function test_add_nav_menu_setting_preview_filters() { * @covers CustomizeSnapshots\Customize_Snapshot_Manager::preview_early_nav_menus_in_customizer() */ public function test_preview_early_nav_menus_in_customizer() { - $this->markTestIncomplete(); + global $pagenow; + $pagenow = 'customize.php'; // WPCS: Global override ok. + set_current_screen( 'customize' ); + + $menu_id = -123; + $setting_id = sprintf( 'nav_menu[%d]', $menu_id ); + + $_REQUEST['customize_snapshot_uuid'] = self::UUID; + $this->manager->post_type->save( array( + 'uuid' => self::UUID, + 'data' => array( + $setting_id => array( + 'value' => array( + 'name' => 'Bar', + ), + ), + ), + 'status' => 'draft', + ) ); + + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->init(); + do_action( 'customize_register', $manager->customize_manager ); + + $setting = $manager->customize_manager->get_setting( $setting_id ); + $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Setting', $setting ); + $nav_menu = wp_get_nav_menu_object( $menu_id ); + $this->assertEquals( 'Bar', $nav_menu->name ); + + $this->assertInstanceOf( 'WP_Customize_Nav_Menu_Section', $manager->customize_manager->get_section( $setting_id ) ); } /** From 1ed08b64ab3126e83c123887a7e4a767f36154fe Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Wed, 10 Aug 2016 23:42:11 -0700 Subject: [PATCH 58/59] Add tests for customize_preview_init and enqueue_preview_scripts --- .../test-class-customize-snapshot-manager.php | 33 +++++++++++++++++++ 1 file changed, 33 insertions(+) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 1ba34d8a..71875131 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -687,6 +687,39 @@ function test_enqueue_controls_scripts() { $this->assertTrue( wp_style_is( 'customize-snapshots', 'enqueued' ) ); } + /** + * Test customize preview init. + * + * @see Customize_Snapshot_Manager::customize_preview_init() + */ + function test_customize_preview_init() { + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $this->assertFalse( has_action( 'wp_enqueue_scripts', array( $manager, 'enqueue_preview_scripts' ) ) ); + $manager->customize_preview_init(); + $this->assertEquals( 10, has_action( 'wp_enqueue_scripts', array( $manager, 'enqueue_preview_scripts' ) ) ); + } + + /** + * Test enqueue preview scripts. + * + * @see Customize_Snapshot_Manager::enqueue_preview_scripts() + */ + function test_enqueue_preview_scripts() { + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $manager->ensure_customize_manager(); + $manager->init(); + $handle = 'customize-snapshots-preview'; + $this->assertFalse( wp_scripts()->query( $handle, 'enqueued' ) ); + $this->assertFalse( wp_styles()->query( $handle, 'enqueued' ) ); + $manager->enqueue_preview_scripts(); + $this->assertTrue( wp_scripts()->query( $handle, 'enqueued' ) ); + $this->assertTrue( wp_styles()->query( $handle, 'enqueued' ) ); + + $after = wp_scripts()->get_data( $handle, 'after' ); + $this->assertNotEmpty( $after ); + $this->assertContains( 'CustomizeSnapshotsPreview', join( '', $after ) ); + } + /** * Test enqueue frontend scripts. * From 535cbd57184d8bdfbc9a3f65aabdb96f62cb0082 Mon Sep 17 00:00:00 2001 From: Weston Ruter <weston@xwp.co> Date: Thu, 11 Aug 2016 00:12:44 -0700 Subject: [PATCH 59/59] Add test for filter_customize_refresh_nonces --- tests/php/test-class-customize-snapshot-manager.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/php/test-class-customize-snapshot-manager.php b/tests/php/test-class-customize-snapshot-manager.php index 71875131..62d60b93 100644 --- a/tests/php/test-class-customize-snapshot-manager.php +++ b/tests/php/test-class-customize-snapshot-manager.php @@ -748,7 +748,8 @@ function test_enqueue_frontend_scripts() { * @covers CustomizeSnapshots\Customize_Snapshot_Manager::filter_customize_refresh_nonces() */ function test_filter_customize_refresh_nonces() { - $this->markTestIncomplete(); + $manager = new Customize_Snapshot_Manager( $this->plugin ); + $this->assertArrayHasKey( 'snapshot', $manager->filter_customize_refresh_nonces( array() ) ); } /**