Benutzer:Schnark/js/wikiblame.js
aus Wikipedia, der freien Enzyklopädie
< Benutzer:Schnark | js
Dies ist die aktuelle Version dieser Seite, zuletzt bearbeitet am 4. Juli 2019 um 07:30 Uhr durch imported>Schnark(522406) (Schaltfläche kennzeichnen).
Hinweis: Leere nach dem Veröffentlichen den Browser-Cache, um die Änderungen sehen zu können.
- Firefox/Safari: Umschalttaste drücken und gleichzeitig Aktualisieren anklicken oder entweder Strg+F5 oder Strg+R (⌘+R auf dem Mac) drücken
- Google Chrome: Umschalttaste+Strg+R (⌘+Umschalttaste+R auf dem Mac) drücken
- Internet Explorer/Edge: Strg+F5 drücken oder Strg drücken und gleichzeitig Aktualisieren anklicken
- Opera: Strg+F5
//Dokumentation unter [[Benutzer:Schnark/js/wikiblame]] <nowiki>
/*global mediaWiki, OO*/
(function ($, mw, libs) {
"use strict";
var l10n = {
//jscs:disable maximumLineLength
en: {
'wikiblame': 'Wikiblame',
'wikiblame-tooltip': 'Find the revision in which a certain text was added',
//Fehler
'wikiblame-invalid-regexp': 'The regular expression contains an error!',
'wikiblame-api-error': 'An error occurred while querying the API!',
'wikiblame-wrong-revisions': 'The selected revisions don\'t match!',
'wikiblame-in-first-revision': 'The text is already present in the first selected revision!',
'wikiblame-not-in-first-revision': 'The text is already missing in the first selected revision!',
'wikiblame-in-last-revision': 'The text is already present in the last selected revision!',
'wikiblame-not-in-last-revision': 'The text is already missing in the last selected revision!',
'wikiblame-not-found': 'The text wasn\'t found!',
//Fortschritt
'wikiblame-get-history': 'Loading history …',
'wikiblame-test-revision': 'Examining revision $1 …',
'wikiblame-load-diff': 'Loading diff …',
//Dialog
'wikiblame-dialog-search-label': 'Search for:',
'wikiblame-dialog-search-help': 'The text or regular expression that should be searched for',
'wikiblame-dialog-regexp-label': 'regular expression',
'wikiblame-dialog-regexp-help': 'Interprete search text as regular expression',
'wikiblame-dialog-source-label': 'Search source code',
'wikiblame-dialog-source-help': 'Search the source code instead of the parsed HTML',
'wikiblame-dialog-invert-label': 'Find deletion',
'wikiblame-dialog-invert-help': 'Search for the deletion of the search text instead of its insertion',
'wikiblame-dialog-later-label': 'later revisions',
'wikiblame-dialog-later-help': 'Search the revisions after the currently shown, instead of all before this one',
'wikiblame-dialog-linear-label': 'linear search',
'wikiblame-dialog-linear-help': 'Slow search, that will always find the next matching diff',
'wikiblame-dialog-down-label': 'start with newer revisions',
'wikiblame-dialog-down-help': 'Start with newer revisions in the linear search',
'wikiblame-dialog-go': 'Search',
'wikiblame-dialog-done': 'Close'
},
de: {
'wikiblame-tooltip': 'Findet die Version, in der ein bestimmter Text eingefügt wurde',
'wikiblame-invalid-regexp': 'Der reguläre Ausdruck enthält einen Fehler!',
'wikiblame-api-error': 'Bei der API-Anfrage trat ein Fehler auf!',
'wikiblame-wrong-revisions': 'Die gewählten Versionen passen nicht zusammen!',
'wikiblame-in-first-revision': 'Der Text befindet sich schon in der ersten untersuchten Version!',
'wikiblame-not-in-first-revision': 'Der Text fehlt schon in der ersten untersuchten Version!',
'wikiblame-in-last-revision': 'Der Text befindet sich schon in der letzten untersuchten Version!',
'wikiblame-not-in-last-revision': 'Der Text fehlt schon in der letzten untersuchten Version!',
'wikiblame-not-found': 'Der Text wurde nicht gefunden!',
'wikiblame-get-history': 'Lade Versionsgeschichte …',
'wikiblame-test-revision': 'Untersuche Version $1 …',
'wikiblame-load-diff': 'Lade Versionsunterschied …',
'wikiblame-dialog-search-label': 'Suche nach:',
'wikiblame-dialog-search-help': 'Der Text oder reguläre Ausdruck, nach dem gesucht werden soll',
'wikiblame-dialog-regexp-label': 'regulärer Ausdruck',
'wikiblame-dialog-regexp-help': 'Suchtext als regulären Ausdruck interpretieren',
'wikiblame-dialog-source-label': 'Quelltext durchsuchen',
'wikiblame-dialog-source-help': 'Durchsucht den Quelltext anstatt des geparsten HTML',
'wikiblame-dialog-invert-label': 'Löschung finden',
'wikiblame-dialog-invert-help': 'Sucht nach der Löschung des Suchtextes statt nach der Einfügung',
'wikiblame-dialog-later-label': 'spätere Versionen',
'wikiblame-dialog-later-help': 'Durchsucht die Versionen ab der aktuell gezeigten, statt die früheren bis zu dieser',
'wikiblame-dialog-linear-label': 'lineare Suche',
'wikiblame-dialog-linear-help': 'Langsame Suchvariante, die immer die nächste passende Änderung findet',
'wikiblame-dialog-down-label': 'bei neueren Versionen beginnen',
'wikiblame-dialog-down-help': 'Bei der linearen Suche mit den neuesten Versionen beginnen',
'wikiblame-dialog-go': 'Suche',
'wikiblame-dialog-done': 'Schließen'
},
'de-ch': {
'wikiblame-dialog-done': 'Schliessen'
}
//jscs:enable maximumLineLength
}, cachedHistory = {},
cachedContent = {
0: {
0: $.Deferred().resolve('')
},
1: {
0: $.Deferred().resolve('')
}
};
function initL10N (l10n) {
var i, chain = mw.language.getFallbackLanguageChain();
for (i = chain.length - 1; i >= 0; i--) {
if (chain[i] in l10n) {
mw.messages.set(l10n[chain[i]]);
}
}
}
function getHistory (page) {
if (!(page in cachedHistory)) {
cachedHistory[page] = $.Deferred();
retrieveHistory(page, cachedHistory[page]);
}
return cachedHistory[page].promise();
}
function retrieveHistory (page, deferred) {
var hist = [0];
function next (cont) {
var data = {
action: 'query',
prop: 'revisions',
titles: page,
rvprop: 'ids',
rvlimit: 'max',
rvdir: 'newer',
'continue': '',
format: 'json',
formatversion: 2
};
if (cont) {
$.extend(data, cont);
}
$.getJSON(mw.util.wikiScript('api'), data).then(function (json) {
if (
!json || !json.query || !json.query.pages ||
!json.query.pages[0] || !json.query.pages[0].revisions
) {
deferred.reject(mw.msg('wikiblame-api-error'));
return;
}
var revs = json.query.pages[0].revisions, i;
for (i = 0; i < revs.length; i++) {
hist.push(revs[i].revid);
}
if (json['continue']) {
next(json['continue']);
} else {
deferred.resolve(hist);
}
}, function () {
deferred.reject(mw.msg('wikiblame-api-error'));
});
}
next();
}
function getContent (revision, parsed) {
if (!(revision in cachedContent[parsed ? 1 : 0])) {
cachedContent[parsed ? 1 : 0][revision] = $.Deferred();
retrieveContent(revision, parsed, cachedContent[parsed ? 1 : 0][revision]);
}
return cachedContent[parsed ? 1 : 0][revision].promise();
}
function retrieveContent (revision, parsed, deferred) {
var prop = parsed ? 'text' : 'wikitext',
data = {
action: 'parse',
oldid: revision,
prop: prop,
format: 'json',
formatversion: 2
};
$.getJSON(mw.util.wikiScript('api'), data).then(function (json) {
if (!json || !json.parse) {
deferred.reject(mw.msg('wikiblame-api-error'));
return;
}
var content = json.parse[prop] || '';
if (parsed) {
content = $('<div>').html(content).text();
}
deferred.resolve(content);
}, function () {
deferred.reject(mw.msg('wikiblame-api-error'));
});
}
function blame (page, min, max, search, parsed, invert, linear, down) {
var history, d = $.Deferred();
function start () {
if (min === 0 && invert) {
min = history[1];
}
if (max === 0) {
max = history[history.length - 1];
}
if (linear) {
blameLinear(min, max, down);
} else {
d.notify(mw.msg('wikiblame-test-revision', min));
testRevision(min).then(function (result) {
if (result) {
d.reject(mw.msg(invert ? 'wikiblame-not-in-first-revision' :
'wikiblame-in-first-revision'));
} else {
d.notify(mw.msg('wikiblame-test-revision', max));
testRevision(max).then(function (result) {
if (!result) {
d.reject(mw.msg(invert ? 'wikiblame-in-last-revision' :
'wikiblame-not-in-last-revision'));
} else {
blameBinary(min, max);
}
}, d.reject);
}
}, d.reject);
}
}
function testRevision (revision) {
return getContent(revision, parsed).then(function (content) {
var result = (typeof search === 'string') ? (content.indexOf(search) > -1) :
(search.test(content));
if (invert) {
result = !result;
}
return result;
});
}
function blameBinary (min, max) {
var i = history.indexOf(min), j = history.indexOf(max), middle;
if (i === -1 || j === -1 || i >= j) {
d.reject(mw.msg('wikiblame-wrong-revisions'));
} else if (i + 1 === j) {
d.resolve([min, max]);
} else {
middle = history[Math.floor((i + j) / 2)];
d.notify(mw.msg('wikiblame-test-revision', middle));
testRevision(middle).then(function (result) {
if (result) {
blameBinary(min, middle);
} else {
blameBinary(middle, max);
}
}, d.reject);
}
}
function blameLinear (min, max, found) {
var i = history.indexOf(min), j = history.indexOf(max), revision = down ? max : min;
if (i === -1 || j === -1 || i > j) {
d.reject(mw.msg('wikiblame-not-found'));
return;
}
d.notify(mw.msg('wikiblame-test-revision', revision));
testRevision(revision).then(function (result) {
if (down) {
if (result || !found) {
blameLinear(min, history[j - 1], result);
} else {
d.resolve([max, history[j + 1]]);
}
} else {
if (!result || found) {
blameLinear(history[i + 1], max, result);
} else {
d.resolve([history[i - 1], min]);
}
}
}, d.reject);
}
d.notify(mw.msg('wikiblame-get-history'));
getHistory(page).then(function (h) {
history = h;
start();
}, d.reject);
return d.promise();
}
function wikiblame (search, regexp, source, invert, rev, later, linear, down) {
if (regexp) {
try {
search = new RegExp(search);
} catch (e) {
return $.Deferred().reject(mw.msg('wikiblame-invalid-regexp')).promise();
}
}
var min = 0, max = 0;
if (later) {
min = rev;
} else {
max = rev;
}
return blame(mw.config.get('wgPageName'), min, max, search, !source, invert, linear, down);
}
function getWikiBlameDialog () {
function makeCheckbox (id, $overlay) {
var checkbox, field;
checkbox = new OO.ui.CheckboxInputWidget();
field = new OO.ui.FieldLayout(checkbox, {
label: mw.msg('wikiblame-dialog-' + id + '-label'),
help: mw.msg('wikiblame-dialog-' + id + '-help'),
align: 'inline',
$overlay: $overlay
});
return {field: field, element: checkbox};
}
function WikiBlameDialog (config) {
WikiBlameDialog.parent.apply(this, arguments);
this.rev = config.rev;
}
OO.inheritClass(WikiBlameDialog, OO.ui.ProcessDialog);
WikiBlameDialog.static.name = 'schnark-wikiblame';
WikiBlameDialog.static.title = mw.msg('wikiblame');
WikiBlameDialog.static.size = 'large';
WikiBlameDialog.static.actions = [
{
action: 'go',
label: mw.msg('wikiblame-dialog-go'),
flags: ['progressive', 'primary']
}, {
action: 'done',
label: mw.msg('wikiblame-dialog-done'),
flags: ['safe', 'close']
}
];
WikiBlameDialog.prototype.getBodyHeight = function () {
return this.panel.$element.outerHeight(true) + 50;
};
WikiBlameDialog.prototype.getActionProcess = function (action) {
if (action === 'go') {
return new OO.ui.Process(function () {
var actions = this.getActions();
actions.setAbilities({done: false});
actions.get({actions: 'go'})[0].pushPending();
this.runSearch().always(function () {
actions.setAbilities({done: true});
actions.get({actions: 'go'})[0].popPending();
});
}, this);
} else if (action === 'done') {
return new OO.ui.Process(function () {
this.close();
}, this);
}
return WikiBlameDialog.parent.prototype.getActionProcess.apply(this, arguments);
};
WikiBlameDialog.prototype.onLinearInputChange = function () {
this.downInput.setDisabled(!this.linearInput.isSelected());
};
WikiBlameDialog.prototype.initialize = function () {
var fieldset, checkbox;
WikiBlameDialog.parent.prototype.initialize.apply(this, arguments);
this.panel = new OO.ui.PanelLayout({padded: true, expanded: false});
fieldset = new OO.ui.FieldsetLayout();
this.panel.$element.append(fieldset.$element);
this.$body.append(this.panel.$element);
this.searchInput = new OO.ui.TextInputWidget();
fieldset.addItems([
new OO.ui.FieldLayout(this.searchInput, {
label: mw.msg('wikiblame-dialog-search-label'),
help: mw.msg('wikiblame-dialog-search-help'),
align: 'top',
$overlay: this.$overlay
})
]);
checkbox = makeCheckbox('regexp', this.$overlay);
this.regexpInput = checkbox.element;
fieldset.addItems([checkbox.field]);
checkbox = makeCheckbox('source', this.$overlay);
this.sourceInput = checkbox.element;
fieldset.addItems([checkbox.field]);
checkbox = makeCheckbox('invert', this.$overlay);
this.invertInput = checkbox.element;
fieldset.addItems([checkbox.field]);
checkbox = makeCheckbox('later', this.$overlay);
this.laterInput = checkbox.element;
fieldset.addItems([checkbox.field]);
checkbox = makeCheckbox('linear', this.$overlay);
this.linearInput = checkbox.element;
fieldset.addItems([checkbox.field]);
checkbox = makeCheckbox('down', this.$overlay);
this.downInput = checkbox.element;
fieldset.addItems([checkbox.field]);
this.progressBar = new OO.ui.ProgressBarWidget();
this.progressBarField = new OO.ui.FieldLayout(
this.progressBar,
{label: '', align: 'top'}
);
this.progressBarField.toggle(false);
fieldset.addItems([this.progressBarField]);
this.linearInput.connect(this, {change: 'onLinearInputChange'});
this.onLinearInputChange();
this.laterInput.setDisabled(this.rev === '0');
};
WikiBlameDialog.prototype.getReadyProcess = function () {
return WikiBlameDialog.parent.prototype.getReadyProcess.apply(this, arguments)
.next(function () {
this.searchInput.focus();
}, this);
};
WikiBlameDialog.prototype.getDataFromInputElements = function () {
var data = {
search: this.searchInput.getValue(),
regexp: this.regexpInput.isSelected(),
source: this.sourceInput.isSelected(),
invert: this.invertInput.isSelected(),
later: this.laterInput.isSelected(),
linear: this.linearInput.isSelected(),
down: this.downInput.isSelected()
}, rev = this.rev.split('|');
data.rev = (rev.length > 1 && (data.earlier !== data.linear)) ? Number(rev[1]) : Number(rev[0]);
return data;
};
WikiBlameDialog.prototype.runSearch = function () {
var data = this.getDataFromInputElements();
this.progressBar.setProgress(false);
this.progressBarField.toggle(true);
return wikiblame(
data.search, data.regexp, data.source, data.invert,
data.rev, data.later, data.linear, data.down
).then(function (data) {
var url = data[0] !== 0 ?
mw.util.getUrl(mw.config.get('wgPageName'), {diff: data[1], oldid: data[0]}) :
mw.util.getUrl(mw.config.get('wgPageName'), {oldid: data[1]});
this.progressBar.setProgress(100);
this.progressBarField.setLabel(mw.msg('wikiblame-load-diff'));
location.href = url;
}.bind(this), function (error) {
this.progressBar.setProgress(100);
this.progressBarField.setLabel(error);
}.bind(this), function (notice) {
this.progressBarField.setLabel(notice);
}.bind(this));
};
return WikiBlameDialog;
}
function showDialog (rev) {
var WikiBlameDialog, dialog, windowManager;
WikiBlameDialog = getWikiBlameDialog();
dialog = new WikiBlameDialog({rev: rev});
windowManager = new OO.ui.WindowManager();
$('body').append(windowManager.$element);
windowManager.addWindows([dialog]);
windowManager.openWindow(dialog);
}
function run (e) {
e.preventDefault();
mw.loader.using(['oojs-ui-core', 'oojs-ui-windows']).then(function () {
var id1 = mw.util.getParamValue('oldid'), id2 = mw.util.getParamValue('diff'), id = '0';
if (id1) {
id = id1;
if (id2 && !(/\D/.test(id2)) && Number(id1) < Number(id2)) {
id += '|' + id2;
}
}
showDialog(id);
});
}
function init () {
$(mw.util.addPortletLink('p-tb', '#', mw.msg('wikiblame'),
't-wikiblame-js', mw.msg('wikiblame-tooltip'))).on('click', run);
}
mw.loader.using('mediawiki.language').then(function () {
initL10N(l10n);
});
libs.wikiblame = blame;
if (mw.config.get('wgNamespaceNumber') >= 0) {
mw.loader.using(['mediawiki.util', 'mediawiki.language']).then(init);
}
})(jQuery, mediaWiki, mediaWiki.libs);
//</nowiki>