MediaWiki:Gadget-AlignTemplateParameters.js
Арахьара хатӀ
Билгалдаккхар: Ӏалашйинчул тӀаьхьа браузеран кеш дӀайаккха йезаш хила мега, хийцамаш ган.
- Firefox / Safari: ГӀирсийн панелехь Shift-дӀа а лаьцна Керладаккхар тӀетаӀайе, йа Ctrl+F5 йаCtrl+R (Mac-хь ⌘+R) тӀетаӀайе.
- Google Chrome:Ctrl+Shift+R тӀетаӀайе (⌘+Shift+R Mac тӀехь)
- Edge: Ctrl дӀа а лаьцна, Refresh тӀе Ӏоттало йа Ctrl+F5 тӀе Ӏоттало.
- Opera: Ctrl+F5 тӀетаӀайе.
// <nowiki>
(function () {
// String.prototype.includes polyfill
if (!String.prototype.includes) {
Object.defineProperty(String.prototype, 'includes', {
value: function(search, start) {
if (typeof start !== 'number') {
start = 0;
}
if (start + search.length > this.length) {
return false;
} else {
return this.indexOf(search, start) !== -1;
}
}
});
}
var pageIsProbablyTemplate = [2, 10].includes(mw.config.get('wgNamespaceNumber'));
function alignTemplateParameters(settings) {
settings = settings || {};
var askOptions = settings.askOptions;
var hardMode = settings.hardMode;
var templateExpanderMode = settings.templateExpanderMode;
var codeStylerMode = settings.codeStylerMode;
var txt = '';
var hidden = [];
var $textbox = $('#wpTextbox1');
var $CodeMirrorVscrollbar = $('.CodeMirror-vscrollbar');
var winScroll = document.documentElement.scrollTop;
var i;
var selectionMode = false;
if (typeof atpMaxWidth === 'undefined') window.atpMaxWidth = 30;
if (typeof atpPreserveBasicSpacing === 'undefined') window.atpPreserveBasicSpacing = true;
if (typeof atpPreserveParameterSpacing === 'undefined') window.atpPreserveParameterSpacing = true;
if (typeof atpStandardExternalLeftSpacing === 'undefined') window.atpStandardExternalLeftSpacing = 1;
if (typeof atpStandardInternalLeftSpacing === 'undefined') window.atpStandardInternalLeftSpacing = 1;
if (typeof atpParserFunctionExternalLeftSpacing === 'undefined') window.atpParserFunctionExternalLeftSpacing = 0;
if (typeof atpParserFunctionInternalLeftSpacing === 'undefined') window.atpParserFunctionInternalLeftSpacing = 1;
if (typeof atpAutoSummary === 'undefined') window.atpAutoSummary = true;
if (atpParserFunctionExternalLeftSpacing > 1) atpParserFunctionExternalLeftSpacing = 1;
if (atpParserFunctionInternalLeftSpacing > 1) atpParserFunctionInternalLeftSpacing = 1;
if (atpStandardExternalLeftSpacing > 1) atpStandardExternalLeftSpacing = 1;
if (atpStandardInternalLeftSpacing > 1) atpStandardInternalLeftSpacing = 1;
function isMultiline(s) {
return s.includes('\n');
}
function r(r1, r2) {
txt = txt.replace(r1, r2);
}
function hide(re) {
r(re, function (s) {
return '\x01' + (isMultiline(s) ? '_' : '') + hidden.push(s) + '\x02';
});
}
function hideTag(tag) {
hide(new RegExp('<' + tag + '( [^>]+)?>[\\s\\S]+?<\\/' + tag + '>', 'gi'));
}
function prettifyTemplates() {
function prettifyTemplate() {
function localR(r1, r2) {
newTpl = newTpl.replace(r1, r2);
}
function localHide(re) {
localR(re, function (s) {
return '\x03' + localHidden.push(s) + '\x04';
});
}
function localUnhide() {
while (newTpl.match(/\x03\d+\x04/)) {
newTpl = newTpl.replace(/\x03(\d+)\x04/g, function (s, num) {
return localHidden[num - 1];
});
}
}
function isNamed(param) {
return param.includes('=');
}
function removeEndingNewlines(s) {
return s.replace(/\n+([ \t]*)$/, '');
}
function generateSpaces(num) {
return ' '.repeat(Math.max(0, num));
}
function lcFirst(s) {
if (!s) return s;
return s[0].toLowerCase() + s.substr(1);
}
function calculateOneValueDominance(arr) {
var spread = arr.reduce((obj, item) => {
obj[item] = (obj[item] || 0) + 1;
return obj;
}, {});
var topValueCount = Object.entries(spread)
.map(([, value]) => value)
.sort((a, b) => b - a)[0];
return topValueCount / arr.length;
}
var newTpl = tpl;
var multiline = isMultiline(newTpl);
newTpl = newTpl.replace(/^\{\{\s+(?!\x01)/, '{{');
if (!newTpl.match(/\{\{[a-zA-Z][^\|]*:/)) { // например, {{fullurl:...|action=edit}}
newTpl = newTpl.replace(/^([^\|]+?)\s+\}\}$/, '$1}}');
}
if (!multiline && !atpCodeStyler && !atpTemplateExpander) return newTpl;
var re, m, m2, tplName, start;
var isParserFunction = false;
var anythingBeforeTplName = '(\\x01\\d+\\x02|(?:<includeonly>)?(?:safe)?subst:(?:<\\/includeonly>|<(?:includeonly|noinclude) ?\\/>))?';
re = new RegExp('^\\{\\{' + anythingBeforeTplName + '(#\\w*)?:[ \\t]*(?=(\\n?))');
m = newTpl.match(re);
tplName = m && m[2];
if (tplName) {
isParserFunction = true;
if (codeStylerMode && tplName !== '#invoke') {
newTpl = newTpl.replace(re, '{{' + (m[1] || '') + tplName + ':' + (m[3] ? '' : ' '));
}
} else {
if (!multiline && !atpTemplateExpander) {
return newTpl;
}
m = newTpl.match(/^\{\{([^|}\n]+)/);
tplName = m && m[1].trim();
}
var localHidden = [];
var params;
if (isParserFunction && atpCodeStyler && codeStylerMode) {
localHide(/\[\[[^\]]+\]\]/g); // [[Вики-ссылки]]
params = newTpl.split('|');
params[0] = params[0].replace(/^\{\{/, '');
params[params.length - 1] = params[params.length - 1].replace(/\}\}$/, '');
var safeToSpace = false; // С неименованными пробелами отбивать пробелами небезопасно
var unnamedCount = 0;
if (tplName === '#invoke' && codeStylerMode === 'newlines') {
safeToSpace = true;
for (i = 2; i < params.length; i++) {
if (!isNamed(params[i])) {
safeToSpace = false;
break;
}
}
}
// Make #if, #ifexpr, #ifeq, #ifexist, #iferror multiline only if both arguments are non-empty, or if
// it contains nested templates / parser functions
var makeIfMultiline = codeStylerMode === 'newlines' &&
(tplName.substr(0, 3) === '#if' &&
params[1] !== undefined &&
(isMultiline(params[1]) ||
tplName === '#ifeq' ||
(params[2] !== undefined &&
isMultiline(params[2])
) ||
((params[1].trim() !== '' &&
params[2] !== undefined &&
params[2].trim() !== ''
) ||
params[1].includes('\x01_') ||
(params[2] !== undefined &&
params[2].includes('\x01_')
)
)
)
);
var isMultipleAlternativesSwitch = false;
var isOneOfSwitchAlternatives;
// FIXME: это надо рефакторить, конечно.
// Выше, видимо, safeToSpace должен мочь стать true не только при codeStylerMode === 'newlines'
if (params.length > 1) {
for (i = 1; i < params.length; i++) {
// FIXME: криво, да, что анализируется предыдущий параметр, но связано с логикой ниже
if (tplName === '#switch' && i - 1 !== 0 && !params[i - 1].includes('=')) {
isMultipleAlternativesSwitch = true;
isOneOfSwitchAlternatives = true;
} else {
isOneOfSwitchAlternatives = false;
}
if (tplName === '#switch' ||
(tplName === '#invoke' &&
(safeToSpace ||
params[i].match(/\n[ \t]*$/) &&
params[i - 1].match(/\n[ \t]*$/)
)
)
) {
params[i] = params[i].replace(/([ \t]*)=[ \t]*/, function (s, m1) {
var sp;
if (tplName === '#invoke' &&
codeStylerMode === 'newlines' &&
!isMultipleAlternativesSwitch
) {
sp = generateSpaces(i);
} else if (m1.length < 1 ||
codeStylerMode === 'newlines-collapse' ||
!(params[i].match(/\n[ \t]*$/) &&
params[i - 1].match(/\n[ \t]*$/)
) ||
isMultipleAlternativesSwitch
) {
sp = ' ';
} else {
sp = m1;
}
return sp + '= ';
});
} else if (tplName === '#invoke') {
params[i] = params[i]
.replace(/[ \t]+=/, ' =')
.replace(/=[ \t]+/, '= ');
}
if (codeStylerMode === 'newlines-collapse' && !(tplName === '#invoke' && !multiline)) {
params[i - 1] = params[i - 1].replace(/\s*$/, ' ');
// {{#if: smth |\nsmth\n}}
params[i] = params[i].replace(/^[ \t]*(?=(\n)?)/, function (s, m1) {
return m1 ? '' : ' ';
});
if (i === params.length - 1) {
params[i] = params[i].replace(/\s*$/, ' ');
}
} else if (!isMultiline(params[i - 1]) ||
params[i - 1].match(/\S[ \t]*$/) ||
(tplName === '#switch' && isOneOfSwitchAlternatives)
) {
if (codeStylerMode === 'newlines' &&
((tplName.substr(0, 3) === '#if' && makeIfMultiline) ||
(tplName === '#switch' && !isOneOfSwitchAlternatives) ||
(tplName === '#invoke' && safeToSpace && i !== 1)
)
) {
params[i - 1] = params[i - 1].replace(/[ \t]*$/, '\n');
multiline = true;
} else if (tplName === '#switch' && isOneOfSwitchAlternatives) {
params[i - 1] = ' ' + params[i - 1].trim() + ' ';
} else {
if (!(tplName === '#invoke' && !safeToSpace)) {
params[i - 1] = params[i - 1].replace(/[ \t]*$/, ' ');
} else if (isNamed(params[i - 1]) || i - 1 <= 1) {
params[i - 1] = params[i - 1].replace(/[ \t]+$/, ' ');
}
}
if (!(tplName === '#invoke' && !safeToSpace)) {
// {{#if: smth |\nsmth\n}}
params[i] = params[i].replace(/^[ \t]*(?=(\n)?)/, function (s, m1) {
return m1 ? '' : ' ';
});
} else if (isNamed(params[i]) || i === 1) {
params[i] = params[i].replace(/^[ \t]+/, ' ');
}
if (i === params.length - 1) {
if (!(tplName === '#invoke' && !safeToSpace)) {
params[i] = params[i].replace(/(\S)[ \t]*$/, '$1 ');
} else if (isNamed(params[i])) {
params[i] = params[i].replace(/(\S)[ \t]+$/, '$1 ');
}
}
}
}
} else {
params[0] = params[0].replace(/\s*$/, ' ');
}
if (tplName === '#expr' || tplName === '#ifexpr') {
params[0] = params[0]
// Не трогать +30 * -7
.replace(/: /, ':')
.replace(/[ \t]*(\+|-|\*|\/|\^|<>|!=|>=|<=|>|<|=)[ \t]*/g, ' $1 ')
.replace(/([+\-*/^=<>:])[ \t]*(\+|-) /g, '$1 $2')
.replace(/:[ \t]*/, ': ');
}
newTpl = '{{' + params.join('|') + '}}';
if (params.length > 1) {
if (tplName !== '#invoke') {
newTpl = newTpl.replace(/\|[ \t]\}\}/, '}}');
}
if (tplName === '#invoke' && (safeToSpace || codeStylerMode === 'newlines-collapse')) {
newTpl = newTpl.replace(
new RegExp('^\\{\\{' + anythingBeforeTplName + '#invoke:[ \\t]*'),
'{{$1#invoke: '
);
} else {
newTpl = newTpl.replace(
new RegExp('^\\{\\{' + anythingBeforeTplName + '#invoke:[ \\t]+'),
'{{$1#invoke: '
);
}
if (tplName !== '#switch') {
newTpl = newTpl.replace(/\| ?\|/g, '||');
}
}
localUnhide();
//console.log(newTpl);
if (!multiline) {
return newTpl;
}
}
if (!isParserFunction && atpTemplateExpander && templateExpanderMode) {
localHide(/\[\[[^\]]+\]\]/g); // [[Вики-ссылки]]
params = newTpl.split('|');
params[0] = params[0].replace(/^\{\{/, '');
params[params.length - 1] = params[params.length - 1].replace(/\}\}$/, '');
var namedCount = 0, unnamedCount = 0;
var hasCollapsed = false;
var isFullyCollapsible = true;
for (i = 1; i < params.length; i++) {
if (isNamed(params[i])) {
namedCount++;
if (!isMultiline(params[i - 1])) {
hasCollapsed = true;
}
} else {
unnamedCount++;
}
if ((isNamed(params[i]) &&
isMultiline(params[i].trim())
) ||
(!isNamed(params[i]) &&
isMultiline(params[i]) &&
params[i + 1] &&
!isNamed(params[i + 1]) &&
isMultiline(params[i + 1])
)
) {
isFullyCollapsible = false; // Можно ли свернуть в одну строчку этот шаблон
}
}
if (namedCount > 1 && !(templateExpanderMode === 'expand' && !hasCollapsed)) {
if (templateExpanderMode === 'expand') {
for (i = 0; i < params.length; i++) {
if (i === 0) {
params[i] = params[i].replace(/\s*$/, '');
}
if ((params[i + 1] &&
isNamed(params[i + 1])
) ||
(i === 0 &&
(params[i + 1] &&
params[i + 2] &&
!isNamed(params[i + 1]) &&
!isNamed(params[i + 2]) &&
isMultiline(params[i + 1])
)
) ||
(i !== 0 &&
(isNamed(params[i]) ||
lcFirst(tplName) === 'публикация'
)
)
) {
if (isNamed(params[i]) || lcFirst(tplName) === 'публикация') {
params[i] = params[i].replace(/\s*$/, '');
} else {
params[i] = removeEndingNewlines(params[i]);
}
params[i] = params[i] + '\n' + generateSpaces(stack.length * 2 + selectionSpacing) +
' ';
if (unnamedCount <= 1 && params[i + 1] && isNamed(params[i + 1])) {
params[i + 1] = ' ' + params[i + 1].trim();
}
if (i !== 0) {
// Для последующего выравнивания
params[i] = params[i].replace('=', generateSpaces(i) + '=');
}
}
}
hasCollapsed = false;
} else if (templateExpanderMode === 'collapse') {
for (i = 0; i < params.length; i++) {
if (i === 0 ||
isNamed(params[i]) ||
(params[i + 1] &&
(isNamed(params[i + 1]) ||
!isMultiline(params[i + 1])
)
) ||
(i === params.length - 1 &&
isFullyCollapsible
)
) {
if (i === 0 || isNamed(params[i])) {
if (isFullyCollapsible ||
(i !== params.length - 1 &&
!(params[i + 1] &&
!isNamed(params[i + 1]) &&
isMultiline(params[i + 1]) &&
params[i + 2] &&
!isNamed(params[i + 2]) &&
isMultiline(params[i + 2])
)
)
) {
params[i] = params[i].trim();
} else {
params[i] = params[i]
.replace(/^\s*/, '')
.replace(/\s*?(\n*)$/, '$1');
}
// Иногда неименованные параметры вытягиваются в стопку
} else if (i !== 0 && !isNamed(params[i]) && isMultiline(params[i]) &&
(isFullyCollapsible ||
params[i + 1] &&
(isNamed(params[i + 1]) ||
!isMultiline(params[i + 1])
) &&
(i === 1 ||
isNamed(params[i - 1]) ||
!isMultiline(params[i - 1])
)
)
) {
params[i] = removeEndingNewlines(params[i]);
}
}
if (i !== 0) {
params[i] = params[i].replace(/[ \t]*=[ \t]*/, '=');
}
if (!pageIsProbablyTemplate &&
(!unnamedCount &&
isNamed(params[Math.max(1, i)]) ||
(lcFirst(tplName) === 'публикация')
) // && i !== params.length - 1
) {
params[i] = params[i].replace(/ *$/, ' ');
}
}
hasCollapsed = true;
}
newTpl = '{{' + params.join('|') + '}}';
}
localUnhide();
//console.log(newTpl);
if (hasCollapsed) {
return newTpl;
}
}
m = newTpl.match(/^(\{\{[\s\S]*?\n\s*)(\||\}\})/);
if (!m) return newTpl;
start = m[1];
if (!templateExpanderMode) {
start = start.trim();
} else {
start = removeEndingNewlines(start);
}
var indentSpaces = ' '.repeat(basicLevel);
if (!refTagBefore) {
// Вставляем то или иное число пробелов в зависимости от уровня вложенности
if (isParserFunction) {
indentSpaces += generateSpaces(stack.length); // Знак «|»
indentSpaces += generateSpaces(stack.length * atpParserFunctionExternalLeftSpacing);
indentSpaces += generateSpaces(stack.length * atpParserFunctionInternalLeftSpacing);
} else {
indentSpaces += generateSpaces(stack.length * 2);
}
indentSpaces += generateSpaces(selectionSpacing);
}
var noEndingBrackets = false;
if (!newTpl.includes('}}', newTpl.length - 2)) {
newTpl += '}}';
noEndingBrackets = true;
}
if (tplName === '#switch') {
// Для правильного выравнивания «=» в «| a | b | c = value»
re = /\n([ \t]*)\|([ \t]*)(?:([^=\n]+?)([ \t]*)=([ \t]*))?([\s\S]*?)(?=(\n[ \t]*\||\}\}))/g;
} else {
re = /\n([ \t]*)\|([ \t]*)(?:([^=|\n]+?)([ \t]*)=([ \t]*))?([\s\S]*?)(?=(\n[ \t]*\||\}\}))/g;
}
params = [];
var longestParameterLength = 0;
var standardWidth = 0;
var length;
var basicExternalLeftSpacing;
var basicInternalLeftSpacing;
var oneSpaceCount = 0;
var zeroSpacesCount = 0;
var paramLeftLengths = [];
var namedParametersCount = 0;
i = 0;
while (m = re.exec(newTpl)) {
i++;
if (i === 1) {
basicExternalLeftSpacing = isParserFunction
? generateSpaces(indentSpaces.length + atpParserFunctionExternalLeftSpacing)
: m[1];
basicInternalLeftSpacing = isParserFunction
? generateSpaces(atpParserFunctionInternalLeftSpacing)
: m[2];
}
if (thisPreserveBasicSpacing) {
/* Этот код гарантирует, что:
1) внешняя левая отбивка не будет размножаться во вложенных шаблонах
2) не будет строк с меньшей внешней левой отбивкой, чем у первой строки
3) не будет внешней левой отбивки из более чем одного пробела на ровном месте */
if (i === 1) {
m[1] = '';
} else {
// Случаи, когда параметры отбиваются по отношению к базовому уровню специально.
// Но у всех аргументов парсерных функций отступ одинаковый
if (isParserFunction || !thisPreserveParameterSpacing) {
m[1] = '';
} else if (thisPreserveParameterSpacing) {
m[1] = generateSpaces(m[1].length - basicExternalLeftSpacing.length);
}
}
if (basicExternalLeftSpacing.length > indentSpaces.length) {
m[1] += ' ';
}
} else {
if (isParserFunction) {
m[1] = '';
// FIXME: криво, что стандартный отступ парсерных функций формируется через
// basicExternalLeftSpacing, а не напрямую через atpParserFunctionExternalLeftSpacing (также выше)
if (basicExternalLeftSpacing.length > indentSpaces.length) {
m[1] += ' ';
}
} else if (thisPreserveParameterSpacing) {
m[1] = generateSpaces(
atpStandardExternalLeftSpacing + m[1].length - basicExternalLeftSpacing.length
);
} else {
m[1] = generateSpaces(atpStandardExternalLeftSpacing);
}
}
if (thisPreserveBasicSpacing) {
// Аналогично для внутренней левой отбивки
if (i === 1) {
m[2] = '';
} else {
if (isParserFunction || !thisPreserveParameterSpacing) {
m[2] = '';
} else if (thisPreserveParameterSpacing) {
m[2] = generateSpaces(m[2].length - basicInternalLeftSpacing.length);
}
}
if (basicInternalLeftSpacing.length > 0) {
m[2] += ' ';
}
} else {
if (thisPreserveParameterSpacing) {
m[2] = generateSpaces(
atpStandardInternalLeftSpacing + m[2].length - basicInternalLeftSpacing.length
);
} else {
m[2] = generateSpaces(atpStandardInternalLeftSpacing);
}
}
if (!hardMode || codeStylerMode || templateExpanderMode) {
paramLeftLengths.push((m[1] + m[2] + m[3] + m[4]).length);
if (m[4] === ' ') {
oneSpaceCount++;
}
if (m[4] === '' && m[5] === '') {
zeroSpacesCount++;
}
}
if (m[3] !== undefined) {
length = m[1].length + m[2].length + m[3].length;
if (length > longestParameterLength) {
longestParameterLength = length;
}
if (!hardMode || codeStylerMode || templateExpanderMode) {
namedParametersCount++;
}
}
if (m[3] === undefined && m[6].match(/^[ \t]*\n/)) {
m[6] = m[6].replace(/^\n\s*\x01/, '\x01');
}
m[6] = m[6]
.replace(/\n\s*\n\s*$/, '\n') // В сумме 3+ переноса строки
.replace(/^[ \t]+$/, ''); // Пустой параметр (но нельзя обрезать, если там переносы)
if (m[3] !== undefined) {
m[6] = m[6]
// Оканчивающие пробелы во всех завершающих (состоящих только из пробелов) строках
.replace(/[ \t]*(\n?)[ \t]*$/, '$1')
// Оканчивающий пробел в параметрах lat_*, lon_* и т. п.
.replace(/(\|.*=)(\n?)$/, '$1 $2');
}
params.push([m[1], m[2], m[3], m[6]]);
}
if (!params[0]) {
return newTpl;
}
standardWidth = Math.min(thisMaxWidth, longestParameterLength);
if (!hardMode || codeStylerMode || templateExpanderMode) {
if (namedParametersCount !== 0 && calculateOneValueDominance(paramLeftLengths) <= 0.75) {
if (oneSpaceCount / namedParametersCount > 0.75) {
standardWidth = 0;
}
if (zeroSpacesCount / namedParametersCount > 0.75) {
standardWidth = -1;
}
}
}
newTpl = '';
if (isMultiline(trailingSpaceBefore)) {
m = trailingSpaceBefore.match(/ *$/);
var trailingNormalSpacesLength = m ? m[0].length : 0;
if (trailingNormalSpacesLength < indentSpaces.length) {
newTpl += generateSpaces(indentSpaces.length - trailingNormalSpacesLength);
} else {
newLeft -= trailingNormalSpacesLength - indentSpaces.length;
}
}
newTpl += start + '\n';
//console.log(params);
if (params.length !== 1 && params[params.length - 1][2] && params[params.length - 1][3]) {
params[params.length - 1][3] = params[params.length - 1][3]
.replace(/\s*$/, '')
// Ещё раз оканчивающий пробел в параметрах lat_*, lon_* и т. п.
.replace(/(\|.*=)(\n?)$/, '$1 $2');
} else if (isParserFunction) {
params[params.length - 1][3] = params[params.length - 1][3].replace(/\s*$/, '');
} else {
params[params.length - 1][3] = removeEndingNewlines(params[params.length - 1][3]);
}
var line;
var NUMBERED_PARAMS = [
'заголовок',
'метка',
'текст',
'викиданные',
'группа', 'group',
'список', 'list',
'блок',
'класс',
'класс_заголовка', 'класс заголовка',
'класс_метки', 'класс метки',
'класс_текста', 'класс текста',
'класс_списка', 'класс списка', 'listclass',
'стиль_заголовка', 'стиль заголовка',
'стиль_метки', 'стиль метки',
'стиль_текста', 'стиль текста',
'стиль_группы', 'стиль группы', 'groupstyle',
'стиль_списка', 'стиль списка', 'liststyle',
];
var paramName, numberMatches, number, numberedParamCurrent, numberedParamCounter, paramNameCount,
paramGroupDuplicatesCount, isDuplicate;
var paramNamesMet = [];
var paramGroupDuplicateNumbersMet = [];
for (i = 0; i < params.length; i++) {
if (params[i][2]) {
paramName = params[i][2];
if (!NUMBERED_PARAMS.includes(paramName) &&
NUMBERED_PARAMS.includes(paramName.replace(/\d+/, ''))
) {
numberMatches = paramName.match(/\d+/);
number = Number(numberMatches[0]);
isDuplicate = paramNamesMet.includes(paramName);
if (isDuplicate) {
paramNameCount = paramNamesMet.filter(function (value) {
return value === paramName;
}).length;
paramGroupDuplicatesCount = paramGroupDuplicateNumbersMet.filter(function (value) {
return value === number;
}).length;
}
if (numberedParamCurrent === undefined) {
numberedParamCounter = 1;
} else if (
// В numberedParamCurrent предыдущий номер.
number !== numberedParamCurrent ||
// Это условие позволяет адекватно разбирать многочисленные дубли имён параметров. Оно
// идентифицирует случаи, когда некий параметр повторяется больше раз, чем уже
// существует групп для этого номера, чтобы повысить счётчик на 1.
(isDuplicate && paramNameCount > paramGroupDuplicatesCount)
) {
numberedParamCounter++;
if (isDuplicate) {
paramGroupDuplicateNumbersMet.push(number);
}
}
numberedParamCurrent = number;
paramNamesMet.push(paramName);
paramName = paramName.replace(/\d+/, numberedParamCounter);
params[i][2] = paramName;
}
}
line = indentSpaces + params[i][0] + '|' + params[i][1] + (params[i][2] || '');
if (params[i][2]) {
if (!params[i][2].match(/^(lat|lon)_/) || !params[i][3].includes('|')) {
line += generateSpaces(
standardWidth - (params[i][2].length + params[i][0].length + params[i][1].length)
);
}
if (standardWidth !== -1) {
line += ' ';
}
line += '=';
if (standardWidth !== -1 && (!params[i][3].match(/^\n(?!<!--)/) || params[i][3].trim() === '')) {
line += ' ';
}
}
line += params[i][3] + '\n';
newTpl += line;
}
if (!noEndingBrackets) {
newTpl += indentSpaces + '}}';
}
return newTpl;
}
var initialTxt = txt;
var thisMaxWidth, thisPreserveBasicSpacing, thisPreserveParameterSpacing, selectionSpacing = 0, basicLevel = 0;
if (askOptions) {
if (!templateExpanderMode && !codeStylerMode) {
if (selectionMode) {
selectionSpacing = parseInt(prompt('Базовая отбивка значений параметров в пробелах:', '0'));
if (isNaN(selectionSpacing)) {
selectionSpacing = 0;
}
}
thisMaxWidth = parseInt(prompt('Максимально допустимая стандартная ширина колонки названий параметров, в символах. (Значение по умолчанию для этой настройки можно указать в своём common.js в переменной atpMaxWidth.)', atpMaxWidth));
if (isNaN(thisMaxWidth)) {
thisMaxWidth = atpMaxWidth;
}
thisPreserveBasicSpacing = confirm('Сохранять отбивку вокруг знака «|» в начале строки? (Значение по умолчанию для этой настройки [true/false, сейчас ' + atpPreserveBasicSpacing + '] можно указать в своём common.js в переменной atpPreserveBasicSpacing.)');
thisPreserveParameterSpacing = confirm('Сохранять отбивку вокруг знака «|» в начале строки у отдельных параметров по отношению к базовому уровню (параметры некоторых шаблонов визуально группируются таким образом)? (Значение по умолчанию для этой настройки [true/false, сейчас ' + atpPreserveParameterSpacing + '] можно указать в своём common.js в переменной atpPreserveParameterSpacing.)');
} else {
thisMaxWidth = atpMaxWidth;
thisPreserveBasicSpacing = atpPreserveBasicSpacing;
thisPreserveParameterSpacing = atpPreserveParameterSpacing;
}
basicLevel = parseInt(prompt('Базовая отбивка строк', '0'));
if (isNaN(basicLevel) || basicLevel < 0) {
basicLevel = 0;
}
} else {
thisMaxWidth = atpMaxWidth;
thisPreserveBasicSpacing = atpPreserveBasicSpacing;
thisPreserveParameterSpacing = atpPreserveParameterSpacing;
}
if (!pageIsProbablyTemplate) { // заготовки карточек
hideTag('pre');
}
hideTag('nowiki');
hideTag('source');
hideTag('syntaxhighlight');
hideTag('templatedata');
hideTag('code');
hideTag('kbd');
hideTag('tt');
hideTag('graph');
hideTag('hiero');
hideTag('math');
hideTag('timeline');
hideTag('chem');
hideTag('score');
hideTag('categorytree');
hide(/<!--[\s\S]*?-->/g);
if (atpCodeStyler && codeStylerMode) {
r(/^;(?=[^ ])/mg, '; ');
r(/(\sstyle=)([\'"])([^<>\2]+?)\2([^<>]*?)/g, function (s, m1, m2, m3, m4) {
if (/\{\{ *#/.test(s)) {
return s;
}
m3 = m3
.replace(/;+/g, ';')
.replace(/; */g, '; ')
.replace(/ *$/, '')
.replace(/([^;}])$/, '$1;')
.replace(/#[0-9A-F]{6}/, function (m) {
return m.toLowerCase();
})
.replace(/#[0-9A-F]{3}/, function (m) {
return m.toLowerCase();
});
return m1 + '"' + m3 + '"' + m4;
});
}
var stack = [],
tpl,
left,
right,
trailingSpaceBefore,
refTagBefore,
leftRe = /\{\{(?:\{(?!\{|!)|(?!\{!))/g, // учитываем {{{{{|subst:}}}template}}, {{{!}} (чтобы получить {|).
// жертвуем тем, что {{{!}}} будет считаться за { + {{!}} + }
leftM,
bracketsLength = 0,
lastStackBrackets,
stackElem,
newLeft;
while (true) {
lastStackBrackets = stack.length && stack[stack.length - 1][1] === 3 ? '}}}' : '}}';
right = txt.indexOf(lastStackBrackets, leftRe.lastIndex);
leftM = leftRe.exec(txt);
if (leftM) {
bracketsLength = leftM[0].length;
left = leftM.index;
} else {
left = -1;
}
if (left === -1 && right === -1 && !stack.length) {
break;
}
if (left !== -1 && (left < right || right === -1)) {
stack.push([left, bracketsLength]);
} else {
stackElem = stack.pop();
if (stackElem) {
left = stackElem[0];
bracketsLength = stackElem[1];
} else {
if (right === -1) {
continue;
} else {
left = 0;
bracketsLength = 2;
}
}
if (right === -1) {
right = txt.length;
}
right += bracketsLength;
tpl = txt.substring(left, right);
trailingSpaceBefore = '';
if (isMultiline(tpl) || templateExpanderMode) {
var m = txt.substring(0, left).match(/(\S)\s*$/);
if (m && m[1] === '=') {
trailingSpaceBefore = m[0].substr(1);
}
refTagBefore = txt.substring(0, left).match(/\n<ref( [\w ]+?=[^<>]+?| *\/?)>\s*$/);
}
newLeft = left;
var index;
var isParserFunction = false;
var isMultilineTemplate = isMultiline(tpl);
if (bracketsLength === 2) {
isParserFunction = /^\{\{\s*#/.test(tpl);
index = hidden.push(prettifyTemplate());
} else {
index = hidden.push(
tpl.replace(/^\{\{\{\s*([^}|]*?)\s*(?:\|\s*([^}]*?)\s*)?\}\}\}$/, function (s, m1, m2) {
return '{{{' + m1 + (m2 === undefined ? '' : '|' + m2) + '}}}';
})
);
}
// Add "_" to the indexes of templates that should be taken into account when determining the
// makeIfMultiline variable value.
txt = txt.substring(0, newLeft) + '\x01' + (isParserFunction || isMultilineTemplate ? '_' : '') +
index + '\x02' + txt.substr(right);
leftRe.lastIndex = right - tpl.length;
}
}
//console.log(hidden);
while (txt.match(/\x01_?\d+\x02/)) {
txt = txt.replace(/\x01_?(\d+)\x02/g, function (s, num) {
return hidden[num - 1];
});
}
if (atpAutoSummary && txt !== initialTxt) {
var summaryValue = $('#wpSummary').val();
if (!/Код кечйар/.test(summaryValue)) {
$('#wpSummary').val(summaryValue + (/[^,; \/]$/.test(summaryValue) ? ', ' : '') + 'Скриптан гӀоьнца код кечйар');
}
}
}
function processAllText() {
if (templateExpanderMode && !selectionMode) {
var expandOrCollapseText = templateExpanderMode === 'expand' ? 'развернуть' : 'свернуть';
if (!confirm('Вы уверены, что хотите ' + expandOrCollapseText + ' все шаблоны на странице? Чтобы ' + expandOrCollapseText + ' один шаблон или группу шаблонов, выделите только их.')) return;
}
txt = $textbox.textSelection('getContents').replace(/^\s+/, '');
prettifyTemplates();
// 2017 wikitext editor adds an empty line to the end with every text replacement. Remove
// the following block when [[phab:T198010]] is fixed.
if (window.ve && ve.init && ve.init.target && ve.init.target.active) {
r(/[\n\r]+$/, '');
}
$textbox.textSelection('setContents', txt);
if (caretPosition) {
$textbox.textSelection('setSelection', {
start: caretPosition[0] > txt.length ? txt.length : caretPosition[0]
});
}
}
$textbox.focus();
var caretPosition = $textbox.textSelection('getCaretPosition', { startAndEnd: true });
if (caretPosition) {
var textScroll = ($CodeMirrorVscrollbar.length ? $CodeMirrorVscrollbar : $textbox).scrollTop();
if (caretPosition[0] === caretPosition[1]) {
processAllText();
} else {
txt = $textbox.textSelection('getSelection');
prettifyTemplates();
$textbox
.textSelection('replaceSelection', txt)
.textSelection('setSelection', {
start: caretPosition[0],
end: caretPosition[0] + txt.length
});
}
($CodeMirrorVscrollbar.length ? $CodeMirrorVscrollbar : $textbox).scrollTop(textScroll);
// If something went wrong
} else if (confirm('Скрипт обработает ВЕСЬ текст на этой странице. Продолжить?')) {
processAllText();
}
// scroll back, for 2017 wikitext editor, IE, Opera
document.documentElement.scrollTop = winScroll;
}
mw.loader.using( [ 'ext.gadget.registerTool', 'jquery.textSelection' ] ).done( function () {
if (typeof atpTemplateExpander === 'undefined') window.atpTemplateExpander = true;
if (typeof atpCodeStyler === 'undefined') window.atpCodeStyler = false;
registerTool( {
name: 'atp',
position: 150,
title: 'Выровнять параметры шаблонов',
label: 'Выровнять параметры шаблонов. Выделите шаблон(ы), чтобы выровнять только их. Ctrl+клик, чтобы выровнять параметры даже тех шаблонов, где выравнивание не используется. Alt+клик, чтобы вызвать настройки',
callback: function () {},
classic: {
icon: '//upload.wikimedia.org/wikipedia/commons/5/59/AlignTemplateParameters.js_icon.png',
addCallback: function () {
$( '.tool-button[rel="atp"]' )
.off('click')
.on('click', function (e) {
alignTemplateParameters({
askOptions: e.altKey,
hardMode: e.ctrlKey || e.metaKey,
});
e.preventDefault();
});
},
},
visual: {
icon: '//upload.wikimedia.org/wikipedia/commons/thumb/1/14/AlignTemplateParameters.js_VE_icon.svg/20px-AlignTemplateParameters.js_VE_icon.svg.png',
modes: [ 'source' ],
callback: alignTemplateParameters,
},
} );
if (atpTemplateExpander) {
if (typeof atpSwapExpandCollapseTemplates === 'undefined') window.atpSwapExpandCollapseTemplates = false;
registerTool( {
name: 'atpTemplateExpander',
position: 151,
label: !atpSwapExpandCollapseTemplates
? 'Развернуть шаблоны в многострочные и выровнять параметры шаблонов. Shift+клик, чтобы свернуть'
: 'Свернуть шаблоны в однострочные и выровнять параметры шаблонов. Shift+клик, чтобы развернуть',
icon: '//upload.wikimedia.org/wikipedia/commons/8/8b/AlignTemplateParameters.js_templateExpander.png',
callback: function () {},
classic: {
addCallback: function () {
$( '.tool-button[rel="atpTemplateExpander"]' )
.off('click')
.on('click', function (e) {
alignTemplateParameters({
askOptions: e.altKey,
templateExpanderMode: e.shiftKey ^ atpSwapExpandCollapseTemplates ? 'collapse' : 'expand',
});
e.preventDefault();
});
},
},
} );
}
if (atpCodeStyler) {
registerTool( {
name: 'atpCodeStyler',
position: 152,
label: 'Оформить функции парсера и выровнять параметры шаблонов. Ctrl+клик, чтобы развернуть их в многострочные. Ctrl+Shift+клик, чтобы свернуть',
icon: '//upload.wikimedia.org/wikipedia/commons/6/68/AlignTemplateParameters.js_codeStyler.png',
callback: function () {},
classic: {
addCallback: function () {
$( '.tool-button[rel="atpCodeStyler"]' )
.off('click')
.on('click', function (e) {
alignTemplateParameters({
askOptions: e.altKey,
codeStylerMode: (e.ctrlKey || e.metaKey) ? (e.shiftKey ? 'newlines-collapse' : 'newlines') : 'spaces',
});
e.preventDefault();
});
},
},
} );
}
} );
}());
// </nowiki>