Content deleted Content added
1.0.8 (September 02, 2014) fix sep class |
1.0.9 (September 02, 2014) fix old IE compatibility of handler, newline sign to blank, newline sign for moved blocks, moved block gray a bit darker, trim moved group borders to first word or newline |
||
Line 3:
// ==UserScript==
// @name wDiff
// @version 1.0.
// @date September
// @description improved word-based diff library with block move detection
// @homepage https://en.wikipedia.org/wiki/User:Cacycle/diff
Line 65:
.oldBlock: number of block in old text order
.newBlock: number of block in new text order
.oldNumber: old text token number of first token
.newNumber: new text token number of first token
.oldStart: old text token index of first token
.count number of
.
.chars: char length
.type: 'same', 'del', 'ins'
.section: section number
.group: group number of block
.fixed:
.string: string of block tokens
groups[]: section blocks that are consecutive in old text
.oldNumber: first block
.blockStart: first block index
.blockEnd: last block index
.maxWords: word count of longest block
.words: word count
.chars: char count
.fixed:
.moved[]: list of groups that have been moved from this position
.movedFrom: position this group has been moved from
.color: color number of moved group
.diff: group diff
*/
// JSHint options: W004: is already defined, W097: Use the function form of "use strict", W100: This character may get silently deleted by one or more browsers
/* jshint -W004, -W097, -W100, newcap: false, browser: true, jquery: true, sub: true, bitwise: true, curly:
/* global console */
Line 180 ⟶ 181:
wDiff.stylesheet =
'.wDiffTab:before { content: "→"; color: #bbb; font-size: smaller; }' +
'.wDiffNewline:before { content: "
'.wDiffMarkRight:before { content: "▶"; }' +
'.wDiffMarkLeft:before { content: "◀"; }' +
'.wDiffDelete { font-weight: normal; text-decoration: none; color: #fff; background-color: #c33; border-radius: 0.25em; padding: 0.2em 1px; }' +
'.wDiffInsert { font-weight: normal; text-decoration: none; color: #fff; background-color: #07e; border-radius: 0.25em; padding: 0.2em 1px; }' +
'.wDiffBlockLeft { background-color: #
'.wDiffBlockRight { background-color: #
'.wDiffMarkLeft { color: #
'.wDiffMarkRight { color: #
'.wDiffFragment { white-space: pre-wrap; background: #fcfcfc; border: #bbb solid; border-width: 1px 1px 1px 0.5em; border-radius: 0.5em; font-family: inherit; font-size: 88%; line-height: 1.6; box-shadow: 2px 2px 2px #ddd; padding: 1em; margin: 0; }' +
'.wDiffNoChange { white-space: pre-wrap; background: #f0f0f0; border: #bbb solid; border-width: 1px 1px 1px 0.5em; border-radius: 0.5em; font-family: inherit; font-size: 88%; line-height: 1.6; box-shadow: 2px 2px 2px #ddd; padding: 0.5em; margin: 1em 0; }' +
'.wDiffSeparator { margin-bottom: 1em; }' +
'.wDiffBlock {
'.wDiffBlock0 { background-color: #ffff60; }' +
'.wDiffBlock1 { background-color: #c0ff60; }' +
Line 202 ⟶ 203:
'.wDiffBlock7 { background-color: #ffbbbb; }' +
'.wDiffBlock8 { background-color: #a0e8a0; }' +
'.wDiffMark {
'.wDiffMark0 { color: #ffff60; }' +
'.wDiffMark1 { color: #c0ff60; }' +
Line 297 ⟶ 298:
var block = document.getElementById('wDiffBlock' + number);
var mark = document.getElementById('wDiffMark' + number);
if ( (type === undefined) || (type == 'mouseover') ) {
if (element.addEventListener !== undefined) {
}
else if (element.attachEvent !== undefined) {
}
}
block.className += ' wDiffBlockHighlight';
}
else if ( (type == 'mouseout') || (type == 'click') ) {
// getElementsByClassName
var container = element.parentNode;
var spans = container.getElementsByTagName('span');
for (var i = 0; i < spans.length; i ++) {
if ( ( (spans[i] != block) && (spans[i] != mark) ) || (type != 'click') ) {
if (spans[i].className.indexOf(' wDiffBlockHighlight') != -1) {
spans[i].className = spans[i].className.replace(/ wDiffBlockHighlight/g, '');
}
else if (spans[i].className.indexOf(' wDiffMarkHighlight') != -1) {
spans[i].className = spans[i].className.replace(/ wDiffMarkHighlight/g, '');
}
}
}
}
return;
Line 1,296 ⟶ 1,300:
// find groups of continuous old text blocks
wDiff.GetGroups(blocks, groups);
// set longest sequence of increasing groups in sections as fixed (not moved)
wDiff.SetFixed(blocks, groups, sections);
// convert groups to insertions/deletions if maximal block length is too short
Line 1,304 ⟶ 1,311:
wDiff.GetSections(blocks, sections);
wDiff.GetGroups(blocks, groups);
wDiff.SetFixed(blocks, groups, sections);
}
// collect deletion ('del') blocks from old text
Line 1,383 ⟶ 1,388:
oldStart: jStart,
count: count,
words: wDiff.WordCount(string),
chars: chars,
type: 'same',
Line 1,491 ⟶ 1,497:
// get word and char count of block
maxWords = blocks[i].words;
}
words +=
chars += blocks[i].chars;
groupEnd = i;
Line 1,536 ⟶ 1,541:
// wDiff.UnlinkBlocks:
// called from: DetectBlocks()
// changes: text.newText/oldText[].link
Line 1,547 ⟶ 1,552:
// cycle through groups
for (var group = 0; group < groups.length; group ++) {
if
var blockStart = groups[group].blockStart;
var blockEnd = groups[group].blockEnd;
// unlink whole group if no block is at least blockMinLength words long
if (groups[group].maxWords < wDiff.blockMinLength) {
for (var block = blockStart; block <= blockEnd; block ++) {
wDiff.UnlinkSingleBlock(blocks[block], text);
unlinked = true;
}
}
// unlink border blocks without words/blanks
else {
for (var block = blockStart; block <= blockEnd; block ++) {
if ( (blocks[block].words !== 0) || (blocks[block].string == '\n') ) {
break;
}
wDiff.UnlinkSingleBlock(blocks[block], text);
unlinked = true;
blockStart = block;
}
// unlink end blocks of 0 words/newlines
for (var block = blockEnd; block > blockStart; block --) {
if ( (blocks[block].words !== 0) || (blocks[block].string == '\n') ) {
break;
}
wDiff.UnlinkSingleBlock(blocks[block], text);
unlinked = true;
}
}
}
}
return unlinked;
};
// wDiff.UnlinkBlock: un-link text tokens of block, converting them into 'ins'/'del' pairs
// called from: wDiff.UnlinkBlocks()
// changes: text.newText/oldText[].link
wDiff.UnlinkSingleBlock = function (block, text) {
// cycle through old text
var j = block.oldStart;
for (var count = 0; count < block.count; count ++) {
// unlink tokens
text.newText.tokens[ text.oldText.tokens[j].link ].link = null;
text.oldText.tokens[j].link = null;
j = text.oldText.tokens[j].next;
}
return;
};
Line 1,698 ⟶ 1,738:
oldStart: oldStart,
count: count,
words: null,
chars: null,
type: 'del',
Line 1,833 ⟶ 1,874:
oldStart: null,
count: count,
words: null,
chars: null,
type: 'ins',
Line 2,084 ⟶ 2,126:
// check for colored block and move direction
var blockFrom = null;
if
if (groups[ groups[group].movedFrom ].blockStart < blockStart) {
blockFrom = 'left';
Line 2,111 ⟶ 2,153:
// add 'same' (unchanged) text
if (type == 'same') {
if (color !== null) {
string = string.replace(/\n/g, wDiff.htmlNewline);
}
diff += string;
}
Line 2,611 ⟶ 2,656:
script.textContent = code;
}
return;
};
Line 2,666 ⟶ 2,711:
wDiff.DebugBlocks = function (blocks) {
var dump = '\ni \toldBl \tnewBl \toldNm \tnewNm \toldSt \tcount \twords \tchars \ttype \tsect \tgroup \tfixed \tstring\n';
for (var i = 0; i < blocks.length; i ++) {
dump += i + ' \t' + blocks[i].oldBlock + ' \t' + blocks[i].newBlock + ' \t' + blocks[i].oldNumber + ' \t' + blocks[i].newNumber + ' \t' + blocks[i].oldStart + ' \t' + blocks[i].count + ' \t' + blocks[i].words + ' \t' + blocks[i].chars + ' \t' + blocks[i].type + ' \t' + blocks[i].section + ' \t' + blocks[i].group + ' \t' + blocks[i].fixed + ' \t' + wDiff.DebugShortenString(blocks[i].string) + '\n';
}
return dump;
|