wp/wp-includes/class-wp-text-diff-renderer-table.php
changeset 16 a86126ab1dd4
parent 9 177826044cd9
child 18 be944660c56a
equal deleted inserted replaced
15:3d4e9c994f10 16:a86126ab1dd4
    98 	}
    98 	}
    99 
    99 
   100 	/**
   100 	/**
   101 	 * @ignore
   101 	 * @ignore
   102 	 *
   102 	 *
   103 	 * @param array $lines
   103 	 * @param array  $lines
   104 	 * @param string $prefix
   104 	 * @param string $prefix
   105 	 */
   105 	 */
   106 	public function _lines( $lines, $prefix = ' ' ) {
   106 	public function _lines( $lines, $prefix = ' ' ) {
   107 	}
   107 	}
   108 
   108 
   111 	 *
   111 	 *
   112 	 * @param string $line HTML-escape the value.
   112 	 * @param string $line HTML-escape the value.
   113 	 * @return string
   113 	 * @return string
   114 	 */
   114 	 */
   115 	public function addedLine( $line ) {
   115 	public function addedLine( $line ) {
   116 		return "<td class='diff-addedline'>{$line}</td>";
   116 		return "<td class='diff-addedline'><span aria-hidden='true' class='dashicons dashicons-plus'></span><span class='screen-reader-text'>" . __( 'Added:' ) . " </span>{$line}</td>";
   117 
   117 
   118 	}
   118 	}
   119 
   119 
   120 	/**
   120 	/**
   121 	 * @ignore
   121 	 * @ignore
   122 	 *
   122 	 *
   123 	 * @param string $line HTML-escape the value.
   123 	 * @param string $line HTML-escape the value.
   124 	 * @return string
   124 	 * @return string
   125 	 */
   125 	 */
   126 	public function deletedLine( $line ) {
   126 	public function deletedLine( $line ) {
   127 		return "<td class='diff-deletedline'>{$line}</td>";
   127 		return "<td class='diff-deletedline'><span aria-hidden='true' class='dashicons dashicons-minus'></span><span class='screen-reader-text'>" . __( 'Deleted:' ) . " </span>{$line}</td>";
   128 	}
   128 	}
   129 
   129 
   130 	/**
   130 	/**
   131 	 * @ignore
   131 	 * @ignore
   132 	 *
   132 	 *
   133 	 * @param string $line HTML-escape the value.
   133 	 * @param string $line HTML-escape the value.
   134 	 * @return string
   134 	 * @return string
   135 	 */
   135 	 */
   136 	public function contextLine( $line ) {
   136 	public function contextLine( $line ) {
   137 		return "<td class='diff-context'>{$line}</td>";
   137 		return "<td class='diff-context'><span class='screen-reader-text'>" . __( 'Unchanged:' ) . " </span>{$line}</td>";
   138 	}
   138 	}
   139 
   139 
   140 	/**
   140 	/**
   141 	 * @ignore
   141 	 * @ignore
   142 	 *
   142 	 *
   148 
   148 
   149 	/**
   149 	/**
   150 	 * @ignore
   150 	 * @ignore
   151 	 *
   151 	 *
   152 	 * @param array $lines
   152 	 * @param array $lines
   153 	 * @param bool $encode
   153 	 * @param bool  $encode
   154 	 * @return string
   154 	 * @return string
   155 	 */
   155 	 */
   156 	public function _added( $lines, $encode = true ) {
   156 	public function _added( $lines, $encode = true ) {
   157 		$r = '';
   157 		$r = '';
   158 		foreach ( $lines as $line ) {
   158 		foreach ( $lines as $line ) {
   166 				 * htmlspecialchars. Use this filter to remove or change the processing. Passes a context
   166 				 * htmlspecialchars. Use this filter to remove or change the processing. Passes a context
   167 				 * indicating if the line is added, deleted or unchanged.
   167 				 * indicating if the line is added, deleted or unchanged.
   168 				 *
   168 				 *
   169 				 * @since 4.1.0
   169 				 * @since 4.1.0
   170 				 *
   170 				 *
   171 				 * @param String $processed_line The processed diffed line.
   171 				 * @param string $processed_line The processed diffed line.
   172 				 * @param String $line           The unprocessed diffed line.
   172 				 * @param string $line           The unprocessed diffed line.
   173 				 * @param string null            The line context. Values are 'added', 'deleted' or 'unchanged'.
   173 				 * @param string $context        The line context. Values are 'added', 'deleted' or 'unchanged'.
   174 				 */
   174 				 */
   175 				$line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'added' );
   175 				$line = apply_filters( 'process_text_diff_html', $processed_line, $line, 'added' );
   176 			}
   176 			}
   177 
   177 
   178 			if ( $this->_show_split_view ) {
   178 			if ( $this->_show_split_view ) {
   186 
   186 
   187 	/**
   187 	/**
   188 	 * @ignore
   188 	 * @ignore
   189 	 *
   189 	 *
   190 	 * @param array $lines
   190 	 * @param array $lines
   191 	 * @param bool $encode
   191 	 * @param bool  $encode
   192 	 * @return string
   192 	 * @return string
   193 	 */
   193 	 */
   194 	public function _deleted( $lines, $encode = true ) {
   194 	public function _deleted( $lines, $encode = true ) {
   195 		$r = '';
   195 		$r = '';
   196 		foreach ( $lines as $line ) {
   196 		foreach ( $lines as $line ) {
   211 
   211 
   212 	/**
   212 	/**
   213 	 * @ignore
   213 	 * @ignore
   214 	 *
   214 	 *
   215 	 * @param array $lines
   215 	 * @param array $lines
   216 	 * @param bool $encode
   216 	 * @param bool  $encode
   217 	 * @return string
   217 	 * @return string
   218 	 */
   218 	 */
   219 	public function _context( $lines, $encode = true ) {
   219 	public function _context( $lines, $encode = true ) {
   220 		$r = '';
   220 		$r = '';
   221 		foreach ( $lines as $line ) {
   221 		foreach ( $lines as $line ) {
   247 	 * @return string
   247 	 * @return string
   248 	 */
   248 	 */
   249 	public function _changed( $orig, $final ) {
   249 	public function _changed( $orig, $final ) {
   250 		$r = '';
   250 		$r = '';
   251 
   251 
   252 		// Does the aforementioned additional processing
   252 		/*
   253 		// *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes
   253 		 * Does the aforementioned additional processing:
   254 		//	match is numeric: an index in other column
   254 		 * *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes.
   255 		//	match is 'X': no match. It is a new row
   255 		 * - match is numeric: an index in other column.
   256 		// *_rows are column vectors for the orig column and the final column.
   256 		 * - match is 'X': no match. It is a new row.
   257 		//	row >= 0: an indix of the $orig or $final array
   257 		 * *_rows are column vectors for the orig column and the final column.
   258 		//	row  < 0: a blank row for that column
   258 		 * - row >= 0: an indix of the $orig or $final array.
       
   259 		 * - row < 0: a blank row for that column.
       
   260 		 */
   259 		list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
   261 		list($orig_matches, $final_matches, $orig_rows, $final_rows) = $this->interleave_changed_lines( $orig, $final );
   260 
   262 
   261 		// These will hold the word changes as determined by an inline diff
   263 		// These will hold the word changes as determined by an inline diff.
   262 		$orig_diffs  = array();
   264 		$orig_diffs  = array();
   263 		$final_diffs = array();
   265 		$final_diffs = array();
   264 
   266 
   265 		// Compute word diffs for each matched pair using the inline diff
   267 		// Compute word diffs for each matched pair using the inline diff.
   266 		foreach ( $orig_matches as $o => $f ) {
   268 		foreach ( $orig_matches as $o => $f ) {
   267 			if ( is_numeric( $o ) && is_numeric( $f ) ) {
   269 			if ( is_numeric( $o ) && is_numeric( $f ) ) {
   268 				$text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) );
   270 				$text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) );
   269 				$renderer  = new $this->inline_diff_renderer;
   271 				$renderer  = new $this->inline_diff_renderer;
   270 				$diff      = $renderer->render( $text_diff );
   272 				$diff      = $renderer->render( $text_diff );
   271 
   273 
   272 				// If they're too different, don't include any <ins> or <dels>
   274 				// If they're too different, don't include any <ins> or <del>'s.
   273 				if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
   275 				if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
   274 					// length of all text between <ins> or <del>
   276 					// Length of all text between <ins> or <del>.
   275 					$stripped_matches = strlen( strip_tags( join( ' ', $diff_matches[0] ) ) );
   277 					$stripped_matches = strlen( strip_tags( join( ' ', $diff_matches[0] ) ) );
   276 					// since we count lengith of text between <ins> or <del> (instead of picking just one),
   278 					// Since we count length of text between <ins> or <del> (instead of picking just one),
   277 					//	we double the length of chars not in those tags.
   279 					// we double the length of chars not in those tags.
   278 					$stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches;
   280 					$stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches;
   279 					$diff_ratio    = $stripped_matches / $stripped_diff;
   281 					$diff_ratio    = $stripped_matches / $stripped_diff;
   280 					if ( $diff_ratio > $this->_diff_threshold ) {
   282 					if ( $diff_ratio > $this->_diff_threshold ) {
   281 						continue; // Too different. Don't save diffs.
   283 						continue; // Too different. Don't save diffs.
   282 					}
   284 					}
   283 				}
   285 				}
   284 
   286 
   285 				// Un-inline the diffs by removing del or ins
   287 				// Un-inline the diffs by removing <del> or <ins>.
   286 				$orig_diffs[ $o ]  = preg_replace( '|<ins>.*?</ins>|', '', $diff );
   288 				$orig_diffs[ $o ]  = preg_replace( '|<ins>.*?</ins>|', '', $diff );
   287 				$final_diffs[ $f ] = preg_replace( '|<del>.*?</del>|', '', $diff );
   289 				$final_diffs[ $f ] = preg_replace( '|<del>.*?</del>|', '', $diff );
   288 			}
   290 			}
   289 		}
   291 		}
   290 
   292 
   333 	 * @since 2.6.0
   335 	 * @since 2.6.0
   334 	 *
   336 	 *
   335 	 * @param array $orig  Lines of the original version of the text.
   337 	 * @param array $orig  Lines of the original version of the text.
   336 	 * @param array $final Lines of the final version of the text.
   338 	 * @param array $final Lines of the final version of the text.
   337 	 * @return array {
   339 	 * @return array {
   338 	 *    Array containing results of comparing the original text to the final text.
   340 	 *     Array containing results of comparing the original text to the final text.
   339 	 *
   341 	 *
   340 	 *    @type array $orig_matches  Associative array of original matches. Index == row
   342 	 *     @type array $orig_matches  Associative array of original matches. Index == row
   341 	 *                               number of `$orig`, value == corresponding row number
   343 	 *                                number of `$orig`, value == corresponding row number
   342 	 *                               of that same line in `$final` or 'x' if there is no
   344 	 *                                of that same line in `$final` or 'x' if there is no
   343 	 *                               corresponding row (indicating it is a deleted line).
   345 	 *                                corresponding row (indicating it is a deleted line).
   344 	 *    @type array $final_matches Associative array of final matches. Index == row
   346 	 *     @type array $final_matches Associative array of final matches. Index == row
   345 	 *                               number of `$final`, value == corresponding row number
   347 	 *                                number of `$final`, value == corresponding row number
   346 	 *                               of that same line in `$orig` or 'x' if there is no
   348 	 *                                of that same line in `$orig` or 'x' if there is no
   347 	 *                               corresponding row (indicating it is a new line).
   349 	 *                                corresponding row (indicating it is a new line).
   348 	 *    @type array $orig_rows     Associative array of interleaved rows of `$orig` with
   350 	 *     @type array $orig_rows     Associative array of interleaved rows of `$orig` with
   349 	 *                               blanks to keep matches aligned with side-by-side diff
   351 	 *                                blanks to keep matches aligned with side-by-side diff
   350 	 *                               of `$final`. A value >= 0 corresponds to index of `$orig`.
   352 	 *                                of `$final`. A value >= 0 corresponds to index of `$orig`.
   351 	 *                               Value < 0 indicates a blank row.
   353 	 *                                Value < 0 indicates a blank row.
   352 	 *    @type array $final_rows    Associative array of interleaved rows of `$final` with
   354 	 *     @type array $final_rows    Associative array of interleaved rows of `$final` with
   353 	 *                               blanks to keep matches aligned with side-by-side diff
   355 	 *                                blanks to keep matches aligned with side-by-side diff
   354 	 *                               of `$orig`. A value >= 0 corresponds to index of `$final`.
   356 	 *                                of `$orig`. A value >= 0 corresponds to index of `$final`.
   355 	 *                               Value < 0 indicates a blank row.
   357 	 *                                Value < 0 indicates a blank row.
   356 	 * }
   358 	 * }
   357 	 */
   359 	 */
   358 	public function interleave_changed_lines( $orig, $final ) {
   360 	public function interleave_changed_lines( $orig, $final ) {
   359 
   361 
   360 		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
   362 		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
   372 		foreach ( $matches as $keys => $difference ) {
   374 		foreach ( $matches as $keys => $difference ) {
   373 			list($o, $f) = explode( ',', $keys );
   375 			list($o, $f) = explode( ',', $keys );
   374 			$o           = (int) $o;
   376 			$o           = (int) $o;
   375 			$f           = (int) $f;
   377 			$f           = (int) $f;
   376 
   378 
   377 			// Already have better matches for these guys
   379 			// Already have better matches for these guys.
   378 			if ( isset( $orig_matches[ $o ] ) && isset( $final_matches[ $f ] ) ) {
   380 			if ( isset( $orig_matches[ $o ] ) && isset( $final_matches[ $f ] ) ) {
   379 				continue;
   381 				continue;
   380 			}
   382 			}
   381 
   383 
   382 			// First match for these guys. Must be best match
   384 			// First match for these guys. Must be best match.
   383 			if ( ! isset( $orig_matches[ $o ] ) && ! isset( $final_matches[ $f ] ) ) {
   385 			if ( ! isset( $orig_matches[ $o ] ) && ! isset( $final_matches[ $f ] ) ) {
   384 				$orig_matches[ $o ]  = $f;
   386 				$orig_matches[ $o ]  = $f;
   385 				$final_matches[ $f ] = $o;
   387 				$final_matches[ $f ] = $o;
   386 				continue;
   388 				continue;
   387 			}
   389 			}
   388 
   390 
   389 			// Best match of this final is already taken?  Must mean this final is a new row.
   391 			// Best match of this final is already taken? Must mean this final is a new row.
   390 			if ( isset( $orig_matches[ $o ] ) ) {
   392 			if ( isset( $orig_matches[ $o ] ) ) {
   391 				$final_matches[ $f ] = 'x';
   393 				$final_matches[ $f ] = 'x';
   392 			} elseif ( isset( $final_matches[ $f ] ) ) {
   394 			} elseif ( isset( $final_matches[ $f ] ) ) {
   393 				// Best match of this orig is already taken?  Must mean this orig is a deleted row.
   395 				// Best match of this orig is already taken? Must mean this orig is a deleted row.
   394 				$orig_matches[ $o ] = 'x';
   396 				$orig_matches[ $o ] = 'x';
   395 			}
   397 			}
   396 		}
   398 		}
   397 
   399 
   398 		// We read the text in this order
   400 		// We read the text in this order.
   399 		ksort( $orig_matches );
   401 		ksort( $orig_matches );
   400 		ksort( $final_matches );
   402 		ksort( $final_matches );
   401 
   403 
   402 		// Stores rows and blanks for each column.
   404 		// Stores rows and blanks for each column.
   403 		$orig_rows  = $orig_rows_copy = array_keys( $orig_matches );
   405 		$orig_rows      = array_keys( $orig_matches );
   404 		$final_rows = array_keys( $final_matches );
   406 		$orig_rows_copy = $orig_rows;
       
   407 		$final_rows     = array_keys( $final_matches );
   405 
   408 
   406 		// Interleaves rows with blanks to keep matches aligned.
   409 		// Interleaves rows with blanks to keep matches aligned.
   407 		// We may end up with some extraneous blank rows, but we'll just ignore them later.
   410 		// We may end up with some extraneous blank rows, but we'll just ignore them later.
   408 		foreach ( $orig_rows_copy as $orig_row ) {
   411 		foreach ( $orig_rows_copy as $orig_row ) {
   409 			$final_pos = array_search( $orig_matches[ $orig_row ], $final_rows, true );
   412 			$final_pos = array_search( $orig_matches[ $orig_row ], $final_rows, true );
   418 				$diff_array = range( -1, $orig_pos - $final_pos );
   421 				$diff_array = range( -1, $orig_pos - $final_pos );
   419 				array_splice( $orig_rows, $orig_pos, 0, $diff_array );
   422 				array_splice( $orig_rows, $orig_pos, 0, $diff_array );
   420 			}
   423 			}
   421 		}
   424 		}
   422 
   425 
   423 		// Pad the ends with blank rows if the columns aren't the same length
   426 		// Pad the ends with blank rows if the columns aren't the same length.
   424 		$diff_count = count( $orig_rows ) - count( $final_rows );
   427 		$diff_count = count( $orig_rows ) - count( $final_rows );
   425 		if ( $diff_count < 0 ) {
   428 		if ( $diff_count < 0 ) {
   426 			while ( $diff_count < 0 ) {
   429 			while ( $diff_count < 0 ) {
   427 				array_push( $orig_rows, $diff_count++ );
   430 				array_push( $orig_rows, $diff_count++ );
   428 			}
   431 			}
   497 	 *
   500 	 *
   498 	 * @param string $name Property to get.
   501 	 * @param string $name Property to get.
   499 	 * @return mixed Property.
   502 	 * @return mixed Property.
   500 	 */
   503 	 */
   501 	public function __get( $name ) {
   504 	public function __get( $name ) {
   502 		if ( in_array( $name, $this->compat_fields ) ) {
   505 		if ( in_array( $name, $this->compat_fields, true ) ) {
   503 			return $this->$name;
   506 			return $this->$name;
   504 		}
   507 		}
   505 	}
   508 	}
   506 
   509 
   507 	/**
   510 	/**
   512 	 * @param string $name  Property to check if set.
   515 	 * @param string $name  Property to check if set.
   513 	 * @param mixed  $value Property value.
   516 	 * @param mixed  $value Property value.
   514 	 * @return mixed Newly-set property.
   517 	 * @return mixed Newly-set property.
   515 	 */
   518 	 */
   516 	public function __set( $name, $value ) {
   519 	public function __set( $name, $value ) {
   517 		if ( in_array( $name, $this->compat_fields ) ) {
   520 		if ( in_array( $name, $this->compat_fields, true ) ) {
   518 			return $this->$name = $value;
   521 			return $this->$name = $value;
   519 		}
   522 		}
   520 	}
   523 	}
   521 
   524 
   522 	/**
   525 	/**
   526 	 *
   529 	 *
   527 	 * @param string $name Property to check if set.
   530 	 * @param string $name Property to check if set.
   528 	 * @return bool Whether the property is set.
   531 	 * @return bool Whether the property is set.
   529 	 */
   532 	 */
   530 	public function __isset( $name ) {
   533 	public function __isset( $name ) {
   531 		if ( in_array( $name, $this->compat_fields ) ) {
   534 		if ( in_array( $name, $this->compat_fields, true ) ) {
   532 			return isset( $this->$name );
   535 			return isset( $this->$name );
   533 		}
   536 		}
   534 	}
   537 	}
   535 
   538 
   536 	/**
   539 	/**
   539 	 * @since 4.0.0
   542 	 * @since 4.0.0
   540 	 *
   543 	 *
   541 	 * @param string $name Property to unset.
   544 	 * @param string $name Property to unset.
   542 	 */
   545 	 */
   543 	public function __unset( $name ) {
   546 	public function __unset( $name ) {
   544 		if ( in_array( $name, $this->compat_fields ) ) {
   547 		if ( in_array( $name, $this->compat_fields, true ) ) {
   545 			unset( $this->$name );
   548 			unset( $this->$name );
   546 		}
   549 		}
   547 	}
   550 	}
   548 }
   551 }