@wordpress/editor
Version:
Enhanced block editor for WordPress posts.
197 lines (196 loc) • 7.26 kB
JavaScript
// packages/editor/src/components/post-revisions-preview/revisions-code-diff.js
import { diffLines } from "diff";
import { Spinner } from "@wordpress/components";
import { store as coreStore } from "@wordpress/core-data";
import { useSelect } from "@wordpress/data";
import { useMemo } from "@wordpress/element";
import { __, _x } from "@wordpress/i18n";
import { VisuallyHidden } from "@wordpress/ui";
import { store as editorStore } from "../../store/index.mjs";
import { buildRevisionsPageQuery } from "../../store/private-selectors.mjs";
import { unlock } from "../../lock-unlock.mjs";
import { jsx, jsxs } from "react/jsx-runtime";
var MAX_DIFF_EDIT_LENGTH = 1e3;
var DIFF_TIMEOUT = 100;
function splitLines(value) {
const lines = value.split("\n");
if (lines[lines.length - 1] === "") {
lines.pop();
}
return lines;
}
function getCodeDiffRows(previousContent, currentContent, showDiff) {
let parts = [{ value: currentContent }];
if (showDiff) {
parts = diffLines(previousContent, currentContent, {
maxEditLength: MAX_DIFF_EDIT_LENGTH,
timeout: DIFF_TIMEOUT
});
if (!parts) {
parts = [
{ value: previousContent, removed: true },
{ value: currentContent, added: true }
];
}
}
let previousLineNumber = 1;
let currentLineNumber = 1;
return parts.flatMap((part) => {
let status = "unchanged";
if (part.added) {
status = "added";
} else if (part.removed) {
status = "removed";
}
return splitLines(part.value).map((value) => {
const row = {
value,
status,
previousLineNumber: null,
currentLineNumber: null
};
if (status !== "added" && showDiff) {
row.previousLineNumber = previousLineNumber++;
}
if (status !== "removed") {
row.currentLineNumber = currentLineNumber++;
}
return row;
});
});
}
function getCodeDiffDisplayState({
previousRevision,
showDiff,
hasOlderRevisionPage,
hasFinishedPreviousRevision
}) {
const needsPreviousRevision = showDiff && previousRevision === null && hasOlderRevisionPage;
return {
showDiff: showDiff && !(needsPreviousRevision && hasFinishedPreviousRevision),
isPreviousRevisionLoading: needsPreviousRevision && !hasFinishedPreviousRevision
};
}
function ConnectedRevisionsCodeDiff() {
const revisionDiff = useSelect((select) => {
const editorSelectors = select(editorStore);
const coreSelectors = select(coreStore);
const {
getCurrentRevision,
getPreviousRevision,
getRevisionPage,
getRevisionsPerPage,
isShowingRevisionDiff
} = unlock(editorSelectors);
const _previousRevision = getPreviousRevision();
const _showDiff = isShowingRevisionDiff();
const revisionPage = getRevisionPage();
const totalPages = Math.ceil(
editorSelectors.getCurrentPostRevisionsCount() / getRevisionsPerPage()
) || 1;
const hasOlderRevisionPage = revisionPage < totalPages;
let hasFinishedPreviousRevision = true;
if (_showDiff && _previousRevision === null && hasOlderRevisionPage) {
const postType = editorSelectors.getCurrentPostType();
const postId = editorSelectors.getCurrentPostId();
const entityConfig = coreSelectors.getEntityConfig(
"postType",
postType
);
const revisionKey = entityConfig?.revisionKey || "id";
hasFinishedPreviousRevision = coreSelectors.hasFinishedResolution(
"getRevisions",
[
"postType",
postType,
postId,
buildRevisionsPageQuery(revisionKey, revisionPage + 1)
]
);
}
return {
revision: getCurrentRevision(),
previousRevision: _previousRevision,
...getCodeDiffDisplayState({
previousRevision: _previousRevision,
showDiff: _showDiff,
hasOlderRevisionPage,
hasFinishedPreviousRevision
})
};
}, []);
return /* @__PURE__ */ jsx(RevisionsCodeDiff, { ...revisionDiff });
}
function RevisionsCodeDiff({
revision,
previousRevision,
showDiff,
isPreviousRevisionLoading
}) {
const rows = useMemo(() => {
if (!revision || isPreviousRevisionLoading) {
return [];
}
return getCodeDiffRows(
previousRevision?.content?.raw ?? "",
revision.content?.raw ?? "",
showDiff
);
}, [revision, previousRevision, showDiff, isPreviousRevisionLoading]);
if (!revision || isPreviousRevisionLoading) {
return /* @__PURE__ */ jsx("div", { className: "editor-revisions-canvas__loading", children: /* @__PURE__ */ jsx(Spinner, {}) });
}
const label = showDiff ? __("Code changes") : __("Revision code");
return /* @__PURE__ */ jsx(
"div",
{
className: "editor-revisions-code-diff",
role: "region",
"aria-label": label,
tabIndex: 0,
children: rows.length ? /* @__PURE__ */ jsxs("table", { className: "editor-revisions-code-diff__table", children: [
/* @__PURE__ */ jsx(VisuallyHidden, { render: /* @__PURE__ */ jsx("caption", {}), children: label }),
/* @__PURE__ */ jsx(VisuallyHidden, { render: /* @__PURE__ */ jsx("thead", {}), children: /* @__PURE__ */ jsxs("tr", { children: [
showDiff && /* @__PURE__ */ jsx("th", { children: __("Previous line") }),
/* @__PURE__ */ jsx("th", { children: __("Current line") }),
showDiff && /* @__PURE__ */ jsx("th", { children: _x("Change", "noun") }),
/* @__PURE__ */ jsx("th", { children: __("Code") })
] }) }),
/* @__PURE__ */ jsx("tbody", { children: rows.map((row, index) => {
let marker = "";
let statusLabel = __("Unchanged");
if (row.status === "added") {
marker = "+";
statusLabel = __("Added");
} else if (row.status === "removed") {
marker = "−";
statusLabel = __("Removed");
}
return /* @__PURE__ */ jsxs(
"tr",
{
className: `editor-revisions-code-diff__line is-${row.status}`,
children: [
showDiff && /* @__PURE__ */ jsx("td", { className: "editor-revisions-code-diff__line-number is-previous", children: row.previousLineNumber }),
/* @__PURE__ */ jsx("td", { className: "editor-revisions-code-diff__line-number is-current", children: row.currentLineNumber }),
showDiff && /* @__PURE__ */ jsxs("td", { className: "editor-revisions-code-diff__marker", children: [
/* @__PURE__ */ jsx(VisuallyHidden, { children: statusLabel }),
/* @__PURE__ */ jsx("span", { "aria-hidden": "true", children: marker })
] }),
/* @__PURE__ */ jsx("td", { className: "editor-revisions-code-diff__code", children: /* @__PURE__ */ jsx("code", { children: row.value }) })
]
},
index
);
}) })
] }) : /* @__PURE__ */ jsx("p", { className: "editor-revisions-code-diff__empty", children: __("This revision is empty.") })
}
);
}
export {
RevisionsCodeDiff,
ConnectedRevisionsCodeDiff as default,
getCodeDiffDisplayState,
getCodeDiffRows
};
//# sourceMappingURL=revisions-code-diff.mjs.map