Content deleted Content added
1.0.7 (September 01, 2014) jshint, split wDiff.DetectBlocks, unlinking too short groups, Greasemonkey header |
1.0.8 (September 02, 2014) css styles to classes, disable colors, add scrolling between block and its mark, add bloack and mark highlighting on hovering |
||
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 101:
var wDiff; if (wDiff === undefined) { wDiff = {}; }
var WED;
//
Line 201 ⟶ 117:
// enable recursive diff to resolve problematic sequences
if (wDiff.recursiveDiff === undefined) { wDiff.recursiveDiff = true; }
// display blocks in different colors
if (wDiff.coloredBlocks === undefined) { wDiff.coloredBlocks = false; }
// UniCode letter support for regexps, from http://xregexp.com/addons/unicode/unicode-base.js v1.0.0
Line 223 ⟶ 142:
// regExp for counting words
if (wDiff.regExpWordCount === undefined) { wDiff.regExpWordCount = new RegExp('(^|[^' + wDiff.letters + '])[' + wDiff.letters + '][' + wDiff.letters + '_\'’]*', 'g'); }
//
Line 254 ⟶ 172:
if (wDiff.fragmentJoinLines === undefined) { wDiff.fragmentJoinLines = 10; }
if (wDiff.fragmentJoinChars === undefined) { wDiff.fragmentJoinChars = 1000; }
//
// css classes
//
if (wDiff.stylesheet === undefined) {
wDiff.stylesheet =
'.wDiffTab:before { content: "→"; color: #bbb; font-size: smaller; }' +
'.wDiffNewline:before { content: "¶"; color: #ccc; padding: 0 0.2em 0 1px; }' +
'.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: #ddd; border-radius: 0.25em; padding: 0.25em 1px; margin: 0 1px; }' +
'.wDiffBlockRight { background-color: #ddd; border-radius: 0.25em; padding: 0.25em 1px; margin: 0 1px; }' +
'.wDiffMarkLeft { color: #ddd; background-color: #c33; border-radius: 0.25em; padding: 0.2em 0.2em; margin: 0 1px; }' +
'.wDiffMarkRight { color: #ddd; background-color: #c33; border-radius: 0.25em; padding: 0.2em 0.2em; margin: 0 1px; }' +
'.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; }' +
'.wDiffSeparator { }' +
'.wDiffBlock { background-color: #ddd; }' +
'.wDiffBlock0 { background-color: #ffff60; }' +
'.wDiffBlock1 { background-color: #c0ff60; }' +
'.wDiffBlock2 { background-color: #ffd8ff; }' +
'.wDiffBlock3 { background-color: #a0ffff; }' +
'.wDiffBlock4 { background-color: #ffe840; }' +
'.wDiffBlock5 { background-color: #bbccff; }' +
'.wDiffBlock6 { background-color: #ffaaff; }' +
'.wDiffBlock7 { background-color: #ffbbbb; }' +
'.wDiffBlock8 { background-color: #a0e8a0; }' +
'.wDiffMark { color: #ddd; }' +
'.wDiffMark0 { color: #ffff60; }' +
'.wDiffMark1 { color: #c0ff60; }' +
'.wDiffMark2 { color: #ffd8ff; }' +
'.wDiffMark3 { color: #a0ffff; }' +
'.wDiffMark4 { color: #ffd840; }' +
'.wDiffMark5 { color: #bbccff; }' +
'.wDiffMark6 { color: #ff99ff; }' +
'.wDiffMark7 { color: #ff9999; }' +
'.wDiffMark8 { color: #90d090; }' +
'.wDiffBlockHighlight { background-color: #333; color: #fff; }' +
'.wDiffMarkHighlight { background-color: #333; color: #fff; }';
}
//
// css styles
//
if (wDiff.styleContainer === undefined) { wDiff.styleContainer = ''; }
if (wDiff.StyleDelete === undefined) { wDiff.styleDelete = ''; }
if (wDiff.styleInsert === undefined) { wDiff.styleInsert = ''; }
if (wDiff.styleBlockLeft === undefined) { wDiff.styleBlockLeft = ''; }
if (wDiff.styleBlockRight === undefined) { wDiff.styleBlockRight = ''; }
if (wDiff.styleBlockHighlight === undefined) { wDiff.styleBlockHighlight = ''; }
if (wDiff.styleBlockColor === undefined) { wDiff.styleBlockColor = []; }
if (wDiff.styleMarkLeft === undefined) { wDiff.styleMarkLeft = ''; }
if (wDiff.styleMarkRight === undefined) { wDiff.styleMarkRight = ''; }
if (wDiff.styleMarkColor === undefined) { wDiff.styleMarkColor = []; }
if (wDiff.styleNewline === undefined) { wDiff.styleNewline = ''; }
if (wDiff.styleTab === undefined) { wDiff.styleTab = ''; }
if (wDiff.styleFragment === undefined) { wDiff.styleFragment = ''; }
if (wDiff.styleNoChange === undefined) { wDiff.styleNoChange = ''; }
if (wDiff.styleSeparator === undefined) { wDiff.styleSeparator = ''; }
if (wDiff.styleOmittedChars === undefined) { wDiff.styleOmittedChars = ''; }
//
// html for core diff
//
// dynamic replacements: {block}: block number style, {mark}: mark number style, {class}: class number, {number}: block number, {title}: title attribute (popup)
// class plus html comment are required indicators for wDiff.ShortenOutput()
if (wDiff.blockEvent === undefined) { wDiff.blockEvent = ' onmouseover="wDiff.BlockHandler(null, this);"'; }
if (wDiff.htmlContainerStart === undefined) { wDiff.htmlContainerStart = '<div class="wDiffContainer" style="' + wDiff.styleContainer + '">'; }
if (wDiff.htmlContainerEnd === undefined) { wDiff.htmlContainerEnd = '</div>'; }
if (wDiff.htmlDeleteStart === undefined) { wDiff.htmlDeleteStart = '<span class="wDiffDelete" style="' + wDiff.styleDelete + '" title="−">'; }
if (wDiff.htmlDeleteEnd === undefined) { wDiff.htmlDeleteEnd = '</span><!--wDiffDelete-->'; }
if (wDiff.htmlInsertStart === undefined) { wDiff.htmlInsertStart = '<span class="wDiffInsert" style="' + wDiff.styleInsert + '" title="+">'; }
if (wDiff.htmlInsertEnd === undefined) { wDiff.htmlInsertEnd = '</span><!--wDiffInsert-->'; }
if (wDiff.htmlBlockLeftStart === undefined) { wDiff.htmlBlockLeftStart = '<span class="wDiffBlockLeft wDiffBlock{class}" style="' + wDiff.styleBlockLeft + '{block}" title="▶ ▢" id="wDiffBlock{number}"' + wDiff.blockEvent + '>'; }
if (wDiff.htmlBlockLeftEnd === undefined) { wDiff.htmlBlockLeftEnd = '</span><!--wDiffBlockLeft-->'; }
if (wDiff.htmlBlockRightStart === undefined) { wDiff.htmlBlockRightStart = '<span class="wDiffBlockRight wDiffBlock{class}" style="' + wDiff.styleBlockRight + '{block}" title="▭ ◀" id="wDiffBlock{number}"' + wDiff.blockEvent + '>'; }
if (wDiff.htmlBlockRightEnd === undefined) { wDiff.htmlBlockRightEnd = '</span><!--wDiffBlockRight-->'; }
if (wDiff.htmlMarkRight === undefined) { wDiff.htmlMarkRight = '<span class="wDiffMarkRight wDiffMark{class}" style="' + wDiff.styleMarkRight + '{mark}"{title} id="wDiffMark{number}"' + wDiff.blockEvent + '></span><!--wDiffMarkRight-->'; }
if (wDiff.htmlMarkLeft === undefined) { wDiff.htmlMarkLeft = '<span class="wDiffMarkLeft wDiffMark{class}" style="' + wDiff.styleMarkLeft + '{mark}"{title} id="wDiffMark{number}"' + wDiff.blockEvent + '></span><!--wDiffMarkLeft-->'; }
if (wDiff.htmlNewline === undefined) { wDiff.htmlNewline = '<span class="wDiffNewline" style="' + wDiff.styleNewline + '"></span>\n'; }
if (wDiff.htmlTab === undefined) { wDiff.htmlTab = '<span class="wDiffTab" style="' + wDiff.styleTab + '">\t</span>'; }
//
// html for shorten output
//
if (wDiff.htmlFragmentStart === undefined) { wDiff.htmlFragmentStart = '<pre class="wDiffFragment" style="' + wDiff.styleFragment + '">'; }
if (wDiff.htmlFragmentEnd === undefined) { wDiff.htmlFragmentEnd = '</pre>'; }
if (wDiff.htmlNoChange === undefined) { wDiff.htmlNoChange = '<pre class="wDiffFragment" style="' + wDiff.styleNoChange + '" title="="></pre>'; }
if (wDiff.htmlSeparator === undefined) { wDiff.htmlSeparator = '<div class="wDiffStyleSeparator" style="' + wDiff.styleSeparator + '"></div>'; }
if (wDiff.htmlOmittedChars === undefined) { wDiff.htmlOmittedChars = '<span class="wDiffOmittedChars" style="' + wDiff.styleOmittedChars + '">…</span>'; }
//
// javascript handler for output code
//
// wDiff.BlockHandler: event handler for block and mark elements
if (wDiff.BlockHandler === undefined) { wDiff.BlockHandler = function (event, element) {
// get event data
var type;
if (event !== null) {
element = event.currentTarget;
type = event.type;
event.stopPropagation();
}
// get mark/block elements
var number = element.id.replace(/\D/g, '');
var block = document.getElementById('wDiffBlock' + number);
var mark = document.getElementById('wDiffMark' + number);
switch (type) {
// highlight corresponding mark/block pairs
case undefined:
case 'mouseover':
if (element.addEventListener !== undefined) {
element.addEventListener('mouseout', wDiff.BlockHandler, false);
element.addEventListener('click', wDiff.BlockHandler, false);
}
else if (element.attachEvent !== undefined) {
element.attachEvent('onmouseout', wDiff.BlockHandler);
element.attachEvent('onclick', wDiff.BlockHandler);
}
else {
return;
}
block.className += ' wDiffBlockHighlight';
mark.className += ' wDiffMarkHighlight';
break;
// remove mark/block highlighting
case 'mouseout':
var highlighted = document.getElementsByClassName('wDiffBlockHighlight');
for (var i = 0; i < highlighted.length; i ++) {
highlighted[i].className = highlighted[i].className.replace(/ wDiffBlockHighlight/g, '');
}
var highlighted = document.getElementsByClassName('wDiffMarkHighlight');
for (var i = 0; i < highlighted.length; i ++) {
highlighted[i].className = highlighted[i].className.replace(/ wDiffMarkHighlight/g, '');
}
break;
// scroll to corresponding mark/block element
case 'click':
// remove element click handler
if (element.removeEventListener !== undefined) {
element.removeEventListener('mouseout', wDiff.BlockHandler, false);
}
else {
element.detachEvent('onmouseout', wDiff.BlockHandler);
}
// get corresponding element
var corrElement;
if (element == block) {
corrElement = mark;
}
else {
corrElement = block;
}
// get offsetTop
var corrElementPos = 0;
var node = corrElement;
do {
corrElementPos += node.offsetTop;
} while ( (node = node.offsetParent) !== null );
// scroll element under mouse cursor
var top = window.pageYOffset;
var cursor = event.pageY;
var line = parseInt(window.getComputedStyle(corrElement).getPropertyValue('line-height'));
window.scroll(0, corrElementPos + top - cursor + line / 2);
break;
}
return;
}; }
//
// start of diff code
//
Line 280 ⟶ 396:
wDiff.AddStyleSheet(wDiff.stylesheet);
// add block handler to head if running under Greasemonkey
if (typeof GM_info == 'object') {
var script = 'var wDiff; if (wDiff === undefined) { wDiff = {}; } wDiff.BlockHandler = ' + wDiff.BlockHandler.toString();
wDiff.AddScript(script);
}
return;
};
Line 1,177 ⟶ 1,298:
wDiff.GetGroups(blocks, groups);
// convert groups to insertions/deletions if maximal block length is too short
if ( (wDiff.blockMinLength > 0) && (wDiff.UnlinkBlocks(text, blocks, groups) === true) ) {
// repeat from start after conversion to insertions/deletions
wDiff.GetSameBlocks(text, blocks);
Line 2,042 ⟶ 2,163:
}
//
if (wDiff.showBlockMoves === false) {
mark = wDiff.htmlDeleteStart + wDiff.HtmlEscape(movedText) + wDiff.htmlDeleteEnd;
Line 2,097 ⟶ 2,218:
//
// wDiff.HtmlCustomize: customize move indicator html:
// input: text (html or css code)
// returns: customized text
Line 2,104 ⟶ 2,225:
wDiff.HtmlCustomize = function (text, number, title) {
if (wDiff.coloredBlocks === true) {
if (blockStyle === undefined) {
blockStyle = '';
}
var markStyle = wDiff.styleMarkColor[number];
if (markStyle === undefined) {
markStyle = '';
}
text = text.replace(/\{block\}/g, ' ' + blockStyle);
text = text.replace(/\{mark\}/g, ' ' + markStyle);
text = text.replace(/\{class\}/g, number);
}
else {
text = text.replace(/\{block\}|\{mark\}|\{class\}/g, '');
}
text = text.replace(/\{number\}/g, number);
// shorten title text, replace {title}
Line 2,119 ⟶ 2,255:
title = title.replace(/ /g, ' ');
text = text.replace(/\{title\}/, ' title="' + title + '"');
}
else {
text = text.replace(/\{title\}/, '');
}
return text;
Line 2,174 ⟶ 2,313:
// scan for diff html tags
var regExpDiff = /<\w+\b[^>]*\bclass="
var tagStart = [];
var tagEnd = [];
Line 2,183 ⟶ 2,322:
while ( (regExpMatch = regExpDiff.exec(html)) !== null ) {
if ( (i > 0) && (tagEnd[i - 1] == regExpMatch.index) ) {
tagEnd[i - 1] = regExpMatch.index + regExpMatch[0].length;
Line 2,456 ⟶ 2,595:
return diff;
};
//
// wDiff.AddScript: add script to head
//
wDiff.AddScript = function (code) {
var script = document.createElement('script');
script.id = 'wDiffBlockHandler';
if (script.innerText !== undefined) {
script.innerText = code;
}
else {
script.textContent = code;
}
wikEd.head.appendChild(script);
return;
};
|