MediaWiki:Gadget-QuickEdit.js: различия между версиями
Перейти к навигации
Перейти к поиску
Нет описания правки |
локализация |
||
| Строка 94: | Строка 94: | ||
$('<col>').addClass('diff-content') | $('<col>').addClass('diff-content') | ||
) | ) | ||
).append(r.compare['*']) : ' | ).append(r.compare['*']) : 'Нет различий.'; | ||
}).then(getPreviewCallback(editor)); | }).then(getPreviewCallback(editor)); | ||
} | } | ||
| Строка 183: | Строка 183: | ||
minor = new OO.ui.CheckboxInputWidget(), | minor = new OO.ui.CheckboxInputWidget(), | ||
save = new OO.ui.ButtonInputWidget({ | save = new OO.ui.ButtonInputWidget({ | ||
label: ' | label: 'Сохранить', | ||
title: ' | title: 'Сохранить изменения', | ||
flags: ['primary', 'progressive'], | flags: ['primary', 'progressive'], | ||
accessKey: 's' | accessKey: 's' | ||
}), | }), | ||
preview = new OO.ui.ButtonInputWidget({ | preview = new OO.ui.ButtonInputWidget({ | ||
label: ' | label: 'Предпросмотр', | ||
title: ' | title: 'Предварительный просмотр вики-текста' | ||
}), | }), | ||
compare = new OO.ui.ButtonInputWidget({ | compare = new OO.ui.ButtonInputWidget({ | ||
label: ' | label: 'Сравнить', | ||
title: ' | title: 'Показать различия между текущей версией и вашей' | ||
}), | }), | ||
cancel = new OO.ui.ButtonInputWidget({ | cancel = new OO.ui.ButtonInputWidget({ | ||
useInputTag: true, | useInputTag: true, | ||
label: ' | label: 'Отмена', | ||
title: ' | title: 'Закрыть форму редактирования и отменить изменения', | ||
flags: ['secondary', 'destructive'] | flags: ['secondary', 'destructive'] | ||
}), | }), | ||
more = new OO.ui.ButtonInputWidget({ | more = new OO.ui.ButtonInputWidget({ | ||
label: '+', | label: '+', | ||
title: ' | title: 'Редактировать весь раздел (включая подразделы)' | ||
}), | }), | ||
buttons = new OO.ui.HorizontalLayout({ | buttons = new OO.ui.HorizontalLayout({ | ||
| Строка 231: | Строка 231: | ||
var fullText = textarea.getValue() + (expanded ? '' : remainder); | var fullText = textarea.getValue() + (expanded ? '' : remainder); | ||
saving = true; | saving = true; | ||
save.setLabel(' | save.setLabel('Сохранение...'); | ||
compare.setDisabled(true); | compare.setDisabled(true); | ||
preview.setDisabled(true); | preview.setDisabled(true); | ||
| Строка 279: | Строка 279: | ||
more.setDisabled(expanded); | more.setDisabled(expanded); | ||
saving = false; | saving = false; | ||
save.setLabel(' | save.setLabel('Сохранить'); | ||
}); | }); | ||
}); | }); | ||
| Строка 337: | Строка 337: | ||
display: 'table-cell', | display: 'table-cell', | ||
verticalAlign: 'middle' | verticalAlign: 'middle' | ||
}).html(' | }).html('Описание правки:'), | ||
summary.$element.css({ | summary.$element.css({ | ||
width: '100%', | width: '100%', | ||
| Строка 346: | Строка 346: | ||
}), | }), | ||
new OO.ui.FieldLayout(minor, { | new OO.ui.FieldLayout(minor, { | ||
label: new OO.ui.HtmlSnippet(' | label: new OO.ui.HtmlSnippet('Малая правка?'), | ||
align: 'inline' | align: 'inline' | ||
}).$element.css({ | }).$element.css({ | ||
| Строка 364: | Строка 364: | ||
padding: '0px 8px 8px' | padding: '0px 8px 8px' | ||
}).append( | }).append( | ||
' | 'Редактирование страницы: ', | ||
$('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).css({ | $('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).css({ | ||
fontWeight: 'bold' | fontWeight: 'bold' | ||
| Строка 422: | Строка 422: | ||
width: '50%', | width: '50%', | ||
paddingTop: '4px' | paddingTop: '4px' | ||
}).text(' | }).text('Их версия (которая будет сохранена)'), | ||
$('<th>').css({ | $('<th>').css({ | ||
width: '50%', | width: '50%', | ||
paddingTop: '4px' | paddingTop: '4px' | ||
}).text(' | }).text('Ваша версия') | ||
), | ), | ||
$('<tr>').append( | $('<tr>').append( | ||
| Строка 478: | Строка 478: | ||
mobile ? '' : '<span class="quickedit-section"> | </span>', | mobile ? '' : '<span class="quickedit-section"> | </span>', | ||
$('<a>') | $('<a>') | ||
.html(mobile ? ' Q' : ' | .html(mobile ? ' Q' : 'быстрая правка') | ||
.addClass('quickedit-section quickedit-editlink') | .addClass('quickedit-section quickedit-editlink') | ||
.attr('href', '#') | .attr('href', '#') | ||
Версия от 23:55, 24 мая 2026
/** Quick Edit **/
// Edit sections of a page without leaving the article
// [[en:w:User:BrandonXLF/QuickEdit]]
// By [[en:w:User:BrandonXLF]]
(function() {
var mobile = mw.config.get('skin') === 'minerva',
apiSingleton,
titleRegexp = new RegExp(
mw.config.get('wgArticlePath').replace(/[.*+?^${}()|[\]\\]/g, '\\$&').replace(/\\\$1/, '([^?]+)') +
'|[?&]title=([^&#]*)'
);
function api(func, params) {
if (!apiSingleton) apiSingleton = new mw.Api();
$.extend(params, {
errorformat: 'html',
errorlang: mw.config.get('wgUserLanguage'),
errorsuselocal: true
});
return apiSingleton[func](params).fail(function(_, data) {
mw.notify(apiSingleton.getErrorMessage(data), {
type: 'error',
tag: 'quickedit'
});
});
}
function getPageInfo(title, sectionID) {
return api('get', {
action: 'query',
curtimestamp: 1,
prop: 'revisions',
indexpageids: 1,
titles: title,
rvprop: ['timestamp', 'content'],
rvslots: 'main',
rvsection: sectionID
}).then(function(res) {
var rev = res.query.pages[res.query.pageids[0]].revisions[0];
return {
start: res.curtimestamp,
base: rev.timestamp,
full: rev.slots.main['*']
};
});
}
function getPreviewCallback(editor) {
editor.children('.preview').remove();
new OO.ui.ProgressBarWidget().$element.css({
maxWidth: '100%',
borderRadius: '0',
boxShadow: 'none',
margin: '8px 0'
}).addClass('preview').appendTo(editor);
return function(html) {
editor.children('.preview').remove();
$('<div>').html(html).css({
margin: '8px 0',
border: '1px solid #a2a9b1',
padding: '8px',
overflowX: 'hidden'
}).addClass('preview').appendTo(editor);
};
}
function showCompare(editor, title, from, to) {
mw.loader.load('mediawiki.diff.styles');
api('post', {
action: 'compare',
fromslots: 'main',
'fromtext-main': from,
fromtitle: title,
frompst: 'true',
toslots: 'main',
'totext-main': to,
totitle: title,
topst: 'true'
}).then(function(r) {
return r.compare['*'] ? $('<table>').addClass('diff').append(
$('<colgroup>').append(
$('<col>').addClass('diff-marker'),
$('<col>').addClass('diff-content'),
$('<col>').addClass('diff-marker'),
$('<col>').addClass('diff-content')
)
).append(r.compare['*']) : 'Нет различий.';
}).then(getPreviewCallback(editor));
}
// Parts taken from EditPage::extractSectionTitle and Parser::stripSectionName
function getSectionSummary(text) {
var match = text.match(/^(=+)(.+)\1\s*(\n|$)/);
return !match ? '' : '/* ' + match[2].trim()
// Strip internal link markup
.replace(/\[\[:?([^[|]+)\|([^[]+)\]\]/g, '$2')
.replace(/\[\[:?([^[]+)\|?\]\]/g, '$1')
// Strip external link markup
.replace(new RegExp('\\[(?:' + mw.config.get('wgUrlProtocols') + ')([^ ]+?) ([^\\[]+)\\]', 'ig'), '$2')
// Remove wikitext quotes
.replace(/(''|'''|''''')(?!')/g, '')
// Strip HTML tags
.replace(/<[^>]+?>/g, '') + ' */ ';
}
function showEditor(el) {
var progress = new OO.ui.ProgressBarWidget(),
// https://www.mediawiki.org/wiki/Heading_HTML_changes
// Cannot use .closest() because DiscussionTools nests an h2 within a .mw-heading
heading = el.parents(':header, .mw-heading').last(),
matcher = heading.nextUntil.bind(heading),
inserter = heading.after.bind(heading),
targetEl = el.siblings('.quickedit-target').last(),
titleMatch = targetEl.attr('href').match(titleRegexp),
title = decodeURIComponent(titleMatch[1] || titleMatch[2]),
sectionID = /[?&]v?e?section=T?-?(\d*)/.exec(targetEl.attr('href'))[1];
if (!heading.closest('.mw-parser-output').length) {
var articleContent = $('#mw-content-text .mw-parser-output');
matcher = function(selector) {
var child = articleContent.children(selector).first();
if (child.length) return child.prevAll();
return articleContent.children();
};
inserter = articleContent.prepend.bind(articleContent);
}
inserter(progress.$element.css({
maxWidth: '100%',
borderRadius: '0',
boxShadow: 'none'
}));
el.addClass('quickedit-loading');
$('.quickedit-hide').removeClass('quickedit-hide');
$('.quickedit-heading').removeClass('quickedit-heading');
$('#quickedit-editor').remove();
getPageInfo(title, sectionID).then(function(r) {
var start = r.start,
base = r.base,
full = r.full,
saving = false,
expanded = false,
remainderStart = full.match(/\n=+.+=+(?:\n|$)/),
part = remainderStart ? full.substring(0, remainderStart.index) : full,
remainder = remainderStart ? full.substring(remainderStart.index) : '',
level = 0,
editor;
full.replace(/^(=+).+?(=+)(?:\n|$)/, function(m, a, b) {
level = Math.min(a.length, b.length);
return m;
});
var levelMatch = 'h1';
for (var i = 2; i <= level; i++)
levelMatch += ',h' + i + ':has(*), .mw-heading' + i;
var partSection = matcher(':header:has(*), .mw-heading'),
fullSection = matcher(levelMatch),
textarea = new OO.ui.MultilineTextInputWidget({
rows: 1,
maxRows: 20,
autosize: true,
value: part
}),
summary = new OO.ui.TextInputWidget({
value: getSectionSummary(part)
}),
minor = new OO.ui.CheckboxInputWidget(),
save = new OO.ui.ButtonInputWidget({
label: 'Сохранить',
title: 'Сохранить изменения',
flags: ['primary', 'progressive'],
accessKey: 's'
}),
preview = new OO.ui.ButtonInputWidget({
label: 'Предпросмотр',
title: 'Предварительный просмотр вики-текста'
}),
compare = new OO.ui.ButtonInputWidget({
label: 'Сравнить',
title: 'Показать различия между текущей версией и вашей'
}),
cancel = new OO.ui.ButtonInputWidget({
useInputTag: true,
label: 'Отмена',
title: 'Закрыть форму редактирования и отменить изменения',
flags: ['secondary', 'destructive']
}),
more = new OO.ui.ButtonInputWidget({
label: '+',
title: 'Редактировать весь раздел (включая подразделы)'
}),
buttons = new OO.ui.HorizontalLayout({
items: [save, preview, compare, cancel]
});
if (part != full) {
buttons.addItems([more], 3);
}
partSection.addClass('quickedit-hide');
heading.addClass('quickedit-heading');
el.removeClass('quickedit-loading');
progress.$element.remove();
textarea.$input.css({
borderRadius: '0'
});
summary.on('enter', function() {
save.emit('click');
});
save.on('click', function() {
if (saving) return;
var fullText = textarea.getValue() + (expanded ? '' : remainder);
saving = true;
save.setLabel('Сохранение...');
compare.setDisabled(true);
preview.setDisabled(true);
cancel.setDisabled(true);
more.setDisabled(true);
api('postWithEditToken', {
action: 'edit',
title: title,
section: sectionID,
summary: summary.getValue(),
text: fullText,
minor: minor.isSelected() ? true : undefined,
notminor: minor.isSelected() ? undefined : true,
starttimestamp: start,
basetimestamp: base
}).then(function() {
api('get', {
action: 'parse',
page: mw.config.get('wgPageName'),
prop: ['text', 'categorieshtml']
}).then(function(r) {
var contentText = $('#mw-content-text'),
catLinks = $('#catlinks');
contentText.find('.mw-parser-output').replaceWith(r.parse.text['*']);
mw.hook('wikipage.content').fire(contentText);
catLinks.replaceWith(r.parse.categorieshtml['*']);
mw.hook('wikipage.categories').fire(catLinks);
saving = false;
});
}, function(code) {
if (code == 'editconflict') {
showEditConflict(editor, title, sectionID, fullText).then(function(r) {
start = r.start;
base = r.base;
textarea = r.textarea;
expanded = true;
});
}
compare.setDisabled(false);
preview.setDisabled(false);
cancel.setDisabled(false);
more.setDisabled(expanded);
saving = false;
save.setLabel('Сохранить');
});
});
preview.on('click', function() {
api('post', {
action: 'parse',
title: title,
prop: 'text',
pst: 'true',
disablelimitreport: 'true',
disableeditsection: 'true',
sectionpreview: 'true',
disabletoc: 'true',
text: textarea.getValue()
}).then(function(r) {
return r.parse.text['*'] + '<div style="clear:both;"></div>';
}).then(getPreviewCallback(editor));
});
compare.on('click', function() {
showCompare(editor, title, part + (expanded ? remainder : ''), textarea.getValue());
});
cancel.on('click', function() {
editor.remove();
heading.removeClass('quickedit-heading');
fullSection.removeClass('quickedit-hide');
});
more.on('click', function() {
expanded = true;
textarea.setValue(textarea.getValue() + remainder);
fullSection.addClass('quickedit-hide');
more.setDisabled(true);
});
editor = $('<div id="quickedit-editor">').css({
overflowX: 'hidden'
}).append(
$('<div>').css({
backgroundColor: '#eaecf0',
borderBottom: '1px solid #a2a9b1',
marginBottom: '8px'
}).append(
textarea.$element.css({
width: '100%',
maxWidth: '100%',
fontFamily: 'monospace, monospace'
}).addClass('quickedit-textarea'),
$('<div>').css({
border: '1px solid #a2a9b1',
borderWidth: '0 1px'
}).append(
$('<div>').css({
padding: '8px 4px 8px 8px',
display: 'table-cell',
verticalAlign: 'middle'
}).html('Описание правки:'),
summary.$element.css({
width: '100%',
maxWidth: '100%',
padding: '8px 0px',
display: 'table-cell',
verticalAlign: 'middle'
}),
new OO.ui.FieldLayout(minor, {
label: new OO.ui.HtmlSnippet('Малая правка?'),
align: 'inline'
}).$element.css({
padding: '8px 8px 8px 4px',
display: 'table-cell',
verticalAlign: 'middle'
})
),
buttons.$element.css({
border: '1px solid #a2a9b1',
borderWidth: '0 1px',
padding: '0 8px 8px 8px'
}),
title !== mw.config.get('wgPageName') ? $('<div>').css({
border: '1px solid #a2a9b1',
borderWidth: '0 1px',
padding: '0px 8px 8px'
}).append(
'Редактирование страницы: ',
$('<a>').attr('href', mw.config.get('wgArticlePath').replace('$1', title)).css({
fontWeight: 'bold'
}).text(title.replace(/_/g, ' '))
) : undefined
)
);
inserter(editor);
}, function() {
el.removeClass('quickedit-loading');
progress.$element.remove();
});
}
function showEditConflict(editor, title, sectionID, text) {
return getPageInfo(title, sectionID).then(function(r) {
var textarea = new OO.ui.MultilineTextInputWidget({
rows: 1,
maxRows: 20,
autosize: true,
value: r.full
}),
textarea2 = new OO.ui.MultilineTextInputWidget({
rows: 1,
maxRows: 20,
autosize: true,
value: text,
});
function syncSize() {
textarea.styleHeight = -1;
textarea.adjustSize(true);
textarea2.styleHeight = -1;
textarea2.adjustSize(true);
var height = Math.max(textarea.$input.height(), textarea2.$input.height());
textarea.$input.height(height);
textarea2.$input.height(height);
}
textarea.$input.css({
borderRadius: '0'
});
editor.find('> :first-child > :first-child').remove();
$('<table>').css({
width: '100%',
border: '1px solid #a2a9b1',
borderBottom: 'none',
borderSpacing: '0',
margin: '0 !important'
}).append(
$('<tr>').append(
$('<th>').css({
width: '50%',
paddingTop: '4px'
}).text('Их версия (которая будет сохранена)'),
$('<th>').css({
width: '50%',
paddingTop: '4px'
}).text('Ваша версия')
),
$('<tr>').append(
$('<td>').css({
width: '50%',
padding: '4px 4px 0 8px'
}).append(
textarea.$element.css({
width: '100%',
maxWidth: '100%',
fontFamily: 'monospace, monospace'
})
),
$('<td>').css({
width: '50%',
padding: '4px 8px 0 4px'
}).append(
textarea2.$element.css({
width: '100%',
maxWidth: '100%',
fontFamily: 'monospace, monospace'
})
)
)
).prependTo(editor.find('> :first-child'));
textarea.on('change', syncSize);
textarea2.on('change', syncSize);
syncSize();
showCompare(editor, title, text, r.full);
r.textarea = textarea;
return r;
});
}
function clickHandler(e) {
var el = $(e.target);
if (!el.hasClass('quickedit-editlink') || el.hasClass('quickedit-loading')) return;
e.preventDefault();
showEditor(el);
}
function addLinksToChildren(element) {
element.find('#quickedit-editor, .quickedit-section').remove();
element.find('.mw-editsection').each(function() {
$('[href*="section="]', this).last().after(
mobile ? '' : '<span class="quickedit-section"> | </span>',
$('<a>')
.html(mobile ? ' Q' : 'быстрая правка')
.addClass('quickedit-section quickedit-editlink')
.attr('href', '#')
).addClass('quickedit-target');
});
}
$.when(mw.loader.using('oojs-ui-core'), $.ready).done(function() {
var body = $(document.body);
body.on('click', clickHandler);
addLinksToChildren(body);
mw.hook('wikipage.content').add(addLinksToChildren);
});
mw.loader.addStyleTag(
'.skin-minerva .mw-editsection { white-space: nowrap; }' +
'.skin-minerva .content .collapsible-heading .quickedit-section { visibility: hidden; }' +
'.skin-minerva .content .collapsible-heading.open-block .quickedit-section { visibility: visible; }' +
'.quickedit-hide { display: none !important; }' +
'.quickedit-loading, .quickedit-heading { color: #777; }'
);
})();