mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-30 13:29:56 +00:00
149 lines
4.1 KiB
JavaScript
149 lines
4.1 KiB
JavaScript
/*\
|
|
title: $:/core/modules/widgets/diff-text.js
|
|
type: application/javascript
|
|
module-type: widget
|
|
|
|
Widget to display a diff between two texts
|
|
|
|
\*/
|
|
(function(){
|
|
|
|
/*jslint node: true, browser: true */
|
|
/*global $tw: false */
|
|
"use strict";
|
|
|
|
var Widget = require("$:/core/modules/widgets/widget.js").widget,
|
|
dmp = require("$:/core/modules/utils/diff-match-patch/diff_match_patch.js");
|
|
|
|
var DiffTextWidget = function(parseTreeNode,options) {
|
|
this.initialise(parseTreeNode,options);
|
|
};
|
|
|
|
/*
|
|
Inherit from the base widget class
|
|
*/
|
|
DiffTextWidget.prototype = new Widget();
|
|
|
|
DiffTextWidget.prototype.invisibleCharacters = {
|
|
"\n": "↩︎\n",
|
|
"\r": "⇠",
|
|
"\t": "⇥\t"
|
|
};
|
|
|
|
/*
|
|
Render this widget into the DOM
|
|
*/
|
|
DiffTextWidget.prototype.render = function(parent,nextSibling) {
|
|
this.parentDomNode = parent;
|
|
this.computeAttributes();
|
|
this.execute();
|
|
// Create the diff
|
|
var dmpObject = new dmp.diff_match_patch(),
|
|
diffs = dmpObject.diff_main(this.getAttribute("source"),this.getAttribute("dest"));
|
|
// Apply required cleanup
|
|
switch(this.getAttribute("cleanup","semantic")) {
|
|
case "none":
|
|
// No cleanup
|
|
break;
|
|
case "efficiency":
|
|
dmpObject.diff_cleanupEfficiency(diffs);
|
|
break;
|
|
default: // case "semantic"
|
|
dmpObject.diff_cleanupSemantic(diffs);
|
|
break;
|
|
}
|
|
// Create the elements
|
|
var domContainer = this.document.createElement("div"),
|
|
domDiff = this.createDiffDom(diffs);
|
|
parent.insertBefore(domContainer,nextSibling);
|
|
// Set variables
|
|
this.setVariable("diff-count",diffs.reduce(function(acc,diff) {
|
|
if(diff[0] !== dmp.DIFF_EQUAL) {
|
|
acc++;
|
|
}
|
|
return acc;
|
|
},0).toString());
|
|
// Render child widgets
|
|
this.renderChildren(domContainer,null);
|
|
// Render the diff
|
|
domContainer.appendChild(domDiff);
|
|
// Save our container
|
|
this.domNodes.push(domContainer);
|
|
};
|
|
|
|
/*
|
|
Create DOM elements representing a list of diffs
|
|
*/
|
|
DiffTextWidget.prototype.createDiffDom = function(diffs) {
|
|
var self = this;
|
|
// Create the element and assign the attributes
|
|
var domPre = this.document.createElement("pre"),
|
|
domCode = this.document.createElement("code");
|
|
$tw.utils.each(diffs,function(diff) {
|
|
var tag = diff[0] === dmp.DIFF_INSERT ? "ins" : (diff[0] === dmp.DIFF_DELETE ? "del" : "span"),
|
|
className = diff[0] === dmp.DIFF_INSERT ? "tc-diff-insert" : (diff[0] === dmp.DIFF_DELETE ? "tc-diff-delete" : "tc-diff-equal"),
|
|
dom = self.document.createElement(tag),
|
|
text = diff[1],
|
|
currPos = 0,
|
|
re = /([\x00-\x1F])/mg,
|
|
match = re.exec(text),
|
|
span,
|
|
printable;
|
|
dom.className = className;
|
|
while(match) {
|
|
if(currPos < match.index) {
|
|
dom.appendChild(self.document.createTextNode(text.slice(currPos,match.index)));
|
|
}
|
|
span = self.document.createElement("span");
|
|
span.className = "tc-diff-invisible";
|
|
printable = self.invisibleCharacters[match[0]] || ("[0x" + match[0].charCodeAt(0).toString(16) + "]");
|
|
span.appendChild(self.document.createTextNode(printable));
|
|
dom.appendChild(span);
|
|
currPos = match.index + match[0].length;
|
|
match = re.exec(text);
|
|
}
|
|
if(currPos < text.length) {
|
|
dom.appendChild(self.document.createTextNode(text.slice(currPos)));
|
|
}
|
|
domCode.appendChild(dom);
|
|
});
|
|
domPre.appendChild(domCode);
|
|
return domPre;
|
|
};
|
|
|
|
/*
|
|
Compute the internal state of the widget
|
|
*/
|
|
DiffTextWidget.prototype.execute = function() {
|
|
// Make child widgets
|
|
var parseTreeNodes;
|
|
if(this.parseTreeNode && this.parseTreeNode.children && this.parseTreeNode.children.length > 0) {
|
|
parseTreeNodes = this.parseTreeNode.children;
|
|
} else {
|
|
parseTreeNodes = [{
|
|
type: "transclude",
|
|
attributes: {
|
|
tiddler: {type: "string", value: "$:/language/Diffs/CountMessage"}
|
|
}
|
|
}];
|
|
}
|
|
this.makeChildWidgets(parseTreeNodes);
|
|
};
|
|
|
|
/*
|
|
Selectively refreshes the widget if needed. Returns true if the widget or any of its children needed re-rendering
|
|
*/
|
|
DiffTextWidget.prototype.refresh = function(changedTiddlers) {
|
|
var changedAttributes = this.computeAttributes();
|
|
if(changedAttributes.source || changedAttributes.dest || changedAttributes.cleanup) {
|
|
this.refreshSelf();
|
|
return true;
|
|
} else {
|
|
return this.refreshChildren(changedTiddlers);
|
|
}
|
|
};
|
|
|
|
exports["diff-text"] = DiffTextWidget;
|
|
|
|
})();
|