Ghost/ghost/admin/app/components/modal-post-history.js
Fabien "egg" O'Carroll 0ef05d4bed Added initial version of post revision diffing
We want the diff to be based on what the editor looks like, so we render two
hidden koenig instances and diff the html output, as opposed to using lexical
to render the "frontend" HTML. We also have some weirdness with the last
revision being the same content as the current state of the post. We can look
to fix that at the storage or API level in future
2023-04-18 14:58:22 +01:00

88 lines
2.3 KiB
JavaScript

import ModalComponent from 'ghost-admin/components/modal-base';
import diff from 'node-htmldiff';
function checkFinishedRendering(element, done) {
let last = element.innerHTML;
function check() {
let html = element.innerHTML;
if (html === last) {
done();
} else {
last = html;
setTimeout(check, 50);
}
}
setTimeout(check, 50);
}
export default ModalComponent.extend({
diffHtml: null,
init() {
this._super(...arguments);
this.post = this.model;
},
didInsertElement() {
this._super(...arguments);
let previous = document.querySelector('.gh-post-history-hidden-lexical.previous');
let current = document.querySelector('.gh-post-history-hidden-lexical.current');
let previousDone = false;
let currentDone = false;
let updateIfBothDone = () => {
if (previousDone && currentDone) {
this.set('diffHtml', diff(previous.innerHTML, current.innerHTML));
}
};
checkFinishedRendering(previous, () => {
previous.querySelectorAll('[contenteditable]').forEach((el) => {
el.setAttribute('contenteditable', false);
});
previousDone = true;
updateIfBothDone();
});
checkFinishedRendering(current, () => {
current.querySelectorAll('[contenteditable]').forEach((el) => {
el.setAttribute('contenteditable', false);
});
currentDone = true;
updateIfBothDone();
});
},
get selectedRevision() {
let revisions = this.post.get('postRevisions').toArray();
// Revisions are in chronological order, and the last revision is the
// the current post, so the second to last is the previous revision
return revisions[revisions.length - 2];
},
get previousLexical() {
return this.selectedRevision.get('lexical');
},
get currentLexical() {
return this.post.get('lexical');
},
get previousTitle() {
return this.selectedRevision.get('title') || this.post.get('title');
},
get currentTitle() {
return this.post.get('title');
},
get cardConfig() {
return {
post: this.model
};
}
});