From 9bd192fab340e835280d9c2ca8f91c79131ebc0d Mon Sep 17 00:00:00 2001 From: Peter Westwood Date: Thu, 28 Feb 2013 15:14:34 +0000 Subject: [PATCH] Revisions: First pass an implementing a new UI/UX for reviewing the revisions of posts. See #23497 props adamsilverstein for the initial patch. This implements a new revisions ui using Backbone and preserves all the old methods of "integration" so the change should be transparent to plugins using revisi ons with CPTs. This is the first pass and so there are a number of things still to be resolved, more details in the ticket. Feedback welcomed. git-svn-id: http://core.svn.wordpress.org/trunk@23506 1a063a9b-81f0-0310-95a4-ce76da25c4cd --- wp-admin/admin-ajax.php | 4 +- wp-admin/css/colors-fresh.css | 15 +- wp-admin/css/revisions.css | 213 +++++++++ wp-admin/css/revisions.min.css | 0 wp-admin/css/wp-admin.css | 28 +- wp-admin/edit-form-advanced.php | 3 +- wp-admin/includes/ajax-actions.php | 137 +++++- wp-admin/js/revisions.js | 530 ++++++++++++++++++++++ wp-admin/js/revisions.min.js | 0 wp-admin/revision.php | 216 +++------ wp-includes/css/jquery-ui-slider.css | 544 +++++++++++++++++++++++ wp-includes/css/jquery-ui-slider.min.css | 0 wp-includes/js/template.js | 29 ++ wp-includes/js/template.min.js | 0 wp-includes/pluggable.php | 10 +- wp-includes/post-template.php | 27 +- wp-includes/script-loader.php | 7 +- wp-includes/wp-diff.php | 52 ++- 18 files changed, 1642 insertions(+), 173 deletions(-) create mode 100644 wp-admin/css/revisions.css create mode 100644 wp-admin/css/revisions.min.css create mode 100644 wp-admin/js/revisions.js create mode 100644 wp-admin/js/revisions.min.js create mode 100644 wp-includes/css/jquery-ui-slider.css create mode 100644 wp-includes/css/jquery-ui-slider.min.css create mode 100644 wp-includes/js/template.js create mode 100644 wp-includes/js/template.min.js diff --git a/wp-admin/admin-ajax.php b/wp-admin/admin-ajax.php index ed1ef9e499..d313854532 100644 --- a/wp-admin/admin-ajax.php +++ b/wp-admin/admin-ajax.php @@ -42,7 +42,7 @@ do_action( 'admin_init' ); $core_actions_get = array( 'fetch-list', 'ajax-tag-search', 'wp-compression-test', 'imgedit-preview', 'oembed-cache', - 'autocomplete-user', 'dashboard-widgets', 'logged-in', + 'autocomplete-user', 'dashboard-widgets', 'logged-in', 'revisions-data' ); $core_actions_post = array( @@ -56,7 +56,7 @@ $core_actions_post = array( 'save-widget', 'set-post-thumbnail', 'date_format', 'time_format', 'wp-fullscreen-save-post', 'wp-remove-post-lock', 'dismiss-wp-pointer', 'upload-attachment', 'get-attachment', 'query-attachments', 'save-attachment', 'save-attachment-compat', 'send-link-to-editor', - 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat', + 'send-attachment-to-editor', 'save-attachment-order', 'heartbeat' ); // Register core Ajax calls. diff --git a/wp-admin/css/colors-fresh.css b/wp-admin/css/colors-fresh.css index bf8700ea20..5126941017 100644 --- a/wp-admin/css/colors-fresh.css +++ b/wp-admin/css/colors-fresh.css @@ -1351,15 +1351,26 @@ div.wp-menu-image { /* Diff */ table.diff .diff-deletedline { - background-color: #fdd; + background-color: #ffe5e6; + color: #f2001f; + text-decoration: line-through; } table.diff .diff-deletedline del { background-color: #f99; } +table.diff .diff-deletedline-symbol { + color: #f2001f; +} + table.diff .diff-addedline { - background-color: #dfd; + background-color: #e9f6ea; + color: #00a500; +} + +table.diff .diff-addedline-symbol { + color: #00a500; } table.diff .diff-addedline ins { diff --git a/wp-admin/css/revisions.css b/wp-admin/css/revisions.css new file mode 100644 index 0000000000..76f51d5b00 --- /dev/null +++ b/wp-admin/css/revisions.css @@ -0,0 +1,213 @@ +/* Styles for the revision screen */ + +.revisiondiffcontainer { + width: 96%; +} + +.revisiondiffcontainer input.button { + margin: 2px; +} + +#diffrestore, #diffnext, #diffcancel { + float: right; + margin-right: 5px; +} + +#diffprevious, #difftitle, #difftitlefrom, #diff_from_current_revision { + float: left; + margin-left: 5px; + height: 35px; +} + +#diffprevious, #diffnext { + margin-top: 7px; + height: 30px; +} + +#diffheader, #diffsubheader { + clear: both; + width: 100%; +} + +#diffheader { + border-bottom: 2px solid #999; + width: 100%; + height: 45px; + line-height: 45px; + padding-top: 10px; +} + +#diffsubheader { + background-color: #eee; + border-bottom: 2px solid #999; + width: 100%; + height:35px; + line-height: 35px; +} + +#diffslider { + width: 70%; + margin-left: auto; + margin-right: auto; + text-align: center; + height: 3.5em; + +} + +#revisioncount { + width: 50%; + margin-left: auto; + margin-right: auto; + margin-top: 0; + line-height: 1em; + height: 1em; + text-align: center; + clear: none; + padding: 5px; +} + +.revisiondiffcontainer { + margin-top: 10px; +} + +#diffsliderwrap { + width: 80%; + margin-left: auto; + margin-right: auto; +} + +#diffsliderwrap #sliderinner { + position: relative; + top: 47px; +} + +#removedandadded { + width: 100% + padding-bottom: 30px; + padding-top: 3px; + font-size: 16px; +} + +#removed, #added { + width: auto; + text-align: left; + padding-left: 5px; + padding-right: 5px; + padding-top: 5px; + padding-bottom: 5px; + float: left; +} + +.diffsplit #added { + float: right; + width: 47%; + text-align: left; +} + +.diffsplit #removedandadded { + width: 100%; +} + +#added { + padding-left: 10px; +} + +#removed { + padding-left: 0px; + } + +#removed { + color: #d2281f; +} + +#added { + color: #00a100; +} + +#comparetworevisions { + float: right; + line-height: 35px; + padding-right: 5px; +} + +#comparetworevisions input{ + margin-right: 2px; +} + +#difftitle img, #difftitlefrom img { + vertical-align: middle; + margin-left: 5px; +} + +#showsplitviewoption, #toggleshowautosavesoption { + float: right; + padding-left: 10px; + padding-right: 10px; +} + +#revisionoptions { + margin-top: 0px; + line-height: 40px; + clear: both; + width: 100%; +} + +.comparetwo #diffprevious, .comparetwo #diffnext { + display: none; +} + +.comparetwo #diffslider { + width: 95%; +} + +.currentversion span#diff_left_current_revision { + display: inline; +} + +span#diff_left_current_revision, span#diff_from_current_revision { + display: none; +} + +span#diff_left_count, span#diff_left_count_inner { + display: inline; +} + +.currentversion span#diff_left_count, +.currentversion span#diff_left_count_inner, +.currentversion #difftitlefrom { + display: none; +} + +#difftitlefrom { + float: left; + display: none; +} + +.comparetwo #difftitlefrom, .comparetwo.currentversion span#diff_from_current_revision { + display: inline; +} +.comparetwo.currentversion #difftitlefrom { + display: none; +} + +#modelsloading { + float: right; + line-height: 30px; + display: none; + clear: none; + margin: 0; + margin-top: -40px; +} + +#modelsloading .spinner { + float: left; + } + +.leftmodelloading #modelsloading, +.rightmodelloading #modelsloading, +.leftmodelloading #modelsloading .spinner, +.rightmodelloading #modelsloading .spinner { + display: inline; +} + + diff --git a/wp-admin/css/revisions.min.css b/wp-admin/css/revisions.min.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wp-admin/css/wp-admin.css b/wp-admin/css/wp-admin.css index 7299d3f627..4cfc76a8b8 100644 --- a/wp-admin/css/wp-admin.css +++ b/wp-admin/css/wp-admin.css @@ -3504,7 +3504,19 @@ table.diff { } table.diff col.content { - width: 50%; + width: auto; +} + +table.diff col.content.diffsplit { + width: 48%; +} + +table.diff col.diffsplit.middle { + width: 4%; +} + +table.diff col.ltype { + width: 30px; } table.diff tr { @@ -8808,3 +8820,17 @@ a.widget-control-edit { .locale-lt-lt .inline-edit-row fieldset label span.input-text-wrap { margin-left: 8em; } + +#revisions-meta-mostrecent, +#revisions-meta-stored, +#revisions-meta-oldest, +#revisions-meta-link { + line-height: 30px; + height: 30px; + vertical-align: middle; + padding-right: 10px; +} +#revisions-meta-mostrecent img, +#revisions-meta-oldest img { +vertical-align: middle; +} diff --git a/wp-admin/edit-form-advanced.php b/wp-admin/edit-form-advanced.php index 79d18da2f4..4eeb7fab06 100644 --- a/wp-admin/edit-form-advanced.php +++ b/wp-admin/edit-form-advanced.php @@ -168,7 +168,8 @@ if ( post_type_supports($post_type, 'author') ) { add_meta_box('authordiv', __('Author'), 'post_author_meta_box', null, 'normal', 'core'); } -if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID && wp_get_post_revisions( $post_ID ) ) +// TODO review this count() - why do we need to add it? +if ( post_type_supports($post_type, 'revisions') && 0 < $post_ID && count ( wp_get_post_revisions( $post_ID ) ) > 1 ) add_meta_box('revisionsdiv', __('Revisions'), 'post_revisions_meta_box', null, 'normal', 'core'); do_action('add_meta_boxes', $post_type, $post); diff --git a/wp-admin/includes/ajax-actions.php b/wp-admin/includes/ajax-actions.php index 0fabe2a50d..b9c7f13d84 100644 --- a/wp-admin/includes/ajax-actions.php +++ b/wp-admin/includes/ajax-actions.php @@ -1379,7 +1379,7 @@ function wp_ajax_inline_save_tax() { global $wp_list_table; check_ajax_referer( 'taxinlineeditnonce', '_inline_edit' ); - + $post_data = wp_unslash( $_POST ); $taxonomy = sanitize_key( $post_data['taxonomy'] ); @@ -2134,3 +2134,138 @@ function wp_ajax_nopriv_heartbeat() { wp_send_json($response); } +function wp_ajax_revisions_data() { + check_ajax_referer( 'revisions-ajax-nonce', 'nonce' ); + + $compareto = isset( $_GET['compareto'] ) ? absint( $_GET['compareto'] ) : 0; + $showautosaves = isset( $_GET['showautosaves'] ) ? $_GET['showautosaves'] : ''; + $show_split_view = isset( $_GET['show_split_view'] ) ? $_GET['show_split_view'] : ''; + $postid = isset( $_GET['postid'] ) ? absint( $_GET['postid'] ) : ''; + + $comparetwomode = ( '' == $postid ) ? false : true; + // + //TODO: currently code returns all possible comparisons for the indicated 'compareto' revision + //however, the front end prevents users from pulling the right handle past the left or the left pass the right, + //so only the possible diffs need be generated + // + $alltherevisions = array(); + + if ( '' == $postid ) + $postid = $compareto; + + if ( ! current_user_can( 'read_post', $postid ) ) + continue; + + if ( ! $revisions = wp_get_post_revisions( $postid ) ) + return; + + //if we are comparing two revisions, the first 'revision' represented by the leftmost + //slider position is the current revision, prepend a comparison to this revision + if ( $comparetwomode ) + array_unshift( $revisions, get_post( $postid ) ); + + $count = 1; + foreach ( $revisions as $revision ) : + if ( 'true' != $showautosaves && wp_is_post_autosave( $revision ) ) + continue; + + $revision_from_date_author = ''; + + + $left_revision = get_post( $compareto ); + $right_revision = get_post( $revision ); + + $author = get_the_author_meta( 'display_name', $revision->post_author ); + /* translators: revision date format, see http://php.net/date */ + $datef = _x( 'j F, Y @ G:i:s', 'revision date format'); + + $gravatar = get_avatar( $revision->post_author, 18 ); + + $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); + $revision_date_author = sprintf( + '%s %s, %s %s (%s)', + $gravatar, + $author, + human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ), + __( ' ago ' ), + $date + ); + + if ( $comparetwomode ) { + $compareto_gravatar = get_avatar( $left_revision->post_author, 18 ); + $compareto_author = get_the_author_meta( 'display_name', $left_revision->post_author ); + $compareto_date = date_i18n( $datef, strtotime( $left_revision->post_modified ) ); + + $revision_from_date_author = sprintf( + '%s %s, %s %s (%s)', + $compareto_gravatar, + $compareto_author, + human_time_diff( strtotime( $left_revision->post_modified ), current_time( 'timestamp' ) ), + __( ' ago ' ), + $compareto_date + ); + } + + $restoreaction = wp_nonce_url( + add_query_arg( + array( 'revision' => $revision->ID, + 'action' => 'restore' ), + '/wp-admin/revision.php' + ), + "restore-post_{$compareto}|{$revision->ID}" + ); + + // + //make sure the left revision is the most recent + // + if ( strtotime( $right_revision->post_modified_gmt ) < strtotime( $left_revision->post_modified_gmt ) ) { + $temp = $left_revision; + $left_revision = $right_revision; + $right_revision = $temp; + } + + // + //compare from left to right, passed from application + // + $content=''; + foreach ( array_keys( _wp_post_revision_fields() ) as $field ) { + $left_content = apply_filters( "_wp_post_revision_field_$field", $left_revision->$field, $field, $left_revision, 'left' ); + $right_content = apply_filters( "_wp_post_revision_field_$field", $right_revision->$field, $field, $right_revision, 'right' ); + + add_filter( "_wp_post_revision_field_$field", 'wp_kses_post' ); + + $args = array(); + + if ( 'true' == $show_split_view ) + $args = array( 'show_split_view' => 'true' ); + + $content .= wp_text_diff( $left_content, $right_content, $args ); + } + + //if we are comparing two revisions + //and we are on the matching revision + //add an error revision indicating unable to compare to self + if ( $comparetwomode && $compareto == $revision->ID ) + $alltherevisions[] = array ( + 'ID' => $revision->ID, + 'revision_date_author' => $revision_date_author, + 'revisiondiff' => sprintf('
%s
', __( 'Cannot compare revision to itself' ) ), + 'restoreaction' => urldecode( $restoreaction ), + 'revision_from_date_author' => '' + ); + + //add to the return data only if there is a difference + if ( '' != $content ) + $alltherevisions[] = array ( + 'ID' => $revision->ID, + 'revision_date_author' => $revision_date_author, + 'revisiondiff' => $content, + 'restoreaction' => urldecode( $restoreaction ), + 'revision_from_date_author' => $revision_from_date_author + ); + + endforeach; + + echo json_encode( $alltherevisions ); + exit(); +} diff --git a/wp-admin/js/revisions.js b/wp-admin/js/revisions.js new file mode 100644 index 0000000000..43fb1e9848 --- /dev/null +++ b/wp-admin/js/revisions.js @@ -0,0 +1,530 @@ +window.wp = window.wp || {}; + +(function($) { + wp.revisions = { + + views : {}, + + Model : Backbone.Model.extend({ + defaults: { + ID : 0, + revision_date_author : '', + revisiondiff : '', + restoreaction: '', + diff_max : 0, + diff_count : 0, + diff_revision_to : 0, + revision_from_date_author : '', + } + }), + + app: _.extend({}, Backbone.Events), + + App : Backbone.Router.extend({ + _revisionDifflView : null, + _revisions : null, + _left_handle_revisions : null, + _right_handle_revisions : null, + _revisionsInteractions : null, + _revisionsOptions : null, + _left_diff : 0, + _right_diff : 1, + _autosaves : false, + _showsplitview : true, + _compareoneortwo : 1, + left_model_loading : false, //keep track of model loads + right_model_loading : false, //disallow slider interaction, also repeat loads, while loading + + //TODO add ability to arrive on specific revision + routes : { + "viewrevision/:revision": "viewrevision", + }, + + viewrevision : function( revision ) { + //coming soon + }, + + start_left_model_loading : function() { + this.left_model_loading = true; + $('.revisiondiffcontainer').addClass('leftmodelloading'); + }, + + stop_left_model_loading : function() { + this.left_model_loading = false; + $('.revisiondiffcontainer').removeClass('leftmodelloading'); + }, + + start_right_model_loading : function() { + this.right_model_loading = true; + $('.revisiondiffcontainer').addClass('rightmodelloading'); + }, + + stop_right_model_loading : function() { + this.right_model_loading = false; + $('.revisiondiffcontainer').removeClass('rightmodelloading'); + }, + + reloadmodel : function() { + if ( 2 == this._compareoneortwo ) { + this.reloadleftright(); + } else { + this.reloadmodelsingle(); + } + }, + + reloadmodelsingle : function() { + var self = this; + self._revisions.url = ajaxurl + '?action=revisions-data&compareto=' + wpRevisionsSettings.post_id + + '&showautosaves=' + self.self_autosaves + + '&showsplitview=' + REVAPP._showsplitview + + '&nonce=' + wpRevisionsSettings.nonce; + self.start_right_model_loading(); + this._revisions.fetch({ //reload revision data + success : function() { + self.stop_right_model_loading(); + var revisioncount = self._revisions.length; + if ( self._right_diff > revisioncount ) //if right handle past rightmost, move + self._right_diff = revisioncount; + //TODO add a test for matchind left revision and push left, testing + //also reset the slider values here + + self._revisionView.render(); + $( '#slider' ).slider( 'option', 'max', revisioncount-1 ); //TODO test this + }, + + error : function () { + self.stop_right_model_loading(); + window.console && console.log( 'Error loading revision data' ); + } + + }); + }, + + reloadleftright : function() { + var self = this; + self.start_left_model_loading(); + self.start_right_model_loading(); + + self._left_handle_revisions = new wp.revisions.Collection(); + self._right_handle_revisions = new wp.revisions.Collection(); + + if ( 0 == self._left_diff ) { + self._right_handle_revisions.url = + ajaxurl + + '?action=revisions-data&compareto=' + wpRevisionsSettings.post_id + + '&wpRevisionsSettings.post_id=' + wpRevisionsSettings.post_id + + '&showautosaves=' + self._autosaves + + '&showsplitview=' + self._showsplitview + + '&nonce=' + wpRevisionsSettings.nonce; + } else { + self._right_handle_revisions.url = + ajaxurl + + '?action=revisions-data&compareto=' + self._revisions.at( self._left_diff - 1 ).get( 'ID' ) + + '&wpRevisionsSettings.post_id=' + wpRevisionsSettings.post_id + + '&showautosaves=' + self._autosaves + + '&showsplitview=' + self._showsplitview + + '&nonce=' + wpRevisionsSettings.nonce; + } + + self._left_handle_revisions.url = + ajaxurl + + '?action=revisions-data&compareto=' + self._revisions.at( self._right_diff - 1 ).get( 'ID' ) + + '&wpRevisionsSettings.post_id=' + wpRevisionsSettings.post_id + + '&showautosaves=' + self._autosaves + + '&showsplitview=' + self._showsplitview + + '&nonce=' + wpRevisionsSettings.nonce; + + self._left_handle_revisions.fetch({ + + xhr: function() { + var xhr = $.ajaxSettings.xhr(); + xhr.onprogress = self.handleProgress; + return xhr; + }, + + handleProgress: function(evt){ + var percentComplete = 0; + if (evt.lengthComputable) { + percentComplete = evt.loaded / evt.total; + window.console && console.log( Math.round( percentComplete * 100) + "%" ); + } + }, + + success : function(){ + self.stop_left_model_loading(); + }, + + error : function () { + window.console && console.log( 'Error loading revision data' ); + self.stop_left_model_loading(); + } + }); + + self._right_handle_revisions.fetch({ + + success : function(){ + self.stop_right_model_loading(); + }, + + error : function () { + window.console && console.log( 'Error loading revision data' ); + self.stop_right_model_loading(); + } + }); + }, + + /* + * initialize the revision appl;ication + */ + initialize : function( options ) { + var self = this; //store the application instance + if (this._revisions === null) { + self._autosaves = ''; + self._revisions = new wp.revisions.Collection(); //set up collection + self.start_right_model_loading(); + self._revisions.fetch({ //load revision data + + success : function() { + self.stop_right_model_loading(); + self.revisionDiffSetup(); + } + }); + } + return this; + }, + + revisionDiffSetup : function() { + var self = this, slider; + + this._revisionView = new wp.revisions.views.View({ + model : this._revisions + }); + this._revisionView.render(); + + this._revisionsInteractions = new wp.revisions.views.Interact({ + model : this._revisions + }); + this._revisionsInteractions.render(); + + this._revisionsOptions = new wp.revisions.views.Options({ + model : this._revisions + }); + this._revisionsOptions.render(); + + } + }) + }; + + wp.revisions.Collection = Backbone.Collection.extend({ + model : wp.revisions.Model, + url : ajaxurl + '?action=revisions-data&compareto=' + wpRevisionsSettings.post_id + '&showautosaves=false&showsplitview=true&nonce=' + wpRevisionsSettings.nonce + }); + + _.extend(wp.revisions.views, { + // + //primary revision diff view + // + View : Backbone.View.extend({ + el : $('#backbonerevisionsdiff')[0], + tagName : 'revisionvview', + className : 'revisionview-container', + template : wp.template('revision'), + revvapp : null, + comparetwochecked : '', + draggingleft : false, + + initialize : function(){ + }, + + // + //render the revisions + // + render : function() { + var addhtml = ''; + //compare two revisions mode? + if ( 2 == REVAPP._compareoneortwo ) { + this.comparetwochecked = 'checked'; + if ( this.draggingleft ) { + if ( this.model.at( REVAPP._left_diff ) ) { + addhtml = this.template( _.extend( + this.model.at( REVAPP._left_diff ).toJSON(), + { comparetwochecked : this.comparetwochecked } //keep the checkmark checked + ) ); + } + } else { //dragging right handle + var thediff = REVAPP._right_diff; + if ( this.model.at( thediff ) ) { + addhtml = this.template( _.extend( + this.model.at( thediff ).toJSON(), + { comparetwochecked : this.comparetwochecked } //keep the checkmark checked + ) ); + } + } + } else { //end compare two revisions mode, eg only one slider handel + this.comparetwochecked = ''; + if ( this.model.at( REVAPP._right_diff - 1 ) ) { + addhtml = this.template( _.extend( + this.model.at( REVAPP._right_diff-1 ).toJSON(), + { comparetwochecked : this.comparetwochecked } //keep the checkmark checked + ) ); + } + } + this.$el.html( addhtml ); + return this; + }, + + //the compare two button is in this view, add the interaction here + events : { + 'click #comparetwo' : 'clickcomparetwo' + }, + + // + //turn on/off the compare two mmode + // + clickcomparetwo : function(){ + self = this; + if ( $( 'input#comparetwo' ).is( ':checked' ) ) { + REVAPP._compareoneortwo = 2 ; + REVAPP.reloadleftright(); + } else { + REVAPP._compareoneortwo = 1 ; + REVAPP._revisionView.draggingleft = false; + REVAPP._left_diff = 0; + REVAPP.reloadmodelsingle(); + } + REVAPP._revisionsInteractions.render(); + } + }), + + // + //options view for show autosaves and show split view options + // + Options : Backbone.View.extend({ + el : $('#backbonerevisionsoptions')[0], + tagName : 'revisionoptionsview', + className : 'revisionoptions-container', + template : wp.template('revisionoptions'), + + initialize : function() { + }, + + //render the options view + render : function() { + var addhtml = this.template; + this.$el.html( addhtml ); + return this; + }, + + //add options interactions + events : { + 'click #toggleshowautosaves' : 'toggleshowautosaves', + 'click #showsplitview' : 'showsplitview' + }, + + // + //toggle include autosaves + // + toggleshowautosaves : function() { + var self = this; + if ( $( '#toggleshowautosaves' ).is( ':checked' ) ) { + REVAPP._autosaves = true ; + } else { + REVAPP._autosaves = false ; + } + //refresh the model data + + REVAPP.reloadmodel(); + //TODO check for two handle mode + + }, + + // + //toggle showing the split diff view + // + showsplitview : function() { + var self = this; + + if ( $( 'input#showsplitview' ).is( ':checked' ) ) { + REVAPP._showsplitview = 'true'; + $('.revisiondiffcontainer').addClass('diffsplit'); + } else { + REVAPP._showsplitview = ''; + $('.revisiondiffcontainer').removeClass('diffsplit'); + } + + REVAPP.reloadmodel(); + } + }), + + // + //main interactions view + // + Interact : Backbone.View.extend({ + el : $('#backbonerevisionsinteract')[0], + tagName : 'revisionvinteract', + className : 'revisionvinteract-container', + template : wp.template('revisionvinteract'), + + initialize : function() { + }, + + render : function() { + var self = this; + + var addhtml = this.template; + this.$el.html( addhtml ); + $( '#diff_max, #diff_maxof' ).html( this.model.length ); + $( '#diff_count' ).html( REVAPP._right_diff ); + $( '#diff_left_count_inner' ).html( 0 == REVAPP._left_diff ? '' : 'revision' + REVAPP._left_diff ); + + var modelcount = REVAPP._revisions.length; + + slider = $("#slider"); + if ( 1 == REVAPP._compareoneortwo ) { + //set up the slider with a single handle + slider.slider({ + value : REVAPP._right_diff-1, + min : 0, + max : modelcount-1, + step : 1, + + //slide interactions for one handles slider + slide : function( event, ui ) { + if ( REVAPP.right_model_loading ) //left model stoll loading, prevent sliding left handle + return false; + + REVAPP._right_diff =( ui.value+1 ); + $( '#diff_count' ).html( REVAPP._right_diff ); + REVAPP._revisionView.render(); + } + }); + $( '.revisiondiffcontainer' ).removeClass( 'comparetwo' ); + } else { //comparing more than one, eg 2 + //set up the slider with two handles + slider.slider({ + values : [ REVAPP._left_diff, REVAPP._right_diff + 1 ], + min : 1, + max : modelcount+1, + step : 1, + range: true, + + //in two handled mode when user starts dragging, swap in precalculated diff for handle + start : function (event, ui ) { + var index = $( ui.handle ).index(); //0 (left) or 1 (right) + + switch ( index ) { + case 1: //left handle drag + if ( REVAPP.left_model_loading ) //left model stoll loading, prevent sliding left handle + return false; + + if ( REVAPP._revisionView.model !== REVAPP._left_handle_revisions && + null != REVAPP._left_handle_revisions ) + REVAPP._revisionView.model = REVAPP._left_handle_revisions; + + REVAPP._revisionView.draggingleft = true; + break; + + case 2: //right + if ( REVAPP.right_model_loading ) //right model stoll loading, prevent sliding right handle + return false; + + //one extra spot at left end when comparing two + if ( REVAPP._revisionView.model !== REVAPP._right_handle_revisions && + null != REVAPP._right_handle_revisions ) + REVAPP._revisionView.model = REVAPP._right_handle_revisions; + + REVAPP._revisionView.draggingleft = false; + REVAPP._right_diff = ui.values[1] - 1 ; + break; + } + }, + + //when sliding in two handled mode change appropriate value + slide : function( event, ui ) { + if ( ui.values[0] == ui.values[1] ) //prevent compare to self + return false; + + var index = $( ui.handle ).index(); //0 (left) or 1 (right) + + switch ( index ) { + case 1: //left + if ( REVAPP.left_model_loading ) //left model stoll loading, prevent sliding left handle + return false; + + REVAPP._left_diff = ui.values[0] - 1; //one extra spot at left end when comparing two + break; + + case 2: //right + if ( REVAPP.right_model_loading ) //right model stoll loading, prevent sliding right handle + return false; + + REVAPP._right_diff = ui.values[1] - 1 ; + break; + } + + $( '#diff_count' ).html( REVAPP._right_diff ); + + if ( 0 == REVAPP._left_diff ) { + $( '.revisiondiffcontainer' ).addClass( 'currentversion' ); + + } else { + $( '.revisiondiffcontainer' ).removeClass( 'currentversion' ); + $( '#diff_left_count_inner' ).html( REVAPP._left_diff ); + } + + REVAPP._revisionView.render(); //render the diff view + }, + + //when the user stops sliding in 2 handle mode, recalculate diffs + stop : function( event, ui ) { + if ( 2 == REVAPP._compareoneortwo ) { + //calculate and generate a diff for comparing to the left handle + //and the right handle, swap out when dragging + if ( ! (REVAPP.left_model_loading && REVAPP.right_model.loading ) ) { + REVAPP.reloadleftright(); + } + } + } + }); + $( '.revisiondiffcontainer' ).addClass( 'comparetwo' ); + } + + return this; + }, + + //next and previous buttons, only available in compare one mode + events : { + 'click #next' : 'nextrevision', + 'click #previous' : 'previousrevision' + }, + + //go to the next revision + nextrevision : function() { + if ( REVAPP._right_diff < this.model.length ) //unless at right boundry + REVAPP._right_diff = REVAPP._right_diff + 1 ; + + REVAPP._revisionView.render(); + + $( '#diff_count' ).html( REVAPP._right_diff ); + $( '#slider' ).slider( 'value', REVAPP._right_diff - 1 ).trigger( 'slide' ); + }, + + //go the the previous revision + previousrevision : function() { + if ( REVAPP._right_diff > 1 ) //unless at left boundry + REVAPP._right_diff = REVAPP._right_diff - 1 ; + + REVAPP._revisionView.render(); + + $( '#diff_count' ).html( REVAPP._right_diff ); + $( '#slider' ).slider( 'value', REVAPP._right_diff - 1 ).trigger( 'slide' ); + } + }) + }); + + //instantiate Revision Application + REVAPP = new wp.revisions.App(); + //TODO consider enable back button to step back thru states? + Backbone.history.start(); + +}(jQuery)); diff --git a/wp-admin/js/revisions.min.js b/wp-admin/js/revisions.min.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wp-admin/revision.php b/wp-admin/revision.php index 51a01479a4..452fbd8d85 100644 --- a/wp-admin/revision.php +++ b/wp-admin/revision.php @@ -8,15 +8,9 @@ /** WordPress Administration Bootstrap */ require_once('./admin.php'); - -wp_enqueue_script('list-revisions'); - -wp_reset_vars(array('revision', 'left', 'right', 'action')); +wp_reset_vars( array( 'revision', 'action' ) ); $revision_id = absint($revision); -$left = absint($left); -$right = absint($right); - $redirect = 'edit.php'; switch ( $action ) : @@ -33,75 +27,13 @@ case 'restore' : $redirect = 'edit.php?post_type=' . $post->post_type; break; } - - check_admin_referer( "restore-post_$post->ID|$revision->ID" ); + check_admin_referer( "restore-post_{$post->ID}|{$revision->ID}" ); wp_restore_post_revision( $revision->ID ); $redirect = add_query_arg( array( 'message' => 5, 'revision' => $revision->ID ), get_edit_post_link( $post->ID, 'url' ) ); break; -case 'diff' : - if ( !$left_revision = get_post( $left ) ) - break; - if ( !$right_revision = get_post( $right ) ) - break; - - if ( !current_user_can( 'read_post', $left_revision->ID ) || !current_user_can( 'read_post', $right_revision->ID ) ) - break; - - // If we're comparing a revision to itself, redirect to the 'view' page for that revision or the edit page for that post - if ( $left_revision->ID == $right_revision->ID ) { - $redirect = get_edit_post_link( $left_revision->ID ); - include( './js/revisions-js.php' ); - break; - } - - // Don't allow reverse diffs? - if ( strtotime($right_revision->post_modified_gmt) < strtotime($left_revision->post_modified_gmt) ) { - $redirect = add_query_arg( array( 'left' => $right, 'right' => $left ) ); - break; - } - - if ( $left_revision->ID == $right_revision->post_parent ) // right is a revision of left - $post =& $left_revision; - elseif ( $left_revision->post_parent == $right_revision->ID ) // left is a revision of right - $post =& $right_revision; - elseif ( $left_revision->post_parent == $right_revision->post_parent ) // both are revisions of common parent - $post = get_post( $left_revision->post_parent ); - else - break; // Don't diff two unrelated revisions - - if ( ! WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions') ) { // Revisions disabled - if ( - // we're not looking at an autosave - ( !wp_is_post_autosave( $left_revision ) && !wp_is_post_autosave( $right_revision ) ) - || - // we're not comparing an autosave to the current post - ( $post->ID !== $left_revision->ID && $post->ID !== $right_revision->ID ) - ) { - $redirect = 'edit.php?post_type=' . $post->post_type; - break; - } - } - - if ( - // They're the same - $left_revision->ID == $right_revision->ID - || - // Neither is a revision - ( !wp_get_post_revision( $left_revision->ID ) && !wp_get_post_revision( $right_revision->ID ) ) - ) - break; - - $post_title = '' . get_the_title() . ''; - $h2 = sprintf( __( 'Compare Revisions of “%1$s”' ), $post_title ); - $title = __( 'Revisions' ); - - $left = $left_revision->ID; - $right = $right_revision->ID; - - $redirect = false; - break; case 'view' : +case 'edit' : default : if ( !$revision = wp_get_post_revision( $revision_id ) ) break; @@ -119,13 +51,9 @@ default : $post_title = '' . get_the_title() . ''; $revision_title = wp_post_revision_title( $revision, false ); - $h2 = sprintf( __( 'Revision for “%1$s” created on %2$s' ), $post_title, $revision_title ); + $h2 = sprintf( __( 'Compare Revisions of “%1$s”' ), $post_title ); $title = __( 'Revisions' ); - // Sets up the diff radio buttons - $left = $revision->ID; - $right = $post->ID; - $redirect = false; break; endswitch; @@ -145,79 +73,83 @@ if ( !empty($post->post_type) && 'post' != $post->post_type ) else $parent_file = $submenu_file = 'edit.php'; +wp_enqueue_style( 'revisions' ); +wp_enqueue_script( 'revisions' ); + require_once( './admin-header.php' ); +//TODO - Some of the translations below split things into multiple strings that are contextually related and this makes it pretty impossible for RTL translation. +//TODO can we pass the context in a better way ?> + +
+ +
- -

- - - - - - - - - $field_title ) : - if ( 'diff' == $action ) { - $left_content = apply_filters( "_wp_post_revision_field_$field", $left_revision->$field, $field, $left_revision, 'left' ); - $right_content = apply_filters( "_wp_post_revision_field_$field", $right_revision->$field, $field, $right_revision, 'right' ); - if ( !$content = wp_text_diff( $left_content, $right_content ) ) - continue; // There is no difference between left and right - $identical = false; - } else { - add_filter( "_wp_post_revision_field_$field", 'htmlspecialchars' ); - $content = apply_filters( "_wp_post_revision_field_$field", $revision->$field, $field, $revision, '' ); - } - ?> - - - - - - - - - - - - -
- - -

- -
- -

- +

+
+
+

+
+
+
'form-table', 'parent' => true, 'right' => $right, 'left' => $left ); -if ( ! WP_POST_REVISIONS || !post_type_supports($post->post_type, 'revisions') ) - $args['type'] = 'autosave'; - -wp_list_post_revisions( $post, $args ); - + $comparetworevisionslink = get_edit_post_link( $revision->ID ); ?> - +
+ + + +
+
+ +
+
+ +
+
+ +*/ +require_once( './admin-footer.php' ); \ No newline at end of file diff --git a/wp-includes/css/jquery-ui-slider.css b/wp-includes/css/jquery-ui-slider.css new file mode 100644 index 0000000000..4ac53e2588 --- /dev/null +++ b/wp-includes/css/jquery-ui-slider.css @@ -0,0 +1,544 @@ +/*! jQuery UI - v1.10.1 - 2013-02-15 +* http://jqueryui.com +* Includes: jquery.ui.core.css, jquery.ui.slider.css +* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Trebuchet%20MS%2CTahoma%2CVerdana%2CArial%2Csans-serif&fwDefault=bold&fsDefault=1.1em&cornerRadius=4px&bgColorHeader=f6a828&bgTextureHeader=gloss_wave&bgImgOpacityHeader=35&borderColorHeader=e78f08&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=eeeeee&bgTextureContent=highlight_soft&bgImgOpacityContent=100&borderColorContent=dddddd&fcContent=333333&iconColorContent=222222&bgColorDefault=f6f6f6&bgTextureDefault=glass&bgImgOpacityDefault=100&borderColorDefault=cccccc&fcDefault=1c94c4&iconColorDefault=ef8c08&bgColorHover=fdf5ce&bgTextureHover=glass&bgImgOpacityHover=100&borderColorHover=fbcb09&fcHover=c77405&iconColorHover=ef8c08&bgColorActive=ffffff&bgTextureActive=glass&bgImgOpacityActive=65&borderColorActive=fbd850&fcActive=eb8f00&iconColorActive=ef8c08&bgColorHighlight=ffe45c&bgTextureHighlight=highlight_soft&bgImgOpacityHighlight=75&borderColorHighlight=fed22f&fcHighlight=363636&iconColorHighlight=228ef1&bgColorError=b81900&bgTextureError=diagonals_thick&bgImgOpacityError=18&borderColorError=cd0a0a&fcError=ffffff&iconColorError=ffd27a&bgColorOverlay=666666&bgTextureOverlay=diagonals_thick&bgImgOpacityOverlay=20&opacityOverlay=50&bgColorShadow=000000&bgTextureShadow=flat&bgImgOpacityShadow=10&opacityShadow=20&thicknessShadow=5px&offsetTopShadow=-5px&offsetLeftShadow=-5px&cornerRadiusShadow=5px +* Copyright (c) 2013 jQuery Foundation and other contributors Licensed MIT */ + +/* Layout helpers +----------------------------------*/ +.ui-helper-hidden { + display: none; +} +.ui-helper-hidden-accessible { + border: 0; + clip: rect(0 0 0 0); + height: 1px; + margin: -1px; + overflow: hidden; + padding: 0; + position: absolute; + width: 1px; +} +.ui-helper-reset { + margin: 0; + padding: 0; + border: 0; + outline: 0; + line-height: 1.3; + text-decoration: none; + font-size: 100%; + list-style: none; +} +.ui-helper-clearfix:before, +.ui-helper-clearfix:after { + content: ""; + display: table; + border-collapse: collapse; +} +.ui-helper-clearfix:after { + clear: both; +} +.ui-helper-clearfix { + min-height: 0; /* support: IE7 */ +} +.ui-helper-zfix { + width: 100%; + height: 100%; + top: 0; + left: 0; + position: absolute; + opacity: 0; + filter:Alpha(Opacity=0); +} + +.ui-front { + z-index: 100; +} + + +/* Interaction Cues +----------------------------------*/ +.ui-state-disabled { + cursor: default !important; +} + + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + display: block; + text-indent: -99999px; + overflow: hidden; + background-repeat: no-repeat; +} + + +/* Misc visuals +----------------------------------*/ + +/* Overlays */ +.ui-widget-overlay { + position: fixed; + top: 0; + left: 0; + width: 100%; + height: 100%; +} +.ui-slider { + position: relative; + text-align: left; +} +.ui-slider .ui-slider-handle { + position: absolute; + z-index: 2; + width: 1.2em; + height: 1.2em; + cursor: default; +} +.ui-slider .ui-slider-range { + position: absolute; + z-index: 1; + font-size: .7em; + display: block; + border: 0; + background-position: 0 0; +} + +/* For IE8 - See #6727 */ +.ui-slider.ui-state-disabled .ui-slider-handle, +.ui-slider.ui-state-disabled .ui-slider-range { + filter: inherit; +} + +.ui-slider-horizontal { + height: .8em; +} +.ui-slider-horizontal .ui-slider-handle { + top: -.3em; + margin-left: -.6em; +} +.ui-slider-horizontal .ui-slider-range { + top: 0; + height: 100%; +} +.ui-slider-horizontal .ui-slider-range-min { + left: 0; +} +.ui-slider-horizontal .ui-slider-range-max { + right: 0; +} + +.ui-slider-vertical { + width: .8em; + height: 100px; +} +.ui-slider-vertical .ui-slider-handle { + left: -.3em; + margin-left: 0; + margin-bottom: -.6em; +} +.ui-slider-vertical .ui-slider-range { + left: 0; + width: 100%; +} +.ui-slider-vertical .ui-slider-range-min { + bottom: 0; +} +.ui-slider-vertical .ui-slider-range-max { + top: 0; +} + +/* Component containers +----------------------------------*/ +.ui-widget { + font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; + font-size: 1.1em; +} +.ui-widget .ui-widget { + font-size: 1em; +} +.ui-widget input, +.ui-widget select, +.ui-widget textarea, +.ui-widget button { + font-family: Trebuchet MS,Tahoma,Verdana,Arial,sans-serif; + font-size: 1em; +} +.ui-widget-content { + border: 1px solid #dddddd; + background: #eeeeee url(../images/ui-bg_highlight-soft_100_eeeeee_1x100.png) 50% top repeat-x; + color: #333333; +} +.ui-widget-content a { + color: #333333; +} +.ui-widget-header { + border: 1px solid #e78f08; + background: #f6a828 url(../images/ui-bg_gloss-wave_35_f6a828_500x100.png) 50% 50% repeat-x; + color: #ffffff; + font-weight: bold; +} +.ui-widget-header a { + color: #ffffff; +} + +/* Interaction states +----------------------------------*/ +.ui-state-default, +.ui-widget-content .ui-state-default, +.ui-widget-header .ui-state-default { + border: 1px solid #cccccc; + background: #f6f6f6 url(../images/ui-bg_glass_100_f6f6f6_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #1c94c4; +} +.ui-state-default a, +.ui-state-default a:link, +.ui-state-default a:visited { + color: #1c94c4; + text-decoration: none; +} +.ui-state-hover, +.ui-widget-content .ui-state-hover, +.ui-widget-header .ui-state-hover, +.ui-state-focus, +.ui-widget-content .ui-state-focus, +.ui-widget-header .ui-state-focus { + border: 1px solid #fbcb09; + background: #fdf5ce url(../images/ui-bg_glass_100_fdf5ce_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #c77405; +} +.ui-state-hover a, +.ui-state-hover a:hover, +.ui-state-hover a:link, +.ui-state-hover a:visited { + color: #c77405; + text-decoration: none; +} +.ui-state-active, +.ui-widget-content .ui-state-active, +.ui-widget-header .ui-state-active { + border: 1px solid #fbd850; + background: #ffffff url(../images/ui-bg_glass_65_ffffff_1x400.png) 50% 50% repeat-x; + font-weight: bold; + color: #eb8f00; +} +.ui-state-active a, +.ui-state-active a:link, +.ui-state-active a:visited { + color: #eb8f00; + text-decoration: none; +} + +/* Interaction Cues +----------------------------------*/ +.ui-state-highlight, +.ui-widget-content .ui-state-highlight, +.ui-widget-header .ui-state-highlight { + border: 1px solid #fed22f; + background: #ffe45c url(../images/ui-bg_highlight-soft_75_ffe45c_1x100.png) 50% top repeat-x; + color: #363636; +} +.ui-state-highlight a, +.ui-widget-content .ui-state-highlight a, +.ui-widget-header .ui-state-highlight a { + color: #363636; +} +.ui-state-error, +.ui-widget-content .ui-state-error, +.ui-widget-header .ui-state-error { + border: 1px solid #cd0a0a; + background: #b81900 url(../images/ui-bg_diagonals-thick_18_b81900_40x40.png) 50% 50% repeat; + color: #ffffff; +} +.ui-state-error a, +.ui-widget-content .ui-state-error a, +.ui-widget-header .ui-state-error a { + color: #ffffff; +} +.ui-state-error-text, +.ui-widget-content .ui-state-error-text, +.ui-widget-header .ui-state-error-text { + color: #ffffff; +} +.ui-priority-primary, +.ui-widget-content .ui-priority-primary, +.ui-widget-header .ui-priority-primary { + font-weight: bold; +} +.ui-priority-secondary, +.ui-widget-content .ui-priority-secondary, +.ui-widget-header .ui-priority-secondary { + opacity: .7; + filter:Alpha(Opacity=70); + font-weight: normal; +} +.ui-state-disabled, +.ui-widget-content .ui-state-disabled, +.ui-widget-header .ui-state-disabled { + opacity: .35; + filter:Alpha(Opacity=35); + background-image: none; +} +.ui-state-disabled .ui-icon { + filter:Alpha(Opacity=35); /* For IE8 - See #6059 */ +} + +/* Icons +----------------------------------*/ + +/* states and images */ +.ui-icon { + width: 16px; + height: 16px; + background-position: 16px 16px; +} +.ui-icon, +.ui-widget-content .ui-icon { + background-image: url(../images/ui-icons_222222_256x240.png); +} +.ui-widget-header .ui-icon { + background-image: url(../images/ui-icons_ffffff_256x240.png); +} +.ui-state-default .ui-icon { + background-image: url(../images/ui-icons_ef8c08_256x240.png); +} +.ui-state-hover .ui-icon, +.ui-state-focus .ui-icon { + background-image: url(../images/ui-icons_ef8c08_256x240.png); +} +.ui-state-active .ui-icon { + background-image: url(../images/ui-icons_ef8c08_256x240.png); +} +.ui-state-highlight .ui-icon { + background-image: url(../images/ui-icons_228ef1_256x240.png); +} +.ui-state-error .ui-icon, +.ui-state-error-text .ui-icon { + background-image: url(../images/ui-icons_ffd27a_256x240.png); +} + +/* positioning */ +.ui-icon-carat-1-n { background-position: 0 0; } +.ui-icon-carat-1-ne { background-position: -16px 0; } +.ui-icon-carat-1-e { background-position: -32px 0; } +.ui-icon-carat-1-se { background-position: -48px 0; } +.ui-icon-carat-1-s { background-position: -64px 0; } +.ui-icon-carat-1-sw { background-position: -80px 0; } +.ui-icon-carat-1-w { background-position: -96px 0; } +.ui-icon-carat-1-nw { background-position: -112px 0; } +.ui-icon-carat-2-n-s { background-position: -128px 0; } +.ui-icon-carat-2-e-w { background-position: -144px 0; } +.ui-icon-triangle-1-n { background-position: 0 -16px; } +.ui-icon-triangle-1-ne { background-position: -16px -16px; } +.ui-icon-triangle-1-e { background-position: -32px -16px; } +.ui-icon-triangle-1-se { background-position: -48px -16px; } +.ui-icon-triangle-1-s { background-position: -64px -16px; } +.ui-icon-triangle-1-sw { background-position: -80px -16px; } +.ui-icon-triangle-1-w { background-position: -96px -16px; } +.ui-icon-triangle-1-nw { background-position: -112px -16px; } +.ui-icon-triangle-2-n-s { background-position: -128px -16px; } +.ui-icon-triangle-2-e-w { background-position: -144px -16px; } +.ui-icon-arrow-1-n { background-position: 0 -32px; } +.ui-icon-arrow-1-ne { background-position: -16px -32px; } +.ui-icon-arrow-1-e { background-position: -32px -32px; } +.ui-icon-arrow-1-se { background-position: -48px -32px; } +.ui-icon-arrow-1-s { background-position: -64px -32px; } +.ui-icon-arrow-1-sw { background-position: -80px -32px; } +.ui-icon-arrow-1-w { background-position: -96px -32px; } +.ui-icon-arrow-1-nw { background-position: -112px -32px; } +.ui-icon-arrow-2-n-s { background-position: -128px -32px; } +.ui-icon-arrow-2-ne-sw { background-position: -144px -32px; } +.ui-icon-arrow-2-e-w { background-position: -160px -32px; } +.ui-icon-arrow-2-se-nw { background-position: -176px -32px; } +.ui-icon-arrowstop-1-n { background-position: -192px -32px; } +.ui-icon-arrowstop-1-e { background-position: -208px -32px; } +.ui-icon-arrowstop-1-s { background-position: -224px -32px; } +.ui-icon-arrowstop-1-w { background-position: -240px -32px; } +.ui-icon-arrowthick-1-n { background-position: 0 -48px; } +.ui-icon-arrowthick-1-ne { background-position: -16px -48px; } +.ui-icon-arrowthick-1-e { background-position: -32px -48px; } +.ui-icon-arrowthick-1-se { background-position: -48px -48px; } +.ui-icon-arrowthick-1-s { background-position: -64px -48px; } +.ui-icon-arrowthick-1-sw { background-position: -80px -48px; } +.ui-icon-arrowthick-1-w { background-position: -96px -48px; } +.ui-icon-arrowthick-1-nw { background-position: -112px -48px; } +.ui-icon-arrowthick-2-n-s { background-position: -128px -48px; } +.ui-icon-arrowthick-2-ne-sw { background-position: -144px -48px; } +.ui-icon-arrowthick-2-e-w { background-position: -160px -48px; } +.ui-icon-arrowthick-2-se-nw { background-position: -176px -48px; } +.ui-icon-arrowthickstop-1-n { background-position: -192px -48px; } +.ui-icon-arrowthickstop-1-e { background-position: -208px -48px; } +.ui-icon-arrowthickstop-1-s { background-position: -224px -48px; } +.ui-icon-arrowthickstop-1-w { background-position: -240px -48px; } +.ui-icon-arrowreturnthick-1-w { background-position: 0 -64px; } +.ui-icon-arrowreturnthick-1-n { background-position: -16px -64px; } +.ui-icon-arrowreturnthick-1-e { background-position: -32px -64px; } +.ui-icon-arrowreturnthick-1-s { background-position: -48px -64px; } +.ui-icon-arrowreturn-1-w { background-position: -64px -64px; } +.ui-icon-arrowreturn-1-n { background-position: -80px -64px; } +.ui-icon-arrowreturn-1-e { background-position: -96px -64px; } +.ui-icon-arrowreturn-1-s { background-position: -112px -64px; } +.ui-icon-arrowrefresh-1-w { background-position: -128px -64px; } +.ui-icon-arrowrefresh-1-n { background-position: -144px -64px; } +.ui-icon-arrowrefresh-1-e { background-position: -160px -64px; } +.ui-icon-arrowrefresh-1-s { background-position: -176px -64px; } +.ui-icon-arrow-4 { background-position: 0 -80px; } +.ui-icon-arrow-4-diag { background-position: -16px -80px; } +.ui-icon-extlink { background-position: -32px -80px; } +.ui-icon-newwin { background-position: -48px -80px; } +.ui-icon-refresh { background-position: -64px -80px; } +.ui-icon-shuffle { background-position: -80px -80px; } +.ui-icon-transfer-e-w { background-position: -96px -80px; } +.ui-icon-transferthick-e-w { background-position: -112px -80px; } +.ui-icon-folder-collapsed { background-position: 0 -96px; } +.ui-icon-folder-open { background-position: -16px -96px; } +.ui-icon-document { background-position: -32px -96px; } +.ui-icon-document-b { background-position: -48px -96px; } +.ui-icon-note { background-position: -64px -96px; } +.ui-icon-mail-closed { background-position: -80px -96px; } +.ui-icon-mail-open { background-position: -96px -96px; } +.ui-icon-suitcase { background-position: -112px -96px; } +.ui-icon-comment { background-position: -128px -96px; } +.ui-icon-person { background-position: -144px -96px; } +.ui-icon-print { background-position: -160px -96px; } +.ui-icon-trash { background-position: -176px -96px; } +.ui-icon-locked { background-position: -192px -96px; } +.ui-icon-unlocked { background-position: -208px -96px; } +.ui-icon-bookmark { background-position: -224px -96px; } +.ui-icon-tag { background-position: -240px -96px; } +.ui-icon-home { background-position: 0 -112px; } +.ui-icon-flag { background-position: -16px -112px; } +.ui-icon-calendar { background-position: -32px -112px; } +.ui-icon-cart { background-position: -48px -112px; } +.ui-icon-pencil { background-position: -64px -112px; } +.ui-icon-clock { background-position: -80px -112px; } +.ui-icon-disk { background-position: -96px -112px; } +.ui-icon-calculator { background-position: -112px -112px; } +.ui-icon-zoomin { background-position: -128px -112px; } +.ui-icon-zoomout { background-position: -144px -112px; } +.ui-icon-search { background-position: -160px -112px; } +.ui-icon-wrench { background-position: -176px -112px; } +.ui-icon-gear { background-position: -192px -112px; } +.ui-icon-heart { background-position: -208px -112px; } +.ui-icon-star { background-position: -224px -112px; } +.ui-icon-link { background-position: -240px -112px; } +.ui-icon-cancel { background-position: 0 -128px; } +.ui-icon-plus { background-position: -16px -128px; } +.ui-icon-plusthick { background-position: -32px -128px; } +.ui-icon-minus { background-position: -48px -128px; } +.ui-icon-minusthick { background-position: -64px -128px; } +.ui-icon-close { background-position: -80px -128px; } +.ui-icon-closethick { background-position: -96px -128px; } +.ui-icon-key { background-position: -112px -128px; } +.ui-icon-lightbulb { background-position: -128px -128px; } +.ui-icon-scissors { background-position: -144px -128px; } +.ui-icon-clipboard { background-position: -160px -128px; } +.ui-icon-copy { background-position: -176px -128px; } +.ui-icon-contact { background-position: -192px -128px; } +.ui-icon-image { background-position: -208px -128px; } +.ui-icon-video { background-position: -224px -128px; } +.ui-icon-script { background-position: -240px -128px; } +.ui-icon-alert { background-position: 0 -144px; } +.ui-icon-info { background-position: -16px -144px; } +.ui-icon-notice { background-position: -32px -144px; } +.ui-icon-help { background-position: -48px -144px; } +.ui-icon-check { background-position: -64px -144px; } +.ui-icon-bullet { background-position: -80px -144px; } +.ui-icon-radio-on { background-position: -96px -144px; } +.ui-icon-radio-off { background-position: -112px -144px; } +.ui-icon-pin-w { background-position: -128px -144px; } +.ui-icon-pin-s { background-position: -144px -144px; } +.ui-icon-play { background-position: 0 -160px; } +.ui-icon-pause { background-position: -16px -160px; } +.ui-icon-seek-next { background-position: -32px -160px; } +.ui-icon-seek-prev { background-position: -48px -160px; } +.ui-icon-seek-end { background-position: -64px -160px; } +.ui-icon-seek-start { background-position: -80px -160px; } +/* ui-icon-seek-first is deprecated, use ui-icon-seek-start instead */ +.ui-icon-seek-first { background-position: -80px -160px; } +.ui-icon-stop { background-position: -96px -160px; } +.ui-icon-eject { background-position: -112px -160px; } +.ui-icon-volume-off { background-position: -128px -160px; } +.ui-icon-volume-on { background-position: -144px -160px; } +.ui-icon-power { background-position: 0 -176px; } +.ui-icon-signal-diag { background-position: -16px -176px; } +.ui-icon-signal { background-position: -32px -176px; } +.ui-icon-battery-0 { background-position: -48px -176px; } +.ui-icon-battery-1 { background-position: -64px -176px; } +.ui-icon-battery-2 { background-position: -80px -176px; } +.ui-icon-battery-3 { background-position: -96px -176px; } +.ui-icon-circle-plus { background-position: 0 -192px; } +.ui-icon-circle-minus { background-position: -16px -192px; } +.ui-icon-circle-close { background-position: -32px -192px; } +.ui-icon-circle-triangle-e { background-position: -48px -192px; } +.ui-icon-circle-triangle-s { background-position: -64px -192px; } +.ui-icon-circle-triangle-w { background-position: -80px -192px; } +.ui-icon-circle-triangle-n { background-position: -96px -192px; } +.ui-icon-circle-arrow-e { background-position: -112px -192px; } +.ui-icon-circle-arrow-s { background-position: -128px -192px; } +.ui-icon-circle-arrow-w { background-position: -144px -192px; } +.ui-icon-circle-arrow-n { background-position: -160px -192px; } +.ui-icon-circle-zoomin { background-position: -176px -192px; } +.ui-icon-circle-zoomout { background-position: -192px -192px; } +.ui-icon-circle-check { background-position: -208px -192px; } +.ui-icon-circlesmall-plus { background-position: 0 -208px; } +.ui-icon-circlesmall-minus { background-position: -16px -208px; } +.ui-icon-circlesmall-close { background-position: -32px -208px; } +.ui-icon-squaresmall-plus { background-position: -48px -208px; } +.ui-icon-squaresmall-minus { background-position: -64px -208px; } +.ui-icon-squaresmall-close { background-position: -80px -208px; } +.ui-icon-grip-dotted-vertical { background-position: 0 -224px; } +.ui-icon-grip-dotted-horizontal { background-position: -16px -224px; } +.ui-icon-grip-solid-vertical { background-position: -32px -224px; } +.ui-icon-grip-solid-horizontal { background-position: -48px -224px; } +.ui-icon-gripsmall-diagonal-se { background-position: -64px -224px; } +.ui-icon-grip-diagonal-se { background-position: -80px -224px; } + + +/* Misc visuals +----------------------------------*/ + +/* Corner radius */ +.ui-corner-all, +.ui-corner-top, +.ui-corner-left, +.ui-corner-tl { + border-top-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-top, +.ui-corner-right, +.ui-corner-tr { + border-top-right-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-left, +.ui-corner-bl { + border-bottom-left-radius: 4px; +} +.ui-corner-all, +.ui-corner-bottom, +.ui-corner-right, +.ui-corner-br { + border-bottom-right-radius: 4px; +} + +/* Overlays */ +.ui-widget-overlay { + background: #666666 url(../images/ui-bg_diagonals-thick_20_666666_40x40.png) 50% 50% repeat; + opacity: .5; + filter: Alpha(Opacity=50); +} +.ui-widget-shadow { + margin: -5px 0 0 -5px; + padding: 5px; + background: #000000 url(../images/ui-bg_flat_10_000000_40x100.png) 50% 50% repeat-x; + opacity: .2; + filter: Alpha(Opacity=20); + border-radius: 5px; +} diff --git a/wp-includes/css/jquery-ui-slider.min.css b/wp-includes/css/jquery-ui-slider.min.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wp-includes/js/template.js b/wp-includes/js/template.js new file mode 100644 index 0000000000..a8bcdfaa91 --- /dev/null +++ b/wp-includes/js/template.js @@ -0,0 +1,29 @@ +window.wp = window.wp || {}; + +(function ($) { + var template; + /** + * wp.template( id ) + * + * Fetches a template by id. + * + * @param {string} id A string that corresponds to a DOM element with an id prefixed with "tmpl-". + * For example, "attachment" maps to "tmpl-attachment". + * @return {function} A function that lazily-compiles the template requested. + */ + template = wp.template = _.memoize(function ( id ) { + var compiled, + options = { + evaluate: /<#([\s\S]+?)#>/g, + interpolate: /\{\{\{([\s\S]+?)\}\}\}/g, + escape: /\{\{([^\}]+?)\}\}(?!\})/g, + variable: 'data' + }; + + return function ( data ) { + compiled = compiled || _.template( $( '#tmpl-' + id ).html(), null, options ); + return compiled( data ); + }; + }); + +}(jQuery)); diff --git a/wp-includes/js/template.min.js b/wp-includes/js/template.min.js new file mode 100644 index 0000000000..e69de29bb2 diff --git a/wp-includes/pluggable.php b/wp-includes/pluggable.php index 99aaad12bf..3041eb2fab 100644 --- a/wp-includes/pluggable.php +++ b/wp-includes/pluggable.php @@ -1713,16 +1713,20 @@ function wp_text_diff( $left_string, $right_string, $args = null ) { $left_lines = explode("\n", $left_string); $right_lines = explode("\n", $right_string); - $text_diff = new Text_Diff($left_lines, $right_lines); - $renderer = new WP_Text_Diff_Renderer_Table(); + $renderer = new WP_Text_Diff_Renderer_Table( $args ); $diff = $renderer->render($text_diff); if ( !$diff ) return ''; $r = "\n"; - $r .= ""; + + if ( isset( $args[ 'showsplitview' ] ) && 'true' == $args[ 'showsplitview' ] ) { + $r .= ""; + } else { + $r .= ""; + } if ( $args['title'] || $args['title_left'] || $args['title_right'] ) $r .= ""; diff --git a/wp-includes/post-template.php b/wp-includes/post-template.php index 13a8407f15..06be04786f 100644 --- a/wp-includes/post-template.php +++ b/wp-includes/post-template.php @@ -1300,23 +1300,34 @@ function wp_post_revision_title( $revision, $link = true ) { if ( !in_array( $revision->post_type, array( 'post', 'page', 'revision' ) ) ) return false; + $author = get_the_author_meta( 'display_name', $revision->post_author ); /* translators: revision date format, see http://php.net/date */ - $datef = _x( 'j F, Y @ G:i', 'revision date format'); - /* translators: 1: date */ - $autosavef = __( '%1$s [Autosave]' ); - /* translators: 1: date */ - $currentf = __( '%1$s [Current Revision]' ); + $datef = _x( 'j F, Y @ G:i:s', 'revision date format'); + + $gravatar = get_avatar( $revision->post_author, 18 ); $date = date_i18n( $datef, strtotime( $revision->post_modified ) ); if ( $link && current_user_can( 'edit_post', $revision->ID ) && $link = get_edit_post_link( $revision->ID ) ) $date = "$date"; + + $revision_date_author = sprintf( + '%s %s, %s %s (%s)', + $gravatar, + $author, + human_time_diff( strtotime( $revision->post_modified ), current_time( 'timestamp' ) ), + __( 'ago' ), + $date + ); + + $autosavef = __( '%1$s [Autosave]' ); + $currentf = __( '%1$s [Current Revision]' ); if ( !wp_is_post_revision( $revision ) ) - $date = sprintf( $currentf, $date ); + $revision_date_author = sprintf( $currentf, $revision_date_author ); elseif ( wp_is_post_autosave( $revision ) ) - $date = sprintf( $autosavef, $date ); + $revision_date_author = sprintf( $autosavef, $revision_date_author ); - return $date; + return $revision_date_author; } /** diff --git a/wp-includes/script-loader.php b/wp-includes/script-loader.php index d168c2c99a..5be260b025 100644 --- a/wp-includes/script-loader.php +++ b/wp-includes/script-loader.php @@ -270,7 +270,10 @@ function wp_default_scripts( &$scripts ) { $scripts->add( 'json2', "/wp-includes/js/json2$suffix.js", array(), '2011-02-23'); $scripts->add( 'underscore', '/wp-includes/js/underscore.min.js', array(), '1.4.4', 1 ); - $scripts->add( 'backbone', '/wp-includes/js/backbone.min.js', array('underscore','jquery'), '0.9.2', 1 ); + $scripts->add( 'template', "/wp-includes/js/template$suffix.js", array('underscore'), '1.4.4', 1 ); + $scripts->add( 'backbone', '/wp-includes/js/backbone.min.js', array('underscore','jquery', 'template'), '0.9.2', 1 ); + + $scripts->add( 'revisions', "/wp-admin/js/revisions$suffix.js", array( 'backbone', 'jquery-ui-slider' ), false, 1 ); $scripts->add( 'imgareaselect', "/wp-includes/js/imgareaselect/jquery.imgareaselect$suffix.js", array('jquery'), '0.9.8', 1 ); @@ -539,6 +542,8 @@ function wp_default_styles( &$styles ) { $styles->add( 'customize-controls', "/wp-admin/css/customize-controls$suffix.css", array( 'wp-admin', 'colors', 'ie' ) ); $styles->add( 'media-views', "/wp-includes/css/media-views$suffix.css", array( 'buttons' ) ); $styles->add( 'buttons', "/wp-includes/css/buttons$suffix.css" ); + $styles->add( 'wp-jquery-ui-slider', "/wp-includes/css/jquery-ui-slider$suffix.css" ); + $styles->add( 'revisions', "/wp-admin/css/revisions$suffix.css", array( 'wp-jquery-ui-slider' ) ); foreach ( $rtl_styles as $rtl_style ) { $styles->add_data( $rtl_style, 'rtl', true ); diff --git a/wp-includes/wp-diff.php b/wp-includes/wp-diff.php index 65dd00743d..be6187f697 100644 --- a/wp-includes/wp-diff.php +++ b/wp-includes/wp-diff.php @@ -59,6 +59,15 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { */ var $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline'; + /** + * Should we show the split view or not + * + * @var string + * @access protected + * @since 3.6.0 + */ + var $_show_split_view = true; + /** * Constructor - Call parent constructor with params array. * @@ -70,6 +79,8 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { */ function __construct( $params = array() ) { parent::__construct( $params ); + if ( isset( $params[ 'show_split_view' ] ) ) + $this->_show_split_view = $params[ 'show_split_view' ]; } /** @@ -98,7 +109,8 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { * @return string */ function addedLine( $line ) { - return ""; + return ""; + } /** @@ -108,7 +120,7 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { * @return string */ function deletedLine( $line ) { - return ""; + return ""; } /** @@ -118,7 +130,7 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { * @return string */ function contextLine( $line ) { - return ""; + return ""; } /** @@ -127,7 +139,7 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { * @return string */ function emptyLine() { - return ''; + return ''; } /** @@ -142,8 +154,12 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { $r = ''; foreach ($lines as $line) { if ( $encode ) - $line = htmlspecialchars( $line ); - $r .= '' . $this->emptyLine() . $this->addedLine( $line ) . "\n"; + $line = wp_kses_post( $line ); + if ( $this->_show_split_view ) { + $r .= '' . $this->emptyLine() . $this->emptyLine() . $this->addedLine( $line ) . "\n"; + } else { + $r .= '' . $this->addedLine( $line ) . "\n"; + } } return $r; } @@ -160,8 +176,13 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { $r = ''; foreach ($lines as $line) { if ( $encode ) - $line = htmlspecialchars( $line ); - $r .= '' . $this->deletedLine( $line ) . $this->emptyLine() . "\n"; + $line = wp_kses_post( $line ); + if ( $this->_show_split_view ) { + $r .= '' . $this->deletedLine( $line ) . $this->emptyLine() . $this->emptyLine() . "\n"; + } else { + $r .= '' . $this->deletedLine( $line ) . "\n"; + } + } return $r; } @@ -178,9 +199,12 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { $r = ''; foreach ($lines as $line) { if ( $encode ) - $line = htmlspecialchars( $line ); - $r .= '' . - $this->contextLine( $line ) . $this->contextLine( $line ) . "\n"; + $line = wp_kses_post( $line ); + if ( $this->_show_split_view ) { + $r .= '' . $this->contextLine( $line ) . $this->emptyLine() . $this->contextLine( $line ) . "\n"; + } else { + $r .= '' . $this->contextLine( $line ) . "\n"; + } } return $r; } @@ -264,7 +288,11 @@ class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { } elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row. $r .= $this->_deleted( array($orig_line), false ); } else { // A true changed row. - $r .= '' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "\n"; + if ( $this->_show_split_view ) { + $r .= '' . $this->deletedLine( $orig_line ) . $this->emptyLine() . $this->addedLine( $final_line ) . "\n"; + } else { + $r .= '' . $this->deletedLine( $orig_line ) . "" . $this->addedLine( $final_line ) . "\n"; + } } }
+{$line}{$line}-{$line}{$line} {$line}{$line}