web/wp-includes/wp-diff.php
changeset 194 32102edaa81b
parent 136 bde1974c263b
child 204 09a1c134465b
equal deleted inserted replaced
193:2f6f6f7551ca 194:32102edaa81b
    58 	 * @since 2.6.0
    58 	 * @since 2.6.0
    59 	 */
    59 	 */
    60 	var $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline';
    60 	var $inline_diff_renderer = 'WP_Text_Diff_Renderer_inline';
    61 
    61 
    62 	/**
    62 	/**
    63 	 * PHP4 Constructor - Call parent constructor with params array.
    63 	 * Constructor - Call parent constructor with params array.
    64 	 *
    64 	 *
    65 	 * This will set class properties based on the key value pairs in the array.
    65 	 * This will set class properties based on the key value pairs in the array.
    66 	 *
    66 	 *
    67 	 * @since unknown
    67 	 * @since 2.6.0
    68 	 *
    68 	 *
    69 	 * @param array $params
    69 	 * @param array $params
    70 	 */
    70 	 */
    71 	function Text_Diff_Renderer_Table( $params = array() ) {
    71 	function __construct( $params = array() ) {
    72 		$parent = get_parent_class($this);
    72 		parent::__construct( $params );
    73 		$this->$parent( $params );
       
    74 	}
    73 	}
    75 
    74 
    76 	/**
    75 	/**
    77 	 * @ignore
    76 	 * @ignore
    78 	 *
    77 	 *
   201 	 */
   200 	 */
   202 	function _changed( $orig, $final ) {
   201 	function _changed( $orig, $final ) {
   203 		$r = '';
   202 		$r = '';
   204 
   203 
   205 		// Does the aforementioned additional processing
   204 		// Does the aforementioned additional processing
   206 		// *_matches tell what rows are "the same" in orig and final.  Those pairs will be diffed to get word changes
   205 		// *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes
   207 		//	match is numeric: an index in other column
   206 		//	match is numeric: an index in other column
   208 		//	match is 'X': no match.  It is a new row
   207 		//	match is 'X': no match. It is a new row
   209 		// *_rows are column vectors for the orig column and the final column.
   208 		// *_rows are column vectors for the orig column and the final column.
   210 		//	row >= 0: an indix of the $orig or $final array
   209 		//	row >= 0: an indix of the $orig or $final array
   211 		//	row  < 0: a blank row for that column
   210 		//	row  < 0: a blank row for that column
   212 		list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
   211 		list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
   213 
       
   214 
   212 
   215 		// These will hold the word changes as determined by an inline diff
   213 		// These will hold the word changes as determined by an inline diff
   216 		$orig_diffs  = array();
   214 		$orig_diffs  = array();
   217 		$final_diffs = array();
   215 		$final_diffs = array();
   218 
   216 
   230 					// since we count lengith of text between <ins> or <del> (instead of picking just one),
   228 					// since we count lengith of text between <ins> or <del> (instead of picking just one),
   231 					//	we double the length of chars not in those tags.
   229 					//	we double the length of chars not in those tags.
   232 					$stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches;
   230 					$stripped_diff = strlen(strip_tags( $diff )) * 2 - $stripped_matches;
   233 					$diff_ratio = $stripped_matches / $stripped_diff;
   231 					$diff_ratio = $stripped_matches / $stripped_diff;
   234 					if ( $diff_ratio > $this->_diff_threshold )
   232 					if ( $diff_ratio > $this->_diff_threshold )
   235 						continue; // Too different.  Don't save diffs.
   233 						continue; // Too different. Don't save diffs.
   236 				}
   234 				}
   237 
   235 
   238 				// Un-inline the diffs by removing del or ins
   236 				// Un-inline the diffs by removing del or ins
   239 				$orig_diffs[$o]  = preg_replace( '|<ins>.*?</ins>|', '', $diff );
   237 				$orig_diffs[$o]  = preg_replace( '|<ins>.*?</ins>|', '', $diff );
   240 				$final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff );
   238 				$final_diffs[$f] = preg_replace( '|<del>.*?</del>|', '', $diff );
   241 			}
   239 			}
   242 		}
   240 		}
   243 
   241 
   244 		foreach ( array_keys($orig_rows) as $row ) {
   242 		foreach ( array_keys($orig_rows) as $row ) {
   245 			// Both columns have blanks.  Ignore them.
   243 			// Both columns have blanks. Ignore them.
   246 			if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 )
   244 			if ( $orig_rows[$row] < 0 && $final_rows[$row] < 0 )
   247 				continue;
   245 				continue;
   248 
   246 
   249 			// If we have a word based diff, use it.  Otherwise, use the normal line.
   247 			// If we have a word based diff, use it. Otherwise, use the normal line.
   250 			$orig_line  = isset($orig_diffs[$orig_rows[$row]])
   248 			if ( isset( $orig_diffs[$orig_rows[$row]] ) )
   251 				? $orig_diffs[$orig_rows[$row]]
   249 				$orig_line = $orig_diffs[$orig_rows[$row]];
   252 				: htmlspecialchars($orig[$orig_rows[$row]]);
   250 			elseif ( isset( $orig[$orig_rows[$row]] ) )
   253 			$final_line = isset($final_diffs[$final_rows[$row]])
   251 				$orig_line = htmlspecialchars($orig[$orig_rows[$row]]);
   254 				? $final_diffs[$final_rows[$row]]
   252 			else
   255 				: htmlspecialchars($final[$final_rows[$row]]);
   253 				$orig_line = '';
   256 
   254 
   257 			if ( $orig_rows[$row] < 0 ) { // Orig is blank.  This is really an added row.
   255 			if ( isset( $final_diffs[$final_rows[$row]] ) )
       
   256 				$final_line = $final_diffs[$final_rows[$row]];
       
   257 			elseif ( isset( $final[$final_rows[$row]] ) )
       
   258 				$final_line = htmlspecialchars($final[$final_rows[$row]]);
       
   259 			else
       
   260 				$final_line = '';
       
   261 
       
   262 			if ( $orig_rows[$row] < 0 ) { // Orig is blank. This is really an added row.
   258 				$r .= $this->_added( array($final_line), false );
   263 				$r .= $this->_added( array($final_line), false );
   259 			} elseif ( $final_rows[$row] < 0 ) { // Final is blank.  This is really a deleted row.
   264 			} elseif ( $final_rows[$row] < 0 ) { // Final is blank. This is really a deleted row.
   260 				$r .= $this->_deleted( array($orig_line), false );
   265 				$r .= $this->_deleted( array($orig_line), false );
   261 			} else { // A true changed row.
   266 			} else { // A true changed row.
   262 				$r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "</tr>\n";
   267 				$r .= '<tr>' . $this->deletedLine( $orig_line ) . $this->addedLine( $final_line ) . "</tr>\n";
   263 			}
   268 			}
   264 		}
   269 		}
   280 	 * @param unknown_type $final
   285 	 * @param unknown_type $final
   281 	 * @return unknown
   286 	 * @return unknown
   282 	 */
   287 	 */
   283 	function interleave_changed_lines( $orig, $final ) {
   288 	function interleave_changed_lines( $orig, $final ) {
   284 
   289 
   285 		// Contains all pairwise string comparisons.  Keys are such that this need only be a one dimensional array.
   290 		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
   286 		$matches = array();
   291 		$matches = array();
   287 		foreach ( array_keys($orig) as $o ) {
   292 		foreach ( array_keys($orig) as $o ) {
   288 			foreach ( array_keys($final) as $f ) {
   293 			foreach ( array_keys($final) as $f ) {
   289 				$matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );
   294 				$matches["$o,$f"] = $this->compute_string_distance( $orig[$o], $final[$f] );
   290 			}
   295 			}
   301 
   306 
   302 			// Already have better matches for these guys
   307 			// Already have better matches for these guys
   303 			if ( isset($orig_matches[$o]) && isset($final_matches[$f]) )
   308 			if ( isset($orig_matches[$o]) && isset($final_matches[$f]) )
   304 				continue;
   309 				continue;
   305 
   310 
   306 			// First match for these guys.  Must be best match
   311 			// First match for these guys. Must be best match
   307 			if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {
   312 			if ( !isset($orig_matches[$o]) && !isset($final_matches[$f]) ) {
   308 				$orig_matches[$o] = $f;
   313 				$orig_matches[$o] = $f;
   309 				$final_matches[$f] = $o;
   314 				$final_matches[$f] = $o;
   310 				continue;
   315 				continue;
   311 			}
   316 			}
   321 
   326 
   322 		// We read the text in this order
   327 		// We read the text in this order
   323 		ksort($orig_matches);
   328 		ksort($orig_matches);
   324 		ksort($final_matches);
   329 		ksort($final_matches);
   325 
   330 
   326 
       
   327 		// Stores rows and blanks for each column.
   331 		// Stores rows and blanks for each column.
   328 		$orig_rows = $orig_rows_copy = array_keys($orig_matches);
   332 		$orig_rows = $orig_rows_copy = array_keys($orig_matches);
   329 		$final_rows = array_keys($final_matches);
   333 		$final_rows = array_keys($final_matches);
   330 
   334 
   331 		// Interleaves rows with blanks to keep matches aligned.
   335 		// Interleaves rows with blanks to keep matches aligned.
   334 			$final_pos = array_search($orig_matches[$orig_row], $final_rows, true);
   338 			$final_pos = array_search($orig_matches[$orig_row], $final_rows, true);
   335 			$orig_pos = (int) array_search($orig_row, $orig_rows, true);
   339 			$orig_pos = (int) array_search($orig_row, $orig_rows, true);
   336 
   340 
   337 			if ( false === $final_pos ) { // This orig is paired with a blank final.
   341 			if ( false === $final_pos ) { // This orig is paired with a blank final.
   338 				array_splice( $final_rows, $orig_pos, 0, -1 );
   342 				array_splice( $final_rows, $orig_pos, 0, -1 );
   339 			} elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways.  Pad final with blank rows.
   343 			} elseif ( $final_pos < $orig_pos ) { // This orig's match is up a ways. Pad final with blank rows.
   340 				$diff_pos = $final_pos - $orig_pos;
   344 				$diff_pos = $final_pos - $orig_pos;
   341 				while ( $diff_pos < 0 )
   345 				while ( $diff_pos < 0 )
   342 					array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
   346 					array_splice( $final_rows, $orig_pos, 0, $diff_pos++ );
   343 			} elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways.  Pad orig with blank rows.
   347 			} elseif ( $final_pos > $orig_pos ) { // This orig's match is down a ways. Pad orig with blank rows.
   344 				$diff_pos = $orig_pos - $final_pos;
   348 				$diff_pos = $orig_pos - $final_pos;
   345 				while ( $diff_pos < 0 )
   349 				while ( $diff_pos < 0 )
   346 					array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
   350 					array_splice( $orig_rows, $orig_pos, 0, $diff_pos++ );
   347 			}
   351 			}
   348 		}
   352 		}
   349 
       
   350 
   353 
   351 		// Pad the ends with blank rows if the columns aren't the same length
   354 		// Pad the ends with blank rows if the columns aren't the same length
   352 		$diff_count = count($orig_rows) - count($final_rows);
   355 		$diff_count = count($orig_rows) - count($final_rows);
   353 		if ( $diff_count < 0 ) {
   356 		if ( $diff_count < 0 ) {
   354 			while ( $diff_count < 0 )
   357 			while ( $diff_count < 0 )
   419 		$chars2 = count_chars($string2);
   422 		$chars2 = count_chars($string2);
   420 
   423 
   421 		// L1-norm of difference vector.
   424 		// L1-norm of difference vector.
   422 		$difference = array_sum( array_map( array(&$this, 'difference'), $chars1, $chars2 ) );
   425 		$difference = array_sum( array_map( array(&$this, 'difference'), $chars1, $chars2 ) );
   423 
   426 
   424 		// $string1 has zero length? Odd.  Give huge penalty by not dividing.
   427 		// $string1 has zero length? Odd. Give huge penalty by not dividing.
   425 		if ( !$string1 )
   428 		if ( !$string1 )
   426 			return $difference;
   429 			return $difference;
   427 
   430 
   428 		// Return distance per charcter (of string1)
   431 		// Return distance per charcter (of string1)
   429 		return $difference / strlen($string1);
   432 		return $difference / strlen($string1);
   465 		$words  = str_replace( "\n", $newlineEscape, $words );
   468 		$words  = str_replace( "\n", $newlineEscape, $words );
   466 		return $words;
   469 		return $words;
   467 	}
   470 	}
   468 
   471 
   469 }
   472 }
   470 
       
   471 ?>