Ticket #6775: 6775.diff

File 6775.diff, 91.2 kB (added by mdawaffe, 8 months ago)
  • wp-includes/default-filters.php

    old new  
    178178add_action('init', 'smilies_init', 5); 
    179179add_action( 'plugins_loaded', 'wp_maybe_load_widgets', 0 ); 
    180180add_action( 'shutdown', 'wp_ob_end_flush_all', 1); 
     181add_action( 'pre_post_update', 'wp_save_revision' ); 
    181182add_action('publish_post', '_publish_post_hook', 5, 1); 
    182183add_action('future_post', '_future_post_hook', 5, 2); 
    183184add_action('future_page', '_future_post_hook', 5, 2); 
  • wp-includes/post-template.php

    old new  
    564564        return false; 
    565565} 
    566566 
    567 ?> 
     567/** 
     568 * wp_post_revision_time() - returns formatted datetimestamp of a revision 
     569 * 
     570 * @package WordPress 
     571 * @subpackage Post Revisions 
     572 * @since 2.6 
     573 * 
     574 * @uses wp_get_revision() 
     575 * @uses date_i18n() 
     576 * 
     577 * @param int|object $revision revision ID or revision object 
     578 * @return string i18n formatted datetimestamp or localized 'Corrent Revision' 
     579 */ 
     580function wp_post_revision_time( $revision ) { 
     581        if ( !$revision = wp_get_revision( $revision ) ) { 
     582                if ( $revision = get_post( $revision ) ) 
     583                        return __( 'Current Revision' ); 
     584                return $revision; 
     585        } 
     586 
     587        $datef  = _c( 'j F, Y @ G:i|revision date format'); 
     588        return date_i18n( $datef, strtotime( $revision->post_date_gmt . ' +0000' ) ); 
     589
     590 
     591/** 
     592 * wp_list_post_revisions() - echoes list of a post's revisions 
     593 * 
     594 * Can output either a UL with edit links or a TABLE with diff interface, and restore action links 
     595 * 
     596 * Second argument controls parameters: 
     597 *   (bool)   parent : include the parent (the "Current Revision") in the list 
     598 *   (string) format : 'list' or 'form-table'.  'list' outputs UL, 'form-table' outputs TABLE with UI 
     599 *   (int)    right  : what revision is currently being viewed - used in form-table format 
     600 *   (int)    left   : what revision is currently being diffed against right - used in form-table format 
     601 * 
     602 * @package WordPress 
     603 * @subpackage Post Revisions 
     604 * @since 2.6 
     605 * 
     606 * @uses wp_get_post_revisions() 
     607 * @uses wp_post_revision_time() 
     608 * @uses get_edit_post_link() 
     609 * @uses get_author_name() 
     610 * 
     611 * @param int|object $post_id post ID or post object 
     612 * @param string|array $args see description @see wp_parse_args() 
     613 */ 
     614function wp_list_post_revisions( $post_id = 0, $args = null ) { // TODO? split into two functions (list, form-table) ? 
     615        if ( !$post = get_post( $post_id ) ) 
     616                return; 
     617 
     618        if ( !$revisions = wp_get_post_revisions( $post->ID ) ) 
     619                return; 
     620 
     621        $defaults = array( 'parent' => false, 'right' => false, 'left' => false, 'format' => 'list' ); 
     622        extract( wp_parse_args( $args, $defaults ), EXTR_SKIP ); 
     623 
     624        $titlef = _c( '%1$s by %2$s|post revision 1:datetime, 2:name' ); 
     625 
     626        if ( $parent ) 
     627                array_unshift( $revisions, $post ); 
     628 
     629        $rows = ''; 
     630        $class = false; 
     631        foreach ( $revisions as $revision ) { 
     632                $date = wp_post_revision_time( $revision ); 
     633                if ( $link = get_edit_post_link( $revision->ID ) ) 
     634                        $date = "<a href='$link'>$date</a>"; 
     635                $name = get_author_name( $revision->post_author ); 
     636 
     637                if ( 'form-table' == $format ) { 
     638                        if ( $left ) 
     639                                $old_checked = $left == $revision->ID ? ' checked="checked"' : ''; 
     640                        else 
     641                                $old_checked = $new_checked ? ' checked="checked"' : ''; 
     642                        $new_checked = $right == $revision->ID ? ' checked="checked"' : ''; 
     643 
     644                        $class = $class ? '' : " class='alternate'"; 
     645 
     646                        if ( $post->ID != $revision->ID && current_user_can( 'edit_post', $post->ID ) ) 
     647                                $actions = '<a href="' . wp_nonce_url( add_query_arg( array( 'revision' => $revision->ID, 'diff' => false, 'restore' => 'restore' ) ), "restore-post_$post->ID|$revision->ID" ) . '">' . __( 'Restore' ) . '</a>'; 
     648                        else 
     649                                $actions = ''; 
     650 
     651                        $rows .= "<tr$class>\n"; 
     652                        $rows .= "\t<th style='white-space: nowrap' scope='row'><input type='radio' name='diff' value='$revision->ID'$old_checked /><input type='radio' name='revision' value='$revision->ID'$new_checked />\n"; 
     653                        $rows .= "\t<td>$date</td>\n"; 
     654                        $rows .= "\t<td>$name</td>\n"; 
     655                        $rows .= "\t<td class='action-links'>$actions</td>\n"; 
     656                        $rows .= "</tr>\n"; 
     657                } else { 
     658                        $rows .= "\t<li>" . sprintf( $titlef, $date, $name ). "</li>\n"; 
     659                } 
     660        } 
     661 
     662        if ( 'form-table' == $format ) : ?> 
     663 
     664<form action="revision.php" method="get"> 
     665 
     666<div class="tablenav"> 
     667        <div class="alignleft"> 
     668                <input type="submit" class="button-secondary" value="<?php _e( 'Compare Revisions' ); ?>" /> 
     669        </div> 
     670</div> 
     671 
     672<br class="clear" /> 
     673 
     674<table class="widefat post-revisions"> 
     675        <col /> 
     676        <col style="width: 33%" /> 
     677        <col style="width: 33%" /> 
     678        <col style="width: 33%" /> 
     679<thead> 
     680        <th scope="col"></th> 
     681        <th scope="col"><?php _e( 'Date Created' ); ?></th> 
     682        <th scope="col"><?php _e( 'Author' ); ?></th> 
     683        <th scope="col" class="action-links"><?php _e( 'Actions' ); ?></th> 
     684</thead> 
     685<tbody> 
     686 
     687<?php echo $rows; ?> 
     688 
     689</tbody> 
     690</table> 
     691 
     692<?php 
     693        else : 
     694                echo "<ul class='post-revisions'>\n"; 
     695                echo $rows; 
     696                echo "</ul>"; 
     697        endif; 
     698 
     699
  • wp-includes/post.php

    old new  
    29902990        } 
    29912991} 
    29922992 
     2993/* Post Revisions */ 
     2994 
     2995/** 
     2996 * _wp_revision_fields() - determines which fields of posts are to be saved in revisions 
     2997 * 
     2998 * Does two things. If passed a postn *array*, it will return a post array ready to be 
     2999 * insterted into the posts table as a post revision. 
     3000 * Otherwise, returns an array whose keys are the post fields to be saved post revisions. 
     3001 * 
     3002 * @package WordPress 
     3003 * @subpackage Post Revisions 
     3004 * @since 2.6 
     3005 * 
     3006 * @param array $post optional a post array to be processed for insertion as a post revision 
     3007 * @return array post array ready to be inserted as a post revision or array of fields that can be versioned 
     3008 */ 
     3009function _wp_revision_fields( $post = null ) { 
     3010        static $fields = false; 
     3011 
     3012        if ( !$fields ) { 
     3013                // Allow these to be versioned 
     3014                $fields = array( 
     3015                        'post_title' => __( 'Title' ), 
     3016                        'post_author' => __( 'Author' ), 
     3017                        'post_content' => __( 'Content' ), 
     3018                        'post_excerpt' => __( 'Excerpt' ), 
     3019                ); 
     3020 
     3021                // WP uses these internally either in versioning or elsewhere - they cannot be versioned 
     3022                foreach ( array( 'ID', 'post_name', 'post_parent', 'post_date', 'post_date_gmt', 'post_status', 'post_type', 'comment_count' ) as $protect ) 
     3023                        unset( $fields[$protect] ); 
     3024        } 
     3025 
     3026        if ( !is_array($post) ) 
     3027                return $fields; 
     3028 
     3029        $return = array(); 
     3030        foreach ( array_intersect( array_keys( $post ), array_keys( $fields ) ) as $field ) 
     3031                $return[$field] = $post[$field]; 
     3032 
     3033        $return['post_parent']   = $post['ID']; 
     3034        $return['post_status']   = 'inherit'; 
     3035        $return['post_type']     = 'revision'; 
     3036        $return['post_name']     = "$post[ID]-revision"; 
     3037        $return['post_date']     = $post['post_modified']; 
     3038        $return['post_date_gmt'] = $post['post_modified_gmt']; 
     3039 
     3040        return $return; 
     3041} 
     3042 
     3043/** 
     3044 * wp_save_revision() - Saves an already existing post as a post revision.  Typically used immediately prior to post updates. 
     3045 * 
     3046 * @package WordPress 
     3047 * @subpackage Post Revisions 
     3048 * @since 2.6 
     3049 * 
     3050 * @uses _wp_put_revision() 
     3051 * 
     3052 * @param int $post_id The ID of the post to save as a revision 
     3053 * @return mixed null or 0 if error, new revision ID if success 
     3054 */ 
     3055function wp_save_revision( $post_id ) { 
     3056        // TODO: rework autosave to use special type of post revision 
     3057        if ( @constant( 'DOING_AUTOSAVE' ) ) 
     3058                return; 
     3059 
     3060        if ( !$post = get_post( $post_id, ARRAY_A ) ) 
     3061                return; 
     3062 
     3063        // TODO: open this up for pages also 
     3064        if ( 'post' != $post->post_type ) 
     3065                retun; 
     3066 
     3067        return _wp_put_revision( $post ); 
     3068} 
     3069 
     3070/** 
     3071 * _wp_put_revision() - Inserts post data into the posts table as a post revision 
     3072 * 
     3073 * @package WordPress 
     3074 * @subpackage Post Revisions 
     3075 * @since 2.6 
     3076 * 
     3077 * @uses wp_insert_post() 
     3078 * 
     3079 * @param int|object|array $post post ID, post object OR post array 
     3080 * @return mixed null or 0 if error, new revision ID if success 
     3081 */ 
     3082function _wp_put_revision( $post = null ) { 
     3083        if ( is_object($post) ) 
     3084                $post = get_object_vars( $post ); 
     3085        elseif ( !is_array($post) ) 
     3086                $post = get_post($post, ARRAY_A); 
     3087 
     3088        if ( !$post || empty($post['ID']) ) 
     3089                return; 
     3090 
     3091        if ( isset($post['post_type']) && 'revision' == $post_post['type'] ) 
     3092                return new WP_Error( 'post_type', __( 'Cannot create a revision of a revision' ) ); 
     3093 
     3094        $post = _wp_revision_fields( $post ); 
     3095 
     3096        if ( $revision_id = wp_insert_post( $post ) ) 
     3097                do_action( '_wp_put_revision', $revision_id ); 
     3098 
     3099        return $revision_id; 
     3100} 
     3101 
     3102/** 
     3103 * wp_get_revision() - Gets a post revision 
     3104 * 
     3105 * @package WordPress 
     3106 * @subpackage Post Revisions 
     3107 * @since 2.6 
     3108 * 
     3109 * @uses get_post() 
     3110 * 
     3111 * @param int|object $post post ID or post object 
     3112 * @param $output optional OBJECT, ARRAY_A, or ARRAY_N 
     3113 * @param string $filter optional sanitation filter.  @see sanitize_post() 
     3114 * @return mixed null if error or post object if success 
     3115 */ 
     3116function &wp_get_revision(&$post, $output = OBJECT, $filter = 'raw') { 
     3117        $null = null; 
     3118        if ( !$revision = get_post( $post, OBJECT, $filter ) ) 
     3119                return $revision; 
     3120        if ( 'revision' !== $revision->post_type ) 
     3121                return $null; 
     3122 
     3123        if ( $output == OBJECT ) { 
     3124                return $revision; 
     3125        } elseif ( $output == ARRAY_A ) { 
     3126                $_revision = get_object_vars($revision); 
     3127                return $_revision; 
     3128        } elseif ( $output == ARRAY_N ) { 
     3129                $_revision = array_values(get_object_vars($revision)); 
     3130                return $_revision; 
     3131        } 
     3132 
     3133        return $revision; 
     3134} 
     3135 
     3136/** 
     3137 * wp_restore_revision() - Restores a post to the specified revision 
     3138 * 
     3139 * Can restore a past using all fields of the post revision, or only selected fields. 
     3140 * 
     3141 * @package WordPress 
     3142 * @subpackage Post Revisions 
     3143 * @since 2.6 
     3144 * 
     3145 * @uses wp_get_revision() 
     3146 * @uses wp_update_post() 
     3147 * 
     3148 * @param int|object $revision_id revision ID or revision object 
     3149 * @param array $fields optional What fields to restore from.  Defaults to all. 
     3150 * @return mixed null if error, false if no fields to restore, (int) post ID if success 
     3151 */ 
     3152function wp_restore_revision( $revision_id, $fields = null ) { 
     3153        if ( !$revision = wp_get_revision( $revision_id, ARRAY_A ) ) 
     3154                return $revision; 
     3155 
     3156        if ( !is_array( $fields ) ) 
     3157                $fields = array_keys( _wp_revision_fields() ); 
     3158 
     3159        $update = array(); 
     3160        foreach( array_intersect( array_keys( $revision ), $fields ) as $field ) 
     3161                $update[$field] = $revision[$field]; 
     3162 
     3163        if ( !$update ) 
     3164                return false; 
     3165 
     3166        $update['ID'] = $revision['post_parent']; 
     3167 
     3168        if ( $post_id = wp_update_post( $update ) ) 
     3169                do_action( 'wp_restore_revision', $post_id, $revision['ID'] ); 
     3170 
     3171        return $post_id; 
     3172} 
     3173 
     3174/** 
     3175 * wp_delete_revision() - Deletes a revision. 
     3176 * 
     3177 * Deletes the row from the posts table corresponding to the specified revision 
     3178 * 
     3179 * @package WordPress 
     3180 * @subpackage Post Revisions 
     3181 * @since 2.6 
     3182 * 
     3183 * @uses wp_get_revision() 
     3184 * @uses wp_delete_post() 
     3185 * 
     3186 * @param int|object $revision_id revision ID or revision object 
     3187 * @param array $fields optional What fields to restore from.  Defaults to all. 
     3188 * @return mixed null if error, false if no fields to restore, (int) post ID if success 
     3189 */ 
     3190function wp_delete_revision( $revision_id ) { 
     3191        if ( !$revision = wp_get_revision( $revision_id ) ) 
     3192                return $revision; 
     3193 
     3194        if ( $delete = wp_delete_post( $revision->ID ) ) 
     3195                do_action( 'wp_delete_revision', $revision->ID, $revision ); 
     3196 
     3197        return $delete; 
     3198} 
     3199 
     3200/** 
     3201 * wp_get_post_revisions() - Returns all revisions of specified post 
     3202 * 
     3203 * @package WordPress 
     3204 * @subpackage Post Revisions 
     3205 * @since 2.6 
     3206 * 
     3207 * @uses get_children() 
     3208 * 
     3209 * @param int|object $post_id post ID or post object 
     3210 * @return array empty if no revisions 
     3211 */ 
     3212function wp_get_post_revisions( $post_id = 0 ) { 
     3213        if ( ( !$post = get_post( $post_id ) ) || empty( $post->ID ) ) 
     3214                return array(); 
     3215 
     3216        if ( !$revisions = get_children( array( 'post_parent' => $post->ID, 'post_type' => 'revision' ) ) ) 
     3217                return array(); 
     3218        return $revisions; 
     3219} 
     3220 
    29933221?> 
  • wp-includes/wp-diff.php

    old new  
     1<?php 
     2 
     3if ( !class_exists( 'Text_Diff' ) ) { 
     4        require( 'Text/Diff.php' ); 
     5        require( 'Text/Diff/Renderer.php' ); 
     6        require( 'Text/Diff/Renderer/inline.php' ); 
     7} 
     8 
     9 
     10/* Descendent of a bastard child of piece of an old MediaWiki Diff Formatter 
     11 * 
     12 * Basically all that remains is the table structure and some method names. 
     13 */ 
     14 
     15class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer { 
     16        var $_leading_context_lines  = 10000; 
     17        var $_trailing_context_lines = 10000; 
     18        var $_diff_threshold = 0.6; 
     19 
     20        var $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline'; 
     21 
     22        function Text_Diff_Renderer_Table( $params = array() ) { 
     23                $parent = get_parent_class($this); 
     24                $this->$parent( $params ); 
     25        } 
     26 
     27        function _startBlock( $header ) { 
     28                return ''; 
     29        } 
     30 
     31        function _lines( $lines, $prefix=' ' ) { 
     32        } 
     33 
     34        // HTML-escape parameter before calling this 
     35        function addedLine( $line ) { 
     36                return "<td>+</td><td class='diff-addedline'>{$line}</td>"; 
     37        } 
     38 
     39        // HTML-escape parameter before calling this 
     40        function deletedLine( $line ) { 
     41                return "<td>-</td><td class='diff-deletedline'>{$line}</td>"; 
     42        } 
     43 
     44        // HTML-escape parameter before calling this 
     45        function contextLine( $line ) { 
     46                return "<td> </td><td class='diff-context'>{$line}</td>"; 
     47        } 
     48 
     49        function emptyLine() { 
     50                return '<td colspan="2">&nbsp;</td>'; 
     51        } 
     52 
     53        function _added( $lines, $encode = true ) { 
     54                $r = ''; 
     55                foreach ($lines as $line) { 
     56                        if ( $encode ) 
     57                                $line = htmlspecialchars( $line ); 
     58                        $r .= '<tr>' . $this->emptyLine() . $this->addedLine( $line ) . "</tr>\n"; 
     59                } 
     60                return $r; 
     61        } 
     62 
     63        function _deleted( $lines, $encode = true ) { 
     64                $r = ''; 
     65                foreach ($lines as $line) { 
     66                        if ( $encode ) 
     67                                $line = htmlspecialchars( $line ); 
     68                        $r .= '<tr>' . $this->deletedLine( $line ) . $this->emptyLine() . "</tr>\n"; 
     69                } 
     70                return $r; 
     71        } 
     72 
     73        function _context( $lines, $encode = true ) { 
     74                $r = ''; 
     75                foreach ($lines as $line) { 
     76                        if ( $encode ) 
     77                                $line = htmlspecialchars( $line ); 
     78                        $r .= '<tr>' . 
     79                                $this->contextLine( $line ) . $this->contextLine( $line ) . "</tr>\n"; 
     80                } 
     81                return $r; 
     82        } 
     83 
     84        // Process changed lines to do word-by-word diffs for extra highlighting (TRAC style) 
     85        // sometimes these lines can actually be deleted or added rows - we do additional processing 
     86        // to figure that out 
     87        function _changed( $orig, $final ) { 
     88                $r = ''; 
     89 
     90                // Does the aforementioned additional processing 
     91                // *_matches tell what rows are "the same" in orig and final.  Those pairs will be diffed to get word changes 
     92                //      match is numeric: an index in other column 
     93                //      match is 'X': no match.  It is a new row 
     94                // *_rows are column vectors for the orig column and the final column. 
     95                //      row >= 0: an indix of the $orig or $final array 
     96                //      row  < 0: a blank row for that column 
     97                list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final ); 
     98 
     99 
     100                // These will hold the word changes as determined by an inline diff 
     101                $orig_diffs  = array(); 
     102                $final_diffs = array(); 
     103 
     104                // Compute word diffs for each matched pair using the inline diff 
     105                foreach ( $orig_matches as $o => $f ) { 
     106                        if ( is_numeric($o) && is_numeric($f) ) { 
     107                                $text_diff = new Text_Diff( 'auto', array( array($orig[$o]), array($final[$f]) ) ); 
     108                                $renderer = new $this->inline_diff_renderer; 
     109                                $diff = $renderer->render( $text_diff ); 
     110 
     111                                // If they're too different, don't include any <ins> or <dels> 
     112                                if ( $diff_count = preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) { 
     113                                        // length of all text between <ins> or <del> 
     114                                        $stripped_matches = strlen(strip_tags( join(' ', $diff_matches[0]) )); 
     115                                        // since we count lengith of text between <ins> or <del> (instead of picking just one), 
     116                                        //      we double the length of chars not in those tags. 
     117                                        $stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches; 
     118                                        $diff_ratio = $stripped_matches / $stripped_diff; 
     119                                        if ( $diff_ratio > $this->_diff_threshold ) 
     120                                                continue; // Too different.  Don't save diffs. 
     121                                } 
     122 
     123                                // Un-inline the diffs by removing del or ins 
     124                                $orig_diffs[$o]  = preg_replace( '|<ins>.*?</ins>|', '', $diff ); 
     125                                $final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff ); 
     126                        } 
     127                } 
     128 
     129                foreach ( array_keys($orig_rows) as $row ) { 
     130                        // Both columns have blanks.  Ignore them. 
     131                        if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 ) 
     132                                continue; 
     133 
     134                        // If we have a word based diff, use it.  Otherwise, use the normal line. 
     135                        $orig_line  = isset($orig_diffs[$orig_rows[$row]]) 
     136                                ? $orig_diffs[$orig_rows[$row]] 
     137                                : htmlspecialchars($orig[$orig_rows[$row]]); 
     138                        $final_line = isset($final_diffs[$final_rows[$row]]) 
     139                                ? $final_diffs[$final_rows[$row]] 
     140                                : htmlspecialchars($final[$final_rows[$row]]); 
     141 
     142                        if ( $orig_rows[$row] < 0 ) { // Orig is blank.  This is really an added row. 
     143                                $r .= $this->_added( array($final_line), false ); 
     144                        } elseif ( $final_rows[$row] < 0 ) { // Final is blank.  This is really a deleted row. 
     145                                $r .= $this->_deleted( array($orig_line), false ); 
     146                        } else { // A true changed row. 
     147                                $r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "</tr>\n"; 
     148                        } 
     149                } 
     150 
     151                return $r; 
     152        } 
     153 
     154        // Takes changed blocks and matches which rows in orig turned into which rows in final. 
     155        // Returns 
     156        //      *_matches ( which rows match with which ) 
     157        //      *_rows ( order of rows in each column interleaved with blank rows as necessary ) 
     158        function interleave_changed_lines( $orig, $final ) { 
     159 
     160                // Contains all pairwise string comparisons.  Keys are such that this need only be a one dimensional array. 
     161                $matches = array(); 
     162                foreach ( array_keys($orig) as $o ) { 
     163                        foreach ( array_keys($final) as $f ) { 
     164                                $matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] ); 
     165                        } 
     166                } 
     167                asort($matches); // Order by string distance. 
     168 
     169                $orig_matches  = array(); 
     170                $final_matches = array(); 
     171 
     172                foreach ( $matches as $keys => $difference ) { 
     173                        list($o, $f) = explode(',', $keys); 
     174                        $o = (int) $o; 
     175                        $f = (int) $f; 
     176 
     177                        // Already have better matches for these guys 
     178                        if ( isset($orig_matches[$o]) && isset($final_matches[$f]) ) 
     179                                continue; 
     180 
     181                        // First match for these guys.  Must be best match 
     182                        if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) { 
     183                                $orig_matches[$o] = $f; 
     184                                $final_matches[$f] = $o; 
     185                                continue; 
     186                        } 
     187 
     188                        // Best match of this final is already taken?  Must mean this final is a new row. 
     189                        if ( isset($orig_matches[$o]) ) 
     190                                $final_matches[$f] = 'x'; 
     191 
     192                        // Best match of this orig is already taken?  Must mean this orig is a deleted row. 
     193                        elseif ( isset($final_matches[$f]) ) 
     194                                $orig_matches[$o] = 'x'; 
     195                } 
     196 
     197                // We read the text in this order 
     198                ksort($orig_matches); 
     199                ksort($final_matches); 
     200 
     201 
     202                // Stores rows and blanks for each column. 
     203                $orig_rows = $orig_rows_copy = array_keys($orig_matches); 
     204                $final_rows = array_keys($final_matches); 
     205 
     206                // Interleaves rows with blanks to keep matches aligned. 
     207                // We may end up with some extraneous blank rows, but we'll just ignore them later. 
     208                foreach ( $orig_rows_copy as $orig_row ) { 
     209                        $final_pos = array_search($orig_matches[$orig_row], $final_rows, true); 
     210                        $orig_pos = (int) array_search($orig_row, $orig_rows, true); 
     211 
     212                        if ( false === $final_pos ) { // This orig is paired with a blank final. 
     213                                array_splice( $final_rows, $orig_pos, 0, -1 ); 
     214                        } elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways.  Pad final with blank rows. 
     215                                $diff_pos = $final_pos - $orig_pos; 
     216                                while ( $diff_pos < 0 ) 
     217                                        array_splice( $final_rows, $orig_pos, 0, $diff_pos++ ); 
     218                        } elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways.  Pad orig with blank rows. 
     219                                $diff_pos = $orig_pos - $final_pos; 
     220                                while ( $diff_pos < 0 ) 
     221                                        array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ ); 
     222                        } 
     223                } 
     224 
     225 
     226                // Pad the ends with blank rows if the columns aren't the same length 
     227                $diff_count = count($orig_rows) - count($final_rows); 
     228                if ( $diff_count < 0 ) { 
     229                        while ( $diff_count < 0 ) 
     230                                array_push($orig_rows, $diff_count++); 
     231                } elseif ( $diff_count > 0 ) { 
     232                        $diff_count = -1 * $diff_count; 
     233                        while ( $diff_count < 0 ) 
     234                                array_push($final_rows, $diff_count++); 
     235                } 
     236 
     237                return array($orig_matches, $final_matches, $orig_rows, $final_rows); 
     238 
     239/* 
     240                // Debug 
     241                echo "\n\n\n\n\n"; 
     242 
     243                echo "-- DEBUG Matches: Orig -> Final --"; 
     244 
     245                foreach ( $orig_matches as $o => $f ) { 
     246                        echo "\n\n\n\n\n"; 
     247                        echo "ORIG: $o, FINAL: $f\n"; 
     248                        var_dump($orig[$o],$final[$f]); 
     249                } 
     250                echo "\n\n\n\n\n"; 
     251 
     252                echo "-- DEBUG Matches: Final -> Orig --"; 
     253 
     254                foreach ( $final_matches as $f => $o ) { 
     255                        echo "\n\n\n\n\n"; 
     256                        echo "FINAL: $f, ORIG: $o\n"; 
     257                        var_dump($final[$f],$orig[$o]); 
     258                } 
     259                echo "\n\n\n\n\n"; 
     260 
     261                echo "-- DEBUG Rows: Orig -- Final --"; 
     262 
     263                echo "\n\n\n\n\n"; 
     264                foreach ( $orig_rows as $row => $o ) { 
     265                        if ( $o < 0 ) 
     266                                $o = 'X'; 
     267                        $f = $final_rows[$row]; 
     268                        if ( $f < 0 ) 
     269                                $f = 'X'; 
     270                        echo "$o -- $f\n"; 
     271                } 
     272                echo "\n\n\n\n\n"; 
     273 
     274                echo "-- END DEBUG --"; 
     275 
     276                echo "\n\n\n\n\n"; 
     277 
     278                return array($orig_matches, $final_matches, $orig_rows, $final_rows); 
     279*/ 
     280        } 
     281 
     282 
     283        // Computes a number that is intended to reflect the "distance" between two strings. 
     284        function compute_string_distance( $string1, $string2 ) { 
     285                // Vectors containing character frequency for all chars in each string 
     286                $chars1 = count_chars($string1); 
     287                $chars2 = count_chars($string2); 
     288 
     289                // L1-norm of difference vector. 
     290                $difference = array_sum( array_map( array(&$this, 'difference'), $chars1, $chars2 ) ); 
     291 
     292                // $string1 has zero length? Odd.  Give huge penalty by not dividing. 
     293                if ( !$string1 ) 
     294                        return $difference; 
     295 
     296                // Return distance per charcter (of string1) 
     297                return $difference / strlen($string1); 
     298        } 
     299 
     300        function difference( $a, $b ) { 
     301                return abs( $a - $b ); 
     302        } 
     303 
     304} 
     305 
     306// Better word splitting than the PEAR package provides 
     307class WP_Text_Diff_Renderer_inline extends Text_Diff_Renderer_inline { 
     308 
     309        function _splitOnWords($string, $newlineEscape = "\n") { 
     310                $string = str_replace("\0", '', $string); 
     311                $words  = preg_split( '/([^\w])/', $string, -1, PREG_SPLIT_DELIM_CAPTURE ); 
     312                $words  = str_replace( "\n", $newlineEscape, $words ); 
     313                return $words; 
     314        } 
     315 
     316} 
     317 
     318?> 
  • wp-includes/link-template.php

    old new  
    442442        return $link; 
    443443} 
    444444 
    445 function get_edit_post_link( $id = 0 ) { 
     445function get_edit_post_link( $id = 0, $context = 'display' ) { 
    446446        if ( !$post = &get_post( $id ) ) 
    447447                return; 
    448448 
     449        if ( 'display' == $context ) 
     450                $action = 'action=edit&amp;'; 
     451        else 
     452                $action = 'action=edit&'; 
     453 
    449454        switch ( $post->post_type ) : 
    450455        case 'page' : 
    451456                if ( !current_user_can( 'edit_page', $post->ID ) ) 
     
    459464                $file = 'media'; 
    460465                $var  = 'attachment_id'; 
    461466                break; 
     467        case 'revision' : 
     468                if ( !current_user_can( 'edit_post', $post->ID ) ) 
     469                        return; 
     470                $file = 'revision'; 
     471                $var  = 'revision'; 
     472                $action = ''; 
     473                break; 
    462474        default : 
    463475                if ( !current_user_can( 'edit_post', $post->ID ) ) 
    464476                        return; 
     
    467479                break; 
    468480        endswitch; 
    469481         
    470         return apply_filters( 'get_edit_post_link', get_bloginfo( 'wpurl' ) . "/wp-admin/$file.php?action=edit&amp;$var=$post->ID", $post->ID ); 
     482        return apply_filters( 'get_edit_post_link', get_bloginfo( 'wpurl' ) . "/wp-admin/$file.php?{$action}$var=$post->ID", $post->ID ); 
    471483} 
    472484 
    473485function edit_post_link( $link = 'Edit This', $before = '', $after = '' ) { 
  • wp-includes/Text/Diff/Engine/xdiff.php

    old new  
     1<?php 
     2/** 
     3 * Class used internally by Diff to actually compute the diffs. 
     4 * 
     5 * This class uses the xdiff PECL package (http://pecl.php.net/package/xdiff) 
     6 * to compute the differences between the two input arrays. 
     7 * 
     8 * $Horde: framework/Text_Diff/Diff/Engine/xdiff.php,v 1.6 2008/01/04 10:07:50 jan Exp $ 
     9 * 
     10 * Copyright 2004-2008 The Horde Project (http://www.horde.org/) 
     11 * 
     12 * See the enclosed file COPYING for license information (LGPL). If you did 
     13 * not receive this file, see http://opensource.org/licenses/lgpl-license.php. 
     14 * 
     15 * @author  Jon Parise <jon@horde.org> 
     16 * @package Text_Diff 
     17 */ 
     18class Text_Diff_Engine_xdiff { 
     19 
     20    /** 
     21     */ 
     22    function diff($from_lines, $to_lines) 
     23    { 
     24        array_walk($from_lines, array('Text_Diff', 'trimNewlines')); 
     25        array_walk($to_lines, array('Text_Diff', 'trimNewlines')); 
     26 
     27        /* Convert the two input arrays into strings for xdiff processing. */ 
     28        $from_string = implode("\n", $from_lines); 
     29        $to_string = implode("\n", $to_lines); 
     30 
     31        /* Diff the two strings and convert the result to an array. */ 
     32        $diff = xdiff_string_diff($from_string, $to_string, count($to_lines)); 
     33        $diff = explode("\n", $diff); 
     34 
     35        /* Walk through the diff one line at a time.  We build the $edits 
     36         * array of diff operations by reading the first character of the 
     37         * xdiff output (which is in the "unified diff" format). 
     38         * 
     39         * Note that we don't have enough information to detect "changed" 
     40         * lines using this approach, so we can't add Text_Diff_Op_changed 
     41         * instances to the $edits array.  The result is still perfectly 
     42         * valid, albeit a little less descriptive and efficient. */ 
     43        $edits = array(); 
     44        foreach ($diff as $line) { 
     45            switch ($line[0]) { 
     46            case ' ': 
     47                $edits[] = &new Text_Diff_Op_copy(array(substr($line, 1))); 
     48                break; 
     49 
     50            case '+': 
     51                $edits[] = &new Text_Diff_Op_add(array(substr($line, 1))); 
     52                break; 
     53 
     54            case '-': 
     55                $edits[] = &new Text_Diff_Op_delete(array(substr($line, 1))); 
     56                break; 
     57            } 
     58        } 
     59 
     60        return $edits; 
     61    } 
     62 
     63} 
  • wp-includes/Text/Diff/Engine/native.php

    old new  
     1<?php 
     2/** 
     3 * $Horde: framework/Text_Diff/Diff/Engine/native.php,v 1.10 2008/01/04 10:27:53 jan Exp $ 
     4 * 
     5 * Class used internally by Text_Diff to actually compute the diffs. This 
     6 * class is implemented using native PHP code. 
     7 * 
     8 * The algorithm used here is mostly lifted from the perl module 
     9 * Algorithm::Diff (version 1.06) by Ned Konz, which is available at: 
     10 * http://www.perl.com/CPAN/authors/id/N/NE/NEDKONZ/Algorithm-Diff-1.06.zip 
     11 * 
     12 * More ideas are taken from: http://www.ics.uci.edu/~eppstein/161/960229.html 
     13 * 
     14 * Some ideas (and a bit of code) are taken from analyze.c, of GNU 
     15 * diffutils-2.7, which can be found at: 
     16 * ftp://gnudist.gnu.org/pub/gnu/diffutils/diffutils-2.7.tar.gz 
     17 * 
     18 * Some ideas (subdivision by NCHUNKS > 2, and some optimizations) are from 
     19 * Geoffrey T. Dairiki <dairiki@dairiki.org>. The original PHP version of this 
     20 * code was written by him, and is used/adapted with his permission. 
     21 * 
     22 * Copyright 2004-2008 The Horde Project (http://www.horde.org/) 
     23 * 
     24 * See the enclosed file COPYING for license information (LGPL). If you did 
     25 * not receive this file, see http://opensource.org/licenses/lgpl-license.php. 
     26 * 
     27 * @author  Geoffrey T. Dairiki <dairiki@dairiki.org> 
     28 * @package Text_Diff 
     29 */ 
     30class Text_Diff_Engine_native { 
     31 
     32    function diff($from_lines, $to_lines) 
     33    { 
     34        array_walk($from_lines, array('Text_Diff', 'trimNewlines')); 
     35        array_walk($to_lines, array('Text_Diff', 'trimNewlines')); 
     36 
     37        $n_from = count($from_lines); 
     38        $n_to = count($to_lines); 
     39 
     40        $this->xchanged = $this->ychanged = array(); 
     41        $this->xv = $this->yv = array(); 
     42        $this->xind = $this->yind = array(); 
     43        unset($this->seq); 
     44        unset($this->in_seq); 
     45        unset($this->lcs); 
     46 
     47        // Skip leading common lines. 
     48        for ($skip = 0; $skip < $n_from && $skip < $n_to; $skip++) { 
     49            if ($from_lines[$skip] !== $to_lines[$skip]) { 
     50                break; 
     51            } 
     52            $this->xchanged[$skip] = $this->ychanged[$skip] = false; 
     53        } 
     54 
     55        // Skip trailing common lines. 
     56        $xi = $n_from; $yi = $n_to; 
     57        for ($endskip = 0; --$xi > $skip && --$yi > $skip; $endskip++) { 
     58            if ($from_lines[$xi] !== $to_lines[$yi]) { 
     59                break; 
     60            } 
     61            $this->xchanged[$xi] = $this->ychanged[$yi] = false; 
     62        } 
     63 
     64        // Ignore lines which do not exist in both files. 
     65        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { 
     66            $xhash[$from_lines[$xi]] = 1; 
     67        } 
     68        for ($yi = $skip; $yi < $n_to - $endskip; $yi++) { 
     69            $line = $to_lines[$yi]; 
     70            if (($this->ychanged[$yi] = empty($xhash[$line]))) { 
     71                continue; 
     72            } 
     73            $yhash[$line] = 1; 
     74            $this->yv[] = $line; 
     75            $this->yind[] = $yi; 
     76        } 
     77        for ($xi = $skip; $xi < $n_from - $endskip; $xi++) { 
     78            $line = $from_lines[$xi]; 
     79            if (($this->xchanged[$xi] = empty($yhash[$line]))) { 
     80                continue; 
     81            } 
     82            $this->xv[] = $line; 
     83            $this->xind[] = $xi; 
     84        } 
     85 
     86        // Find the LCS. 
     87        $this->_compareseq(0, count($this->xv), 0, count($this->yv)); 
     88 
     89        // Merge edits when possible. 
     90        $this->_shiftBoundaries($from_lines, $this->xchanged, $this->ychanged); 
     91        $this->_shiftBoundaries($to_lines, $this->ychanged, $this->xchanged); 
     92 
     93        // Compute the edit operations. 
     94        $edits = array(); 
     95        $xi = $yi = 0; 
     96        while ($xi < $n_from || $yi < $n_to) { 
     97            assert($yi < $n_to || $this->xchanged[$xi]); 
     98            assert($xi < $n_from || $this->ychanged[$yi]); 
     99 
     100            // Skip matching "snake". 
     101            $copy = array(); 
     102            while ($xi < $n_from && $yi < $n_to 
     103                   && !$this->xchanged[$xi] && !$this->ychanged[$yi]) { 
     104                $copy[] = $from_lines[$xi++]; 
     105                ++$yi; 
     106            } 
     107            if ($copy) { 
     108                $edits[] = &new Text_Diff_Op_copy($copy); 
     109            } 
     110 
     111            // Find deletes & adds. 
     112            $delete = array(); 
     113            while ($xi < $n_from && $this->xchanged[$xi]) { 
     114                $delete[] = $from_lines[$xi++]; 
     115            } 
     116 
     117            $add = array(); 
     118            while ($yi < $n_to && $this->ychanged[$yi]) { 
     119                $add[] = $to_lines[$yi++]; 
     120            } 
     121 
     122            if ($delete && $add) { 
     123                $edits[] = &new Text_Diff_Op_change($delete, $add); 
     124            } elseif ($delete) { 
     125                $edits[] = &new Text_Diff_Op_delete($delete); 
     126            } elseif ($add) { 
     127                $edits[] = &new Text_Diff_Op_add($add); 
     128            } 
     129        } 
     130 
     131        return $edits; 
     132    } 
     133 
     134    /** 
     135     * Divides the Largest Common Subsequence (LCS) of the sequences (XOFF, 
     136     * XLIM) and (YOFF, YLIM) into NCHUNKS approximately equally sized 
     137     * segments. 
     138     * 
     139     * Returns (LCS, PTS).  LCS is the length of the LCS. PTS is an array of 
     140     * NCHUNKS+1 (X, Y) indexes giving the diving points between sub 
     141     * sequences.  The first sub-sequence is contained in (X0, X1), (Y0, Y1), 
     142     * the second in (X1, X2), (Y1, Y2) and so on.  Note that (X0, Y0) == 
     143     * (XOFF, YOFF) and (X[NCHUNKS], Y[NCHUNKS]) == (XLIM, YLIM).