wp/wp-includes/class-wp-text-diff-renderer-table.php
changeset 21 48c4eec2b7e6
parent 19 3d72ae0968f4
child 22 8c2e4d02f4ef
equal deleted inserted replaced
20:7b1b88e27a20 21:48c4eec2b7e6
    11  * Table renderer to display the diff lines.
    11  * Table renderer to display the diff lines.
    12  *
    12  *
    13  * @since 2.6.0
    13  * @since 2.6.0
    14  * @uses Text_Diff_Renderer Extends
    14  * @uses Text_Diff_Renderer Extends
    15  */
    15  */
       
    16 #[AllowDynamicProperties]
    16 class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer {
    17 class WP_Text_Diff_Renderer_Table extends Text_Diff_Renderer {
    17 
    18 
    18 	/**
    19 	/**
    19 	 * @see Text_Diff_Renderer::_leading_context_lines
    20 	 * @see Text_Diff_Renderer::_leading_context_lines
    20 	 * @var int
    21 	 * @var int
    26 	 * @see Text_Diff_Renderer::_trailing_context_lines
    27 	 * @see Text_Diff_Renderer::_trailing_context_lines
    27 	 * @var int
    28 	 * @var int
    28 	 * @since 2.6.0
    29 	 * @since 2.6.0
    29 	 */
    30 	 */
    30 	public $_trailing_context_lines = 10000;
    31 	public $_trailing_context_lines = 10000;
       
    32 
       
    33 	/**
       
    34 	 * Title of the item being compared.
       
    35 	 *
       
    36 	 * @since 6.4.0 Declared a previously dynamic property.
       
    37 	 * @var string|null
       
    38 	 */
       
    39 	public $_title;
       
    40 
       
    41 	/**
       
    42 	 * Title for the left column.
       
    43 	 *
       
    44 	 * @since 6.4.0 Declared a previously dynamic property.
       
    45 	 * @var string|null
       
    46 	 */
       
    47 	public $_title_left;
       
    48 
       
    49 	/**
       
    50 	 * Title for the right column.
       
    51 	 *
       
    52 	 * @since 6.4.0 Declared a previously dynamic property.
       
    53 	 * @var string|null
       
    54 	 */
       
    55 	public $_title_right;
    31 
    56 
    32 	/**
    57 	/**
    33 	 * Threshold for when a diff should be saved or omitted.
    58 	 * Threshold for when a diff should be saved or omitted.
    34 	 *
    59 	 *
    35 	 * @var float
    60 	 * @var float
   111 	 *
   136 	 *
   112 	 * @param string $line HTML-escape the value.
   137 	 * @param string $line HTML-escape the value.
   113 	 * @return string
   138 	 * @return string
   114 	 */
   139 	 */
   115 	public function addedLine( $line ) {
   140 	public function addedLine( $line ) {
   116 		return "<td class='diff-addedline'><span aria-hidden='true' class='dashicons dashicons-plus'></span><span class='screen-reader-text'>" . __( 'Added:' ) . " </span>{$line}</td>";
   141 		return "<td class='diff-addedline'><span aria-hidden='true' class='dashicons dashicons-plus'></span><span class='screen-reader-text'>" .
   117 
   142 			/* translators: Hidden accessibility text. */
       
   143 			__( 'Added:' ) .
       
   144 		" </span>{$line}</td>";
   118 	}
   145 	}
   119 
   146 
   120 	/**
   147 	/**
   121 	 * @ignore
   148 	 * @ignore
   122 	 *
   149 	 *
   123 	 * @param string $line HTML-escape the value.
   150 	 * @param string $line HTML-escape the value.
   124 	 * @return string
   151 	 * @return string
   125 	 */
   152 	 */
   126 	public function deletedLine( $line ) {
   153 	public function deletedLine( $line ) {
   127 		return "<td class='diff-deletedline'><span aria-hidden='true' class='dashicons dashicons-minus'></span><span class='screen-reader-text'>" . __( 'Deleted:' ) . " </span>{$line}</td>";
   154 		return "<td class='diff-deletedline'><span aria-hidden='true' class='dashicons dashicons-minus'></span><span class='screen-reader-text'>" .
       
   155 			/* translators: Hidden accessibility text. */
       
   156 			__( 'Deleted:' ) .
       
   157 		" </span>{$line}</td>";
   128 	}
   158 	}
   129 
   159 
   130 	/**
   160 	/**
   131 	 * @ignore
   161 	 * @ignore
   132 	 *
   162 	 *
   133 	 * @param string $line HTML-escape the value.
   163 	 * @param string $line HTML-escape the value.
   134 	 * @return string
   164 	 * @return string
   135 	 */
   165 	 */
   136 	public function contextLine( $line ) {
   166 	public function contextLine( $line ) {
   137 		return "<td class='diff-context'><span class='screen-reader-text'>" . __( 'Unchanged:' ) . " </span>{$line}</td>";
   167 		return "<td class='diff-context'><span class='screen-reader-text'>" .
       
   168 			/* translators: Hidden accessibility text. */
       
   169 			__( 'Unchanged:' ) .
       
   170 		" </span>{$line}</td>";
   138 	}
   171 	}
   139 
   172 
   140 	/**
   173 	/**
   141 	 * @ignore
   174 	 * @ignore
   142 	 *
   175 	 *
   244 	 *
   277 	 *
   245 	 * @param array $orig
   278 	 * @param array $orig
   246 	 * @param array $final
   279 	 * @param array $final
   247 	 * @return string
   280 	 * @return string
   248 	 */
   281 	 */
   249 	public function _changed( $orig, $final ) {
   282 	public function _changed( $orig, $final ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.finalFound
   250 		$r = '';
   283 		$r = '';
   251 
   284 
   252 		/*
   285 		/*
   253 		 * Does the aforementioned additional processing:
   286 		 * Does the aforementioned additional processing:
   254 		 * *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes.
   287 		 * *_matches tell what rows are "the same" in orig and final. Those pairs will be diffed to get word changes.
   266 
   299 
   267 		// Compute word diffs for each matched pair using the inline diff.
   300 		// Compute word diffs for each matched pair using the inline diff.
   268 		foreach ( $orig_matches as $o => $f ) {
   301 		foreach ( $orig_matches as $o => $f ) {
   269 			if ( is_numeric( $o ) && is_numeric( $f ) ) {
   302 			if ( is_numeric( $o ) && is_numeric( $f ) ) {
   270 				$text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) );
   303 				$text_diff = new Text_Diff( 'auto', array( array( $orig[ $o ] ), array( $final[ $f ] ) ) );
   271 				$renderer  = new $this->inline_diff_renderer;
   304 				$renderer  = new $this->inline_diff_renderer();
   272 				$diff      = $renderer->render( $text_diff );
   305 				$diff      = $renderer->render( $text_diff );
   273 
   306 
   274 				// If they're too different, don't include any <ins> or <del>'s.
   307 				// If they're too different, don't include any <ins> or <del>'s.
   275 				if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
   308 				if ( preg_match_all( '!(<ins>.*?</ins>|<del>.*?</del>)!', $diff, $diff_matches ) ) {
   276 					// Length of all text between <ins> or <del>.
   309 					// Length of all text between <ins> or <del>.
   277 					$stripped_matches = strlen( strip_tags( implode( ' ', $diff_matches[0] ) ) );
   310 					$stripped_matches = strlen( strip_tags( implode( ' ', $diff_matches[0] ) ) );
   278 					// Since we count length of text between <ins> or <del> (instead of picking just one),
   311 					/*
   279 					// we double the length of chars not in those tags.
   312 					 * Since we count length of text between <ins> or <del> (instead of picking just one),
       
   313 					 * we double the length of chars not in those tags.
       
   314 					 */
   280 					$stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches;
   315 					$stripped_diff = strlen( strip_tags( $diff ) ) * 2 - $stripped_matches;
   281 					$diff_ratio    = $stripped_matches / $stripped_diff;
   316 					$diff_ratio    = $stripped_matches / $stripped_diff;
   282 					if ( $diff_ratio > $this->_diff_threshold ) {
   317 					if ( $diff_ratio > $this->_diff_threshold ) {
   283 						continue; // Too different. Don't save diffs.
   318 						continue; // Too different. Don't save diffs.
   284 					}
   319 					}
   355 	 *                                blanks to keep matches aligned with side-by-side diff
   390 	 *                                blanks to keep matches aligned with side-by-side diff
   356 	 *                                of `$orig`. A value >= 0 corresponds to index of `$final`.
   391 	 *                                of `$orig`. A value >= 0 corresponds to index of `$final`.
   357 	 *                                Value < 0 indicates a blank row.
   392 	 *                                Value < 0 indicates a blank row.
   358 	 * }
   393 	 * }
   359 	 */
   394 	 */
   360 	public function interleave_changed_lines( $orig, $final ) {
   395 	public function interleave_changed_lines( $orig, $final ) { // phpcs:ignore Universal.NamingConventions.NoReservedKeywordParameterNames.finalFound
   361 
   396 
   362 		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
   397 		// Contains all pairwise string comparisons. Keys are such that this need only be a one dimensional array.
   363 		$matches = array();
   398 		$matches = array();
   364 		foreach ( array_keys( $orig ) as $o ) {
   399 		foreach ( array_keys( $orig ) as $o ) {
   365 			foreach ( array_keys( $final ) as $f ) {
   400 			foreach ( array_keys( $final ) as $f ) {
   404 		// Stores rows and blanks for each column.
   439 		// Stores rows and blanks for each column.
   405 		$orig_rows      = array_keys( $orig_matches );
   440 		$orig_rows      = array_keys( $orig_matches );
   406 		$orig_rows_copy = $orig_rows;
   441 		$orig_rows_copy = $orig_rows;
   407 		$final_rows     = array_keys( $final_matches );
   442 		$final_rows     = array_keys( $final_matches );
   408 
   443 
   409 		// Interleaves rows with blanks to keep matches aligned.
   444 		/*
   410 		// We may end up with some extraneous blank rows, but we'll just ignore them later.
   445 		 * Interleaves rows with blanks to keep matches aligned.
       
   446 		 * We may end up with some extraneous blank rows, but we'll just ignore them later.
       
   447 		 */
   411 		foreach ( $orig_rows_copy as $orig_row ) {
   448 		foreach ( $orig_rows_copy as $orig_row ) {
   412 			$final_pos = array_search( $orig_matches[ $orig_row ], $final_rows, true );
   449 			$final_pos = array_search( $orig_matches[ $orig_row ], $final_rows, true );
   413 			$orig_pos  = (int) array_search( $orig_row, $orig_rows, true );
   450 			$orig_pos  = (int) array_search( $orig_row, $orig_rows, true );
   414 
   451 
   415 			if ( false === $final_pos ) { // This orig is paired with a blank final.
   452 			if ( false === $final_pos ) { // This orig is paired with a blank final.
   495 
   532 
   496 	/**
   533 	/**
   497 	 * Make private properties readable for backward compatibility.
   534 	 * Make private properties readable for backward compatibility.
   498 	 *
   535 	 *
   499 	 * @since 4.0.0
   536 	 * @since 4.0.0
       
   537 	 * @since 6.4.0 Getting a dynamic property is deprecated.
   500 	 *
   538 	 *
   501 	 * @param string $name Property to get.
   539 	 * @param string $name Property to get.
   502 	 * @return mixed Property.
   540 	 * @return mixed A declared property's value, else null.
   503 	 */
   541 	 */
   504 	public function __get( $name ) {
   542 	public function __get( $name ) {
   505 		if ( in_array( $name, $this->compat_fields, true ) ) {
   543 		if ( in_array( $name, $this->compat_fields, true ) ) {
   506 			return $this->$name;
   544 			return $this->$name;
   507 		}
   545 		}
       
   546 
       
   547 		wp_trigger_error(
       
   548 			__METHOD__,
       
   549 			"The property `{$name}` is not declared. Getting a dynamic property is " .
       
   550 			'deprecated since version 6.4.0! Instead, declare the property on the class.',
       
   551 			E_USER_DEPRECATED
       
   552 		);
       
   553 		return null;
   508 	}
   554 	}
   509 
   555 
   510 	/**
   556 	/**
   511 	 * Make private properties settable for backward compatibility.
   557 	 * Make private properties settable for backward compatibility.
   512 	 *
   558 	 *
   513 	 * @since 4.0.0
   559 	 * @since 4.0.0
       
   560 	 * @since 6.4.0 Setting a dynamic property is deprecated.
   514 	 *
   561 	 *
   515 	 * @param string $name  Property to check if set.
   562 	 * @param string $name  Property to check if set.
   516 	 * @param mixed  $value Property value.
   563 	 * @param mixed  $value Property value.
   517 	 * @return mixed Newly-set property.
       
   518 	 */
   564 	 */
   519 	public function __set( $name, $value ) {
   565 	public function __set( $name, $value ) {
   520 		if ( in_array( $name, $this->compat_fields, true ) ) {
   566 		if ( in_array( $name, $this->compat_fields, true ) ) {
   521 			return $this->$name = $value;
   567 			$this->$name = $value;
   522 		}
   568 			return;
       
   569 		}
       
   570 
       
   571 		wp_trigger_error(
       
   572 			__METHOD__,
       
   573 			"The property `{$name}` is not declared. Setting a dynamic property is " .
       
   574 			'deprecated since version 6.4.0! Instead, declare the property on the class.',
       
   575 			E_USER_DEPRECATED
       
   576 		);
   523 	}
   577 	}
   524 
   578 
   525 	/**
   579 	/**
   526 	 * Make private properties checkable for backward compatibility.
   580 	 * Make private properties checkable for backward compatibility.
   527 	 *
   581 	 *
   528 	 * @since 4.0.0
   582 	 * @since 4.0.0
       
   583 	 * @since 6.4.0 Checking a dynamic property is deprecated.
   529 	 *
   584 	 *
   530 	 * @param string $name Property to check if set.
   585 	 * @param string $name Property to check if set.
   531 	 * @return bool Whether the property is set.
   586 	 * @return bool Whether the property is set.
   532 	 */
   587 	 */
   533 	public function __isset( $name ) {
   588 	public function __isset( $name ) {
   534 		if ( in_array( $name, $this->compat_fields, true ) ) {
   589 		if ( in_array( $name, $this->compat_fields, true ) ) {
   535 			return isset( $this->$name );
   590 			return isset( $this->$name );
   536 		}
   591 		}
       
   592 
       
   593 		wp_trigger_error(
       
   594 			__METHOD__,
       
   595 			"The property `{$name}` is not declared. Checking `isset()` on a dynamic property " .
       
   596 			'is deprecated since version 6.4.0! Instead, declare the property on the class.',
       
   597 			E_USER_DEPRECATED
       
   598 		);
       
   599 		return false;
   537 	}
   600 	}
   538 
   601 
   539 	/**
   602 	/**
   540 	 * Make private properties un-settable for backward compatibility.
   603 	 * Make private properties un-settable for backward compatibility.
   541 	 *
   604 	 *
   542 	 * @since 4.0.0
   605 	 * @since 4.0.0
       
   606 	 * @since 6.4.0 Unsetting a dynamic property is deprecated.
   543 	 *
   607 	 *
   544 	 * @param string $name Property to unset.
   608 	 * @param string $name Property to unset.
   545 	 */
   609 	 */
   546 	public function __unset( $name ) {
   610 	public function __unset( $name ) {
   547 		if ( in_array( $name, $this->compat_fields, true ) ) {
   611 		if ( in_array( $name, $this->compat_fields, true ) ) {
   548 			unset( $this->$name );
   612 			unset( $this->$name );
   549 		}
   613 			return;
       
   614 		}
       
   615 
       
   616 		wp_trigger_error(
       
   617 			__METHOD__,
       
   618 			"A property `{$name}` is not declared. Unsetting a dynamic property is " .
       
   619 			'deprecated since version 6.4.0! Instead, declare the property on the class.',
       
   620 			E_USER_DEPRECATED
       
   621 		);
   550 	}
   622 	}
   551 }
   623 }