UNPKG

@wordpress/editor

Version:
8 lines (7 loc) 13.1 kB
{ "version": 3, "sources": ["../../../src/components/post-revisions-preview/revisions-code-diff.js"], "sourcesContent": ["import { diffLines } from 'diff';\nimport { Spinner } from '@wordpress/components';\nimport { store as coreStore } from '@wordpress/core-data';\nimport { useSelect } from '@wordpress/data';\nimport { useMemo } from '@wordpress/element';\nimport { __, _x } from '@wordpress/i18n';\nimport { VisuallyHidden } from '@wordpress/ui';\nimport { store as editorStore } from '../../store';\nimport { buildRevisionsPageQuery } from '../../store/private-selectors';\nimport { unlock } from '../../lock-unlock';\n\nconst MAX_DIFF_EDIT_LENGTH = 1000;\nconst DIFF_TIMEOUT = 100;\n\n/**\n * Diff parts often end in a newline. Remove the trailing empty item so it is\n * not rendered as another source line.\n *\n * @param {string} value Diff part value.\n * @return {string[]} Lines in the diff part.\n */\nfunction splitLines( value ) {\n\tconst lines = value.split( '\\n' );\n\tif ( lines[ lines.length - 1 ] === '' ) {\n\t\tlines.pop();\n\t}\n\treturn lines;\n}\n\n/**\n * Creates the rows shown in the code diff and adds line numbers for both\n * revisions.\n *\n * @param {string} previousContent Previous revision content.\n * @param {string} currentContent Selected revision content.\n * @param {boolean} showDiff Whether changes should be highlighted.\n * @return {Array<Object>} Code-diff rows.\n */\nexport function getCodeDiffRows( previousContent, currentContent, showDiff ) {\n\tlet parts = [ { value: currentContent } ];\n\tif ( showDiff ) {\n\t\tparts = diffLines( previousContent, currentContent, {\n\t\t\tmaxEditLength: MAX_DIFF_EDIT_LENGTH,\n\t\t\ttimeout: DIFF_TIMEOUT,\n\t\t} );\n\n\t\t// Line diffing can be quadratic for unrelated revisions. If it exceeds\n\t\t// either limit, mark every old and new line instead.\n\t\tif ( ! parts ) {\n\t\t\tparts = [\n\t\t\t\t{ value: previousContent, removed: true },\n\t\t\t\t{ value: currentContent, added: true },\n\t\t\t];\n\t\t}\n\t}\n\tlet previousLineNumber = 1;\n\tlet currentLineNumber = 1;\n\n\treturn parts.flatMap( ( part ) => {\n\t\tlet status = 'unchanged';\n\t\tif ( part.added ) {\n\t\t\tstatus = 'added';\n\t\t} else if ( part.removed ) {\n\t\t\tstatus = 'removed';\n\t\t}\n\n\t\treturn splitLines( part.value ).map( ( value ) => {\n\t\t\tconst row = {\n\t\t\t\tvalue,\n\t\t\t\tstatus,\n\t\t\t\tpreviousLineNumber: null,\n\t\t\t\tcurrentLineNumber: null,\n\t\t\t};\n\n\t\t\tif ( status !== 'added' && showDiff ) {\n\t\t\t\trow.previousLineNumber = previousLineNumber++;\n\t\t\t}\n\t\t\tif ( status !== 'removed' ) {\n\t\t\t\trow.currentLineNumber = currentLineNumber++;\n\t\t\t}\n\n\t\t\treturn row;\n\t\t} );\n\t} );\n}\n\n/**\n * Determines whether the code diff should wait for an older revision or fall\n * back to showing the selected revision without a diff.\n *\n * @param {Object} options Display options.\n * @param {Object|null} options.previousRevision Previous revision.\n * @param {boolean} options.showDiff Whether changes should be highlighted.\n * @param {boolean} options.hasOlderRevisionPage Whether another revisions page exists.\n * @param {boolean} options.hasFinishedPreviousRevision Whether the previous revision request finished.\n * @return {Object} Code-diff display state.\n */\nexport function getCodeDiffDisplayState( {\n\tpreviousRevision,\n\tshowDiff,\n\thasOlderRevisionPage,\n\thasFinishedPreviousRevision,\n} ) {\n\tconst needsPreviousRevision =\n\t\tshowDiff && previousRevision === null && hasOlderRevisionPage;\n\n\treturn {\n\t\tshowDiff:\n\t\t\tshowDiff &&\n\t\t\t! ( needsPreviousRevision && hasFinishedPreviousRevision ),\n\t\tisPreviousRevisionLoading:\n\t\t\tneedsPreviousRevision && ! hasFinishedPreviousRevision,\n\t};\n}\n\nexport default function ConnectedRevisionsCodeDiff() {\n\tconst revisionDiff = useSelect( ( select ) => {\n\t\tconst editorSelectors = select( editorStore );\n\t\tconst coreSelectors = select( coreStore );\n\t\tconst {\n\t\t\tgetCurrentRevision,\n\t\t\tgetPreviousRevision,\n\t\t\tgetRevisionPage,\n\t\t\tgetRevisionsPerPage,\n\t\t\tisShowingRevisionDiff,\n\t\t} = unlock( editorSelectors );\n\t\tconst _previousRevision = getPreviousRevision();\n\t\tconst _showDiff = isShowingRevisionDiff();\n\t\tconst revisionPage = getRevisionPage();\n\t\tconst totalPages =\n\t\t\tMath.ceil(\n\t\t\t\teditorSelectors.getCurrentPostRevisionsCount() /\n\t\t\t\t\tgetRevisionsPerPage()\n\t\t\t) || 1;\n\t\tconst hasOlderRevisionPage = revisionPage < totalPages;\n\t\tlet hasFinishedPreviousRevision = true;\n\n\t\tif ( _showDiff && _previousRevision === null && hasOlderRevisionPage ) {\n\t\t\tconst postType = editorSelectors.getCurrentPostType();\n\t\t\tconst postId = editorSelectors.getCurrentPostId();\n\t\t\tconst entityConfig = coreSelectors.getEntityConfig(\n\t\t\t\t'postType',\n\t\t\t\tpostType\n\t\t\t);\n\t\t\tconst revisionKey = entityConfig?.revisionKey || 'id';\n\n\t\t\thasFinishedPreviousRevision = coreSelectors.hasFinishedResolution(\n\t\t\t\t'getRevisions',\n\t\t\t\t[\n\t\t\t\t\t'postType',\n\t\t\t\t\tpostType,\n\t\t\t\t\tpostId,\n\t\t\t\t\tbuildRevisionsPageQuery( revisionKey, revisionPage + 1 ),\n\t\t\t\t]\n\t\t\t);\n\t\t}\n\n\t\treturn {\n\t\t\trevision: getCurrentRevision(),\n\t\t\tpreviousRevision: _previousRevision,\n\t\t\t...getCodeDiffDisplayState( {\n\t\t\t\tpreviousRevision: _previousRevision,\n\t\t\t\tshowDiff: _showDiff,\n\t\t\t\thasOlderRevisionPage,\n\t\t\t\thasFinishedPreviousRevision,\n\t\t\t} ),\n\t\t};\n\t}, [] );\n\n\treturn <RevisionsCodeDiff { ...revisionDiff } />;\n}\n\n/**\n * Shows the selected revision's raw block markup as a read-only diff.\n *\n * @param {Object} props Component props.\n * @param {Object} props.revision Selected revision.\n * @param {Object|null} props.previousRevision Previous revision.\n * @param {boolean} props.showDiff Whether to show changes.\n * @param {boolean} props.isPreviousRevisionLoading Whether the previous revision is loading.\n * @return {React.JSX.Element} The revision code diff.\n */\nexport function RevisionsCodeDiff( {\n\trevision,\n\tpreviousRevision,\n\tshowDiff,\n\tisPreviousRevisionLoading,\n} ) {\n\tconst rows = useMemo( () => {\n\t\tif ( ! revision || isPreviousRevisionLoading ) {\n\t\t\treturn [];\n\t\t}\n\n\t\treturn getCodeDiffRows(\n\t\t\tpreviousRevision?.content?.raw ?? '',\n\t\t\trevision.content?.raw ?? '',\n\t\t\tshowDiff\n\t\t);\n\t}, [ revision, previousRevision, showDiff, isPreviousRevisionLoading ] );\n\n\tif ( ! revision || isPreviousRevisionLoading ) {\n\t\treturn (\n\t\t\t<div className=\"editor-revisions-canvas__loading\">\n\t\t\t\t<Spinner />\n\t\t\t</div>\n\t\t);\n\t}\n\n\tconst label = showDiff ? __( 'Code changes' ) : __( 'Revision code' );\n\n\treturn (\n\t\t<div\n\t\t\tclassName=\"editor-revisions-code-diff\"\n\t\t\trole=\"region\"\n\t\t\taria-label={ label }\n\t\t\ttabIndex={ 0 }\n\t\t>\n\t\t\t{ rows.length ? (\n\t\t\t\t<table className=\"editor-revisions-code-diff__table\">\n\t\t\t\t\t<VisuallyHidden render={ <caption /> }>\n\t\t\t\t\t\t{ label }\n\t\t\t\t\t</VisuallyHidden>\n\t\t\t\t\t<VisuallyHidden render={ <thead /> }>\n\t\t\t\t\t\t<tr>\n\t\t\t\t\t\t\t{ showDiff && <th>{ __( 'Previous line' ) }</th> }\n\t\t\t\t\t\t\t<th>{ __( 'Current line' ) }</th>\n\t\t\t\t\t\t\t{ showDiff && <th>{ _x( 'Change', 'noun' ) }</th> }\n\t\t\t\t\t\t\t<th>{ __( 'Code' ) }</th>\n\t\t\t\t\t\t</tr>\n\t\t\t\t\t</VisuallyHidden>\n\t\t\t\t\t<tbody>\n\t\t\t\t\t\t{ rows.map( ( row, index ) => {\n\t\t\t\t\t\t\tlet marker = '';\n\t\t\t\t\t\t\tlet statusLabel = __( 'Unchanged' );\n\t\t\t\t\t\t\tif ( row.status === 'added' ) {\n\t\t\t\t\t\t\t\tmarker = '+';\n\t\t\t\t\t\t\t\tstatusLabel = __( 'Added' );\n\t\t\t\t\t\t\t} else if ( row.status === 'removed' ) {\n\t\t\t\t\t\t\t\tmarker = '−';\n\t\t\t\t\t\t\t\tstatusLabel = __( 'Removed' );\n\t\t\t\t\t\t\t}\n\n\t\t\t\t\t\t\treturn (\n\t\t\t\t\t\t\t\t<tr\n\t\t\t\t\t\t\t\t\tkey={ index }\n\t\t\t\t\t\t\t\t\tclassName={ `editor-revisions-code-diff__line is-${ row.status }` }\n\t\t\t\t\t\t\t\t>\n\t\t\t\t\t\t\t\t\t{ showDiff && (\n\t\t\t\t\t\t\t\t\t\t<td className=\"editor-revisions-code-diff__line-number is-previous\">\n\t\t\t\t\t\t\t\t\t\t\t{ row.previousLineNumber }\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t\t<td className=\"editor-revisions-code-diff__line-number is-current\">\n\t\t\t\t\t\t\t\t\t\t{ row.currentLineNumber }\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t{ showDiff && (\n\t\t\t\t\t\t\t\t\t\t<td className=\"editor-revisions-code-diff__marker\">\n\t\t\t\t\t\t\t\t\t\t\t<VisuallyHidden>\n\t\t\t\t\t\t\t\t\t\t\t\t{ statusLabel }\n\t\t\t\t\t\t\t\t\t\t\t</VisuallyHidden>\n\t\t\t\t\t\t\t\t\t\t\t<span aria-hidden=\"true\">\n\t\t\t\t\t\t\t\t\t\t\t\t{ marker }\n\t\t\t\t\t\t\t\t\t\t\t</span>\n\t\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t\t) }\n\t\t\t\t\t\t\t\t\t<td className=\"editor-revisions-code-diff__code\">\n\t\t\t\t\t\t\t\t\t\t<code>{ row.value }</code>\n\t\t\t\t\t\t\t\t\t</td>\n\t\t\t\t\t\t\t\t</tr>\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t} ) }\n\t\t\t\t\t</tbody>\n\t\t\t\t</table>\n\t\t\t) : (\n\t\t\t\t<p className=\"editor-revisions-code-diff__empty\">\n\t\t\t\t\t{ __( 'This revision is empty.' ) }\n\t\t\t\t</p>\n\t\t\t) }\n\t\t</div>\n\t);\n}\n"], "mappings": "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", "names": [] }