mirror of
https://github.com/Jermolene/TiddlyWiki5
synced 2024-11-20 00:34:50 +00:00
144 lines
4.0 KiB
JavaScript
144 lines
4.0 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",Math.trunc((diffs.length - 1) / 2).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;
|
||
|
|
||
|
})();
|