Benutzer:Schnark/js/templateEditor.js
aus Wikipedia, der freien Enzyklopädie
< Benutzer:Schnark | js
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/templateEditor]] <nowiki>
/*global mediaWiki, ve, OO*/
(function ($, mw, libs) {
"use strict";
if (libs.templateEditor) { //gegen doppelte Einbindung schützen
return;
}
var hasOwn = Object.prototype.hasOwnProperty, templateEditor = {
version: 2.17,
status: 'register',
started: false,
$footer: null,
footitems: [],
$tbody: null,
editData: {
title: '',
text: '',
comments: [],
minor: true,
watch: false,
starttime: '',
edittime: ''
},
targets: [],
plugins: {},
runningPlugins: [],
ve: false
}, l10n = {
/*jscs:disable maximumLineLength*/
en: {
'comma-separator': ', ',
'schnark-template-editor-autocorr': '(automatically corrected)',
'schnark-template-editor-autofill': '(automatically added)',
'schnark-template-editor-quote': '“$1”',
'schnark-template-editor-suggestion-title': 'adopt suggestion',
'schnark-template-editor-exclam': '<strong style="color:#d33;">!</strong>',
'schnark-template-editor-suggestions': '{{PLURAL:$2|Suggestion|Suggestions}}: $1',
'schnark-template-editor-default-headline': 'Edit',
'schnark-template-editor-edit-button-text': 'Proceed',
'schnark-template-editor-default-list-head': '-Suggestions-'
},
de: {
'schnark-template-editor-autocorr': '(automatisch korrigiert)',
'schnark-template-editor-autofill': '(automatisch hinzugefügt)',
'schnark-template-editor-quote': '„$1“',
'schnark-template-editor-suggestion-title': 'Vorschlag übernehmen',
'schnark-template-editor-suggestions': '{{PLURAL:$2|Vorschlag|Vorschläge}}: $1',
'schnark-template-editor-default-headline': 'Bearbeiten',
'schnark-template-editor-edit-button-text': 'Übernehmen',
'schnark-template-editor-default-list-head': '-Vorschläge-'
},
'de-ch': {
'schnark-template-editor-quote': '«$1»'
}
};
/*jscs:enable maximumLineLength*/
function initL10N (l10n, keep) {
var i, chain = mw.language.getFallbackLanguageChain();
keep = $.grep(mw.messages.get(keep), function (val) {
return val !== null;
});
for (i = chain.length - 1; i >= 0; i--) {
if (chain[i] in l10n) {
mw.messages.set(l10n[chain[i]]);
}
}
mw.messages.set(keep);
}
function callHook (name, data) {
templateEditor.status = name;
for (var i = 0; i < templateEditor.runningPlugins.length; i++) {
templateEditor.plugins[templateEditor.runningPlugins[i]].hooks[name](data);
}
}
function register (id, short, version, hooks) {
if (templateEditor.status !== 'register') {
return false;
}
if (templateEditor.plugins[id]) {
return false;
}
if (libs.templateEditor.qunit) {
if (id.indexOf('QUnit') !== 0) {
return false;
}
} else {
if (id.indexOf('QUnit') === 0) {
return false;
}
}
templateEditor.plugins[id] = {
short: short,
version: version,
hooks: {},
elements: {}
};
//jscs:disable
templateEditor.plugins[id].hooks.start = hooks.onStart || function () {return false;};
//jscs:enable
templateEditor.plugins[id].hooks.ready = hooks.onReady || function () {};
templateEditor.plugins[id].hooks.finish = hooks.onFinish || function () {};
return getFunctions(id);
}
function getFunctions (id) {
if (!(id in templateEditor.plugins)) {
return false;
}
return {
getFunctions: getFunctions,
getVersion: getVersion,
start: function (data) {
return begin(id, data);
},
addInput: function (id2, data) {
if (id2 in templateEditor.plugins[id].elements) {
return null;
}
return addInput(id, id2, data);
},
addRow: addRow,
addFootitem: addFootitem,
setVal: function (id2, val) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
return setVal(id, id2, val);
},
getVal: function (id2) {
if (id2 !== undefined && !(id2 in templateEditor.plugins[id].elements)) {
return null;
}
return getVal(id, id2);
},
get$: function (id2, el) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
return get$(id, id2, el);
},
setSuggestions: function (id2, suggestions) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
setSuggestions(id, id2, suggestions);
},
setList: function (id2, list, title, origval) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
setList(id, id2, list, title, origval);
},
setWarning: function (id2, warning) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
setWarning(id, id2, warning);
},
getWarning: function (id2) {
if (!(id2 in templateEditor.plugins[id].elements)) {
return null;
}
return getWarning(id, id2);
},
getTitle: getTitle,
getText: getText,
setText: setText,
addComment: addComment,
setNotMinor: setNotMinor
};
}
function getVersion (flag) {
function formatVersion (version) {
if (typeof version === 'number' && version === Math.floor(version)) {
return String(version) + '.0';
}
return String(version);
}
var versions = [], i, p;
if (flag === undefined) {
return templateEditor.version;
}
if (flag === false) {
versions.push(formatVersion(templateEditor.version));
for (p in templateEditor.plugins) {
if (hasOwn.call(templateEditor.plugins, p) && templateEditor.plugins[p].version) {
versions.push(templateEditor.plugins[p].short + '-' + formatVersion(templateEditor.plugins[p].version));
}
}
return versions.join('/');
}
if (flag === true) {
versions.push(formatVersion(templateEditor.version));
for (i = 0; i < templateEditor.runningPlugins.length; i++) {
versions.push(templateEditor.plugins[templateEditor.runningPlugins[i]].short + '-' +
formatVersion(templateEditor.plugins[templateEditor.runningPlugins[i]].version));
}
return versions.join('/');
}
if (!templateEditor.plugins[flag]) {
return null;
}
return templateEditor.plugins[flag].version;
}
function begin (id, data) {
if (templateEditor.started) {
return false;
}
templateEditor.started = true;
callAPI(function () {
initL10N(l10n, ['comma-separator']);
templateEditor.status = 'start';
var order, orders = {}, plugin, headline, redirect;
for (plugin in templateEditor.plugins) {
if (hasOwn.call(templateEditor.plugins, plugin)) {
if (plugin === id) {
order = data.order || 0;
} else {
order = templateEditor.plugins[plugin].hooks.start({id: id, data: data});
}
if (order || plugin === id) {
templateEditor.runningPlugins.push(plugin);
orders[plugin] = order;
}
}
}
templateEditor.runningPlugins.sort(function (a, b) {
return orders[a] - orders[b];
});
headline = data.headline;
redirect = data.redirect;
if (headline === undefined) {
headline = mw.msg('schnark-template-editor-default-headline');
}
if (redirect === undefined) {
redirect = true;
}
start(headline, data.$, redirect);
});
return true;
}
function getDataEdit () {
if (window.ve && ve.init && ve.init.target && ve.init.target.active) {
templateEditor.ve = ve.init.target;
return getDataVE();
}
return $.getJSON(mw.util.wikiScript('api'), {
action: 'query',
titles: mw.config.get('wgPageName'),
prop: 'info|revisions',
rvprop: 'content|timestamp',
rvslots: 'main',
inprop: 'watched',
curtimestamp: true,
format: 'json',
formatversion: 2
});
}
function getDataVE () {
var target = templateEditor.ve;
return target.serialize(target.getSurface().getDom()).then(function (data) {
return {
query: {
pages: [{
revisions: [{
timestamp: target.baseTimeStamp,
slots: {
main: {
content: data.content.replace(/\r?\n/g, '\n')
}
}
}],
watched: !!$('#ca-unwatch').length
}]
},
curtimestamp: target.startTimeStamp
};
});
}
function prepareData (json) {
var page = json.query.pages[0];
if (page.watched) {
templateEditor.editData.watch = true;
}
templateEditor.editData.starttime = json.curtimestamp;
templateEditor.editData.edittime = page.revisions[0].timestamp;
if (!libs.templateEditor.qunit) {
templateEditor.editData.starttime = templateEditor.editData.starttime.replace(/\D/g, '');
templateEditor.editData.edittime = templateEditor.editData.edittime.replace(/\D/g, '');
}
setText(page.revisions[0].slots.main.content);
}
function callAPI (callback) {
if (libs.templateEditor.qunit) {
//synchron, alle Module wurden im QUnit-Test schon geladen
prepareData({
query: {
pages: [{
revisions: [{
timestamp: 'edittime',
slots: {
main: {
content: 'text'
}
}
}]
}]
},
curtimestamp: 'starttime'
});
callback();
return;
}
mw.loader.load(['mediawiki.language', 'mediawiki.jqueryMsg']);
mw.loader.using('mediawiki.util').then(function () {
getDataEdit().then(function (json) {
if (!json || !json.query || !json.query.pages) {
return;
}
prepareData(json);
mw.loader.using(['mediawiki.language', 'mediawiki.jqueryMsg']).then(callback);
});
});
}
function start (headline, $el, redirect) {
initInterface(headline, $el);
if (!libs.templateEditor.qunit && !templateEditor.ve && redirect && mw.config.get('wgIsRedirect')) {
$.get(
mw.util.getUrl(
$('.redirectText').first().find('a').last().attr('title'), {
action: 'render'
}
)
).then(function (html) {
var $div = $('<div>').html(html);
mw.hook('wikipage.content').fire($div);
$('.redirectMsg').first().after($div);
});
}
}
function setWikitextVE (wikitext, summary) {
var target = ve.init.target, surface = target.getSurface(), surfaceModel;
target.initialSummary = summary;
if (surface.getMode() !== 'source') {
target.reloadSurface('visual',
mw.libs.ve.targetLoader.requestParsoidData(target.pageName, {
oldId: target.revid,
targetName: 'schnark-templateEditor',
modified: true,
wikitext: wikitext
})
);
} else {
surfaceModel = surface.getModel();
surfaceModel.setLinearSelection(
new ve.Range(0, surfaceModel.getDocument().data.getLength())
);
surfaceModel.getFragment().insertContent(wikitext).collapseToStart().select();
}
}
function doEdit () {
callHook('finish');
var $form, form,
text = getText(),
comment = templateEditor.editData.comments.join(', '),
minor = templateEditor.editData.minor,
watch = templateEditor.editData.watch,
starttime = templateEditor.editData.starttime,
edittime = templateEditor.editData.edittime;
if (templateEditor.ve) {
templateEditor.oowin.close();
setWikitextVE(text, comment);
templateEditor.started = false;
templateEditor.status = 'register';
templateEditor.$footer = null;
templateEditor.footitems = [];
templateEditor.$tbody = null;
templateEditor.targets = [];
templateEditor.runningPlugins = [];
$.each(templateEditor.plugins, function (id, data) {
data.elements = {};
});
templateEditor.oowin.simpleWindowContent.remove();
return;
}
form =
mw.html.element('textarea', {name: 'wpTextbox1'}, '\n' + text) +
mw.html.element('input', {type: 'hidden', name: 'wpSummary', value: comment}) +
mw.html.element('input', {type: 'checkbox', name: 'wpMinoredit', value: 1, checked: minor}) +
mw.html.element('input', {type: 'checkbox', name: 'wpWatchthis', value: 1, checked: watch}) +
mw.html.element('input', {type: 'hidden', name: 'wpEdittime', value: edittime}) +
mw.html.element('input', {type: 'hidden', name: 'wpStarttime', value: starttime}) +
mw.html.element('input', {type: 'hidden', name: 'wpDiff', value: 'wpDiff'}) +
mw.html.element('input', {type: 'hidden', name: 'wpUltimateParam', value: 1});
$form = $(mw.html.element('form', {
style: 'display: none;', method: 'post', enctype: 'multipart/form-data',
action: mw.config.get('wgScript') + '?' + $.param({title: mw.config.get('wgPageName'), action: 'submit'})
}, new mw.html.Raw(form)));
$('body').append($form);
if (!libs.templateEditor.qunit) {
$form.trigger('submit');
}
}
function initInterface (headline, $el) {
if (!$el) {
$el = $('<div>');
if (templateEditor.ve) {
$('body').append($el.addClass('oo-ui-element-hidden')); //add to DOM, but hide
mw.loader.using(['oojs', 'oojs-ui']).then(function () {
showAsDialog($el.removeClass('oo-ui-element-hidden'));
});
} else {
$('#siteSub').after($el);
}
}
var editButton = mw.html.element('input', {
type: 'button', 'class': 'templateEditorButton',
value: mw.msg('schnark-template-editor-edit-button-text')
}),
html = '<table class="templateEditor-table">' +
'<thead><tr>' + mw.html.element('th', {colspan: 2}, headline) +
'<td>' + editButton + '</td></tr></thead>' +
'<tbody></tbody>' +
'<tfoot><tr><td class="templateEditor-foot" colspan="2"></td>' +
'<td>' + editButton + '</td></tr></tfoot>' +
'</table>';
$el.html(html);
templateEditor.$footer = $el.find('tfoot').find('td.templateEditor-foot');
templateEditor.$tbody = $el.find('tbody');
$el.find('.templateEditorButton').on('click', doEdit);
$el.on('click', '.templateEditor-suggestion', function (e) {
var $this = $(this),
target = templateEditor.targets[$this.attr('data-template-editor-target')],
text = $this.find('.templateEditor-suggestion-inner').text();
setVal(target[0], target[1], text).trigger('change');
e.preventDefault();
});
callHook('ready');
}
function showAsDialog ($el) {
function SimpleWindow ($el) {
SimpleWindow.parent.call(this, {size: 'larger'});
$el.css('padding', '2em'); //FIXME properly call resize
setTimeout(function () {
$el.css('padding', '');
}, 1000);
this.simpleWindowContent = $el;
}
OO.inheritClass(SimpleWindow, OO.ui.Dialog);
SimpleWindow.static.name = 'schnark-templateEditor';
SimpleWindow.prototype.initialize = function () {
SimpleWindow.parent.prototype.initialize.call(this);
this.$body.append(this.simpleWindowContent);
};
var windowManager = new OO.ui.WindowManager(), win = new SimpleWindow($el);
$('body').append(windowManager.$element);
windowManager.addWindows([win]);
windowManager.openWindow(win);
templateEditor.oowin = win;
}
function addInput (id1, id2, options) {
var opt = $.extend({
type: 'text', autofill: false,
autocorr: function (val) {
return val;
}
}, options),
html, id = ('templateEditor-input-' + id1 + '-' + id2).replace(/[^a-zA-Z0-9\-]/g, '-'),
$el, $input, $warning, $additional, $list;
if (opt.type === 'text') {
html = '<tr style="vertical-align:top;">' + mw.html.element('td', {}, new mw.html.Raw(opt.text)) +
mw.html.element('td', {}, new mw.html.Raw(
mw.html.element('input', {id: id, type: 'text', value: '', size: '70'})
)) +
mw.html.element('td', {}, new mw.html.Raw(
mw.html.element('span', {style: 'margin-right:1em;', 'class': 'templateEditor-comment'}, '') +
mw.html.element('span', {'class': 'templateEditor-additional'}, '') +
mw.html.element('div', {'class': 'templateEditor-list'}, '')
)) + '</tr>';
} else {
html = '<tr style="vertical-align:top;">' + mw.html.element('td', {}, '') +
mw.html.element('td', {}, new mw.html.Raw(
mw.html.element('input', {id: id, type: 'checkbox'}) +
mw.html.element('label', {'for': id}, new mw.html.Raw(opt.text))
)) +
mw.html.element('td', {}, new mw.html.Raw(
mw.html.element('span', {style: 'margin-right:1em;', 'class': 'templateEditor-comment'}, '') +
mw.html.element('span', {'class': 'templateEditor-additional'}, '') +
mw.html.element('div', {'class': 'templateEditor-list'}, '')
)) + '</tr>';
}
$el = $(html);
$input = $el.find('#' + id);
$warning = $el.find('.templateEditor-comment');
$additional = $el.find('.templateEditor-additional');
$list = $el.find('.templateEditor-list');
templateEditor.plugins[id1].elements[id2] = {
opt: opt,
$: {input: $input, warning: $warning, additional: $additional, list: $list},
warning: '',
origval: (opt.type === 'text') ? '' : false,
suggestion: null
};
templateEditor.$tbody.append($el);
if (opt.val) {
templateEditor.plugins[id1].elements[id2].origval = opt.val;
setVal(id1, id2, opt.val);
}
$input.on('change', function () {
if (getWarning(id1, id2) === makeWarning('autofill')) {
setWarning(id1, id2, getVal(id1, id2) === '' ? makeWarning('empty') : '');
}
setSuggestions(id1, id2, templateEditor.plugins[id1].elements[id2].suggestion);
});
return $additional;
}
function addRow ($row) {
templateEditor.$tbody.append($row);
return $row;
}
function addFootitem (html) {
templateEditor.footitems.push(html);
templateEditor.$footer.html(templateEditor.footitems.join(' • '));
}
function setVal (id1, id2, val) {
var opt = templateEditor.plugins[id1].elements[id2].opt,
$input = templateEditor.plugins[id1].elements[id2].$.input,
newVal = opt.autocorr(val);
if (newVal !== val && getWarning(id1, id2) === '') {
setWarning(id1, id2, makeWarning('autocorr'));
}
if (opt.type === 'text') {
$input.val(newVal);
} else {
$input.prop('checked', newVal);
}
return $input;
}
function getVal (id1, id2) {
var vals = {}, id, opt, $input, val;
if (id2 === undefined) {
for (id in templateEditor.plugins[id1].elements) {
if (hasOwn.call(templateEditor.plugins[id1].elements, id)) {
vals[id] = getVal(id1, id);
}
}
return vals;
}
opt = templateEditor.plugins[id1].elements[id2].opt;
$input = templateEditor.plugins[id1].elements[id2].$.input;
if (opt.type === 'text') {
val = $input.val() || '';
} else {
val = $input.prop('checked');
}
return opt.autocorr(val);
}
function get$ (id1, id2, item) {
return templateEditor.plugins[id1].elements[id2].$[item || 'input'];
}
function setSuggestions (id1, id2, suggestions) {
var oldWarn, opt, target, suggestionList = [], i;
templateEditor.plugins[id1].elements[id2].suggestion = suggestions;
if (suggestions === null) {
suggestions = [];
}
if (!Array.isArray(suggestions)) {
suggestions = [suggestions];
}
oldWarn = getWarning(id1, id2);
if (oldWarn === makeWarning('autofill')) {
setVal(id1, id2, ''); //reset
}
if (suggestions.length === 0) {
if (oldWarn !== makeWarning('autocorr')) {
setWarning(id1, id2, '');
}
return;
}
opt = templateEditor.plugins[id1].elements[id2].opt;
if (
suggestions.length === 1 && opt.autofill && suggestions[0] !== '' &&
getVal(id1, id2) === '' && oldWarn !== makeWarning('empty')
) {
setVal(id1, id2, suggestions[0]);
setWarning(id1, id2, makeWarning('autofill'));
return;
}
if (suggestions.length === 1 && getVal(id1, id2) === suggestions[0]) {
if (get$(id1, id2, 'warning').find('.templateEditor-suggestion').length > 0) {
setWarning(id1, id2, '');
}
return;
}
target = templateEditor.targets.length;
templateEditor.targets[target] = [id1, id2];
for (i = 0; i < suggestions.length; i++) {
suggestionList.push(
mw.html.element('a', {
'class': 'templateEditor-suggestion internal',
title: mw.msg('schnark-template-editor-suggestion-title'),
href: '#', 'data-template-editor-target': target
}, new mw.html.Raw(
mw.msg('schnark-template-editor-quote',
mw.html.element('span', {
'class': 'templateEditor-suggestion-inner'
}, suggestions[i])
)
))
);
}
setWarning(id1, id2, ' ' + mw.msg('schnark-template-editor-exclam') + ' ' +
mw.msg('schnark-template-editor-suggestions',
suggestionList.join(mw.msg('comma-separator')),
suggestionList.length
)
);
}
function setList (id1, id2, list, title, origval) {
var $list = templateEditor.plugins[id1].elements[id2].$.list, html, i;
if (list.length === 0) {
$list.html('');
return;
}
if (origval === undefined) {
origval = templateEditor.plugins[id1].elements[id2].origval;
}
if (title === undefined) {
title = mw.msg('schnark-template-editor-default-list-head');
}
html = '<select size="1">';
html += mw.html.element('option', {value: origval}, title);
for (i = 0; i < list.length; i++) {
html += mw.html.element('option', {value: list[i][1]}, list[i][0]);
}
html += '</select>';
$list.html(html)
.find('select').on('change', function () {
setVal(id1, id2, this.value).trigger('change');
});
}
function makeWarning (type) {
var warnings = {
autocorr: '<span> ' + mw.msg('schnark-template-editor-autocorr') + '</span>',
autofill: '<span> ' + mw.msg('schnark-template-editor-autofill') + '</span>',
empty: '<span style="display:none;">geleert</span>' //für interne Zwecke
};
return warnings[type];
}
function setWarning (id1, id2, warning) {
templateEditor.plugins[id1].elements[id2].warning = warning;
templateEditor.plugins[id1].elements[id2].$.warning.html(warning);
}
function getWarning (id1, id2) {
return templateEditor.plugins[id1].elements[id2].warning;
}
function getTitle () {
return templateEditor.editData.title;
}
function setTitle (title) {
templateEditor.editData.title = title;
}
function getText () {
return templateEditor.editData.text;
}
function setText (text) {
templateEditor.editData.text = text;
}
function addComment (comment) {
templateEditor.editData.comments.push(comment);
}
function setNotMinor () {
templateEditor.editData.minor = false;
}
setTitle(mw.config.get('wgTitle'));
libs.templateEditor = register;
mw.hook('userjs.load-script.templateEditor').fire(register);
})(jQuery, mediaWiki, mediaWiki.libs);
//</nowiki>