МедияУики:Gadget-Advisor.js и Потребител:Ted Masters/Test 3.js: Разлика между страниците
(Разлики между страниците)
Изтрито е съдържание Добавено е съдържание
м Грешки в статичния код: Остарели HTML-тагове |
Ted Masters (беседа | приноси) Редакция без резюме |
||
Ред 2:
// Виж МедияУики:Gadget-Advisor-core.js за основния скрипт
// виж http://en.wikipedia.org/wiki/User:Cameltrader/Advisor.js/Description
importScript('МедияУики:Gadget-Advisor-core.js');
var ct = ct || {};
ct.inBrackets = function (s, m, brackets) {
};
// originally from https://en.wikipedia.org/wiki/User:GregU/dashes.js
// checkPat1, checkPat2, checkTags, checkFileName default to true
ct.doNotFix = function (s, m, checkPat1, checkPat2, checkTags, checkFileName, checkWikiPreCode, checkQuotes) {
return true; // specific template/parser function (with up to six balanced curly brackets -- 3 levels of template/parser function nesting or 2 levels of parameter placeholder nesting)
return true; // skip math/chem equations, source code, timelines, graphs, maps, ref content, content in citation tags
}
if (checkWikiPreCode !== false && s.slice(0, pos + 1).search(/(?:^|\n) +.*$/) >= 0)
return true; // it's a text in wiki pre code (a line starting with a normal space)
if (checkQuotes !== false) {
let leftSlice = s.slice(0, pos + 1).replace(/'''/g, '');
let rightSlice = s.slice(pos + 1).replace(/'''/g, '');
if (leftSlice.match(/„(?:(?=([^„“”]+))\1|„[^„“”]*[“”])*$/) &&
rightSlice.match(/^(?:(?=([^„“”]+))\1|„[^„“”]*[“”])*[“”]/) ||
leftSlice.match(/“(?:(?=([^“”]+))\1|“[^“”]*”)*$/) &&
rightSlice.match(/^(?:(?=([^“”]+))\1|“[^“”]*”)*”/) ||
leftSlice.match(/«(?:(?=([^«»]+))\1|«[^«»]*»)*$/) &&
rightSlice.match(/^(?:(?=([^«»]+))\1|«[^«»]*»)*»/) ||
leftSlice.match(/"[^"]*$/) &&
rightSlice.match(/^[^"]*"/) &&
leftSlice.match(/"/g).length % 2 === 1 &&
rightSlice.match(/"/g).length % 2 === 1 ||
leftSlice.match(/''(?:(?!'').)*$/) &&
rightSlice.match(/^.*?''/) &&
leftSlice.match(/''/g).length % 2 === 1 &&
rightSlice.match(/''/g).length % 2 === 1
) return true; // it's a text in quotes or italicized text
}
};
if (mw.config.get('wgUserLanguage') === 'bg') {
ct.translation = {
'Changing text in wikEd is not yet supported.':
'Променянето на текст в wikEd още не се поддържа.',
Line 88 ⟶ 113:
};
}
ct.rules = ct.rules || [];
ct.rules.push(function (s) {
re = ct.fixRegExp(re);
let b = [];
for ( if (m[1].toLowerCase() !== m[4].toLowerCase()) continue;
m[3] = m[3] || '';
m[5] = m[5] || '';
m[6] = m[6] || '';
b.push({
start: m.start,
end: m.end,
replacement: m[3] + '[[' + m[
name: 'А|' + (m[3] ? '..' : '') + 'А' +
description: '„
help: 'Синтаксисът на МедияУики позволява препратки от вида „<kbd>[[А|
+ 'А' + (m[5] ? 'Б' : '') + (m[6] ? '...' : '') + ']]</kbd>“ да се пишат като „'
+ (m[3] ? '..' : '') + '[[А]]' + (m[5] ? 'Б' : '') + (m[6] ? '..' : '') + '“.'
});
}
return
});
ct.rules.push(function (s) {
function doNotFixSpaces(str, index) {
let
let wikiPre = str.slice(0, index + 1).search(/(?:^|\n) +.*$/);
return (nextTagPos > -1 && str.charAt(index + nextTagPos + 1) === '/' || wikiPre > -1);
}
let replacement = s.replace(/[^\S\r\n]+$/gm, function (m, index, str) {
// Remove end-of-line spaces
let prev2chars = str.slice(index - 2, index);
// don't rm EOL-space in empty table cells (after |) and in empty template param vals (after =)
// but after headings, yes (after ==)
if (prev2chars[1] === '=' && prev2chars !== '==' || prev2chars[1] === '|') return m;
if (start === -1) start = index;
end = index;
return '';
}).replace(/[^\s][^\S\r\n]{2,}(?=[^\s=]|==)/g, function (m, index, str) {
// Remove double spaces
if (doNotFixSpaces(str, index)) return m;
if (start === -1 || start > index + 1)
if (end < index + 2) end =
return m[0] + ' ';
let spacesRemoved = s.length - replacement.length;
if (spacesRemoved === 0) return [];
return [{
start: start,
end: end + spacesRemoved,
replacement: replacement.slice(start, end),
name: (spacesRemoved === 1 ? 'интервал' : spacesRemoved + ' интервала'),
description: 'Изтрий двойните интервали и интервалите в края на редовете',
help: 'Двойните интервали и интервалите в края на редовете са ненужни.'
}];
});
ct.rules.push(function (s) {
// [^|] - пропусни ако вероятно е за означаване на празна клетка в таблица
for (
if (
b.push({
start: m.start + 1,
Line 202 ⟶ 203:
// не работи при липса на интервал преди цифра защото може да е негативно число
// също не работи преди " и" или " или" за случаи като "антропо- и зооморфна пластика"
for (
if (
b.push({
start: m.start + 1,
Line 221 ⟶ 222:
ct.rules.push(function (s) {
let b = [];
for (let i =
let m = a[i];
if (ct.doNotFix(s, m) || (m[1].length == 3 && m[2].length == 10)) continue; // don't change ISBN-13
b.push({
start: m.start + 1,
Line 243 ⟶ 241:
ct.rules.push(function (s) {
// If we are editing a section, we have to be tolerant to the first heading's level
for (let i = 0; i < a.length; i++) {
let m = a[i];
b.push({
start: m.start,
end: m.end,
replacement:
name: 'празно заглавие
description: '
help: 'Празните заглавия са ненужни.'
});
} else {
if (!m[2].startsWith(' ') || !m[2].endsWith(' ')) {
b.push({
start: m.start,
end: m.end,
replacement: m[1] + ' ' + m[2].trim() + ' ' + m[3],
name: 'заглавие-стил',
description: 'Поправи интервалите',
help: 'Стилът на заглавието трябва да е <kbd>== С интервали ==</kbd>.'
});
}
let oldLevel = level;
level = m[1].length - 1;
if (level - oldLevel > 1 && (!isSection || oldLevel > 0) ||
m[1].length > 6 ||
m[3].length > 6 ||
m[1].length !== m[3].length
) {
b.push({
start: m.start,
end: m.end,
name: 'заглавие-вложеност',
description: 'Поправи ръчно неправилната вложеност, провери ръчно и следващите подзаглавия',
help: 'Всяко заглавие трябва да е вложено точно едно ниво под по-общото заглавие.'
}
// let frequentMistakes = [
// { code: 'външни вр.', wrong: /^[Вв]ъншни *[Вв]ръзки$/i, correct: 'Външни препратки' },
// { code: 'see-also', wrong: /^see *al+so$/i, correct: 'See also' },
// { code: 'ext-links', wrong: /^external links?$/i, correct: 'External links' },
// { code: 'refs', wrong: /^ref+e?r+en(c|s)es?$/i, correct: 'References' }
// ];
// for (let j = 0; j < frequentMistakes.length; j++) {
// let fm = frequentMistakes[j];
// if (fm.wrong.test(m[3]) && m[3] != fm.correct) {
// let r = m[1] + m[2] + fm.correct + m[2] + m[1];
// if (r != m[0]) {
// b.push({
// start: m.start,
// end: m.end,
// replacement: r,
// name: fm.code,
// description: 'Поправи на „' + fm.correct + "“.",
// help: 'Правилното изписване е „<kbd>' + fm.correct + "</kbd>“."
// });
// }
// }
// }
}
}
Line 305 ⟶ 314:
ct.rules.push(function (s) {
// ISBN: ten or thirteen digits, each digit optionally followed by a hyphen, the last digit can be 'X' or 'x'
for (
if (
b.push({
start: m.start,
Line 317 ⟶ 326:
description: 'Трябва да е дълъг 10 или 13 цифри',
help: 'ISBN номерата трябва да са дълги 10 или 13 цифри. '
+ 'Този се състои от ' +
});
continue;
}
if (xIndex !== -1 && (xIndex !== 9 || isNew)) {
b.push({
Line 334 ⟶ 343:
continue;
}
for (
? ((j & 1) ? 3 : 1) // the new way: 1 for even, 3 for odd
: 10 - j;
computedChecksum = (computedChecksum + (quotient * digit)) % modulus;
}
computedChecksum = (modulus - computedChecksum) % modulus;
if (computedChecksum === actualChecksum)
b.push({
start: m.start,
Line 361 ⟶ 368:
ct.rules.push(function (s) {
let b = [];
for (
if (
start: m.start + 1,
end: m.end - 1,
Line 375 ⟶ 382:
help: 'Когато се ползва като местоимение, „й“ трябва да се изписва '
+ 'като „ѝ“ с ударение.'
});
}
return
});
ct.rules.push(function (s) {
//
let autofix = ['г.', 'лв.', 'щ.д.'];
let a = ct.getAllMatches(re, s);
for (let i = 0; i < a.length; i++) {
let m = a[i]
if (ct.doNotFix(s, m)) continue;
let number = m[1];
let autofixThis = $.inArray(unit, autofix) > -1;
if (m[3] === 'год.' ||
(autofixThis && spacing !== ' ' && spacing !== '\u00a0' && spacing !== ' ') ||
(!autofixThis && spacing === '')
) {
b.push({
start: m.start + 1,
end: m.end,
replacement: (
name: 'число+' + unit,
description: 'Добави интервал между числото и единицата ' + unit,
help: 'Между
+ 'за предпочитане непренасящият се <kbd>&nbsp;</kbd> '
+ '(non-breaking space, <kbd>U+00A0</kbd>).'
Line 428 ⟶ 420:
ct.rules.push(function (s) {
let m1 = { 'start': m.start + m[1].length, 'end': m.end - m[3].length };
if (ct.doNotFix(s, m, false, false, true, true, true, false) ||
ct.inBrackets(s, m1, ['[', ']']) ||
ct.inBrackets(s, m1, ['{', '}']) ||
!isNaN(m[2]) && !isNaN(m[4]) // m[2] и m[4] са цифри; вероятност за десетично число
) continue;
b.push({
start: m1.start,
end: m1.end,
replacement: ', ',
name: 'запетая',
description: 'Премахни интервала преди запетаята и/или добави такъв след нея',
help: 'Интервалът трябва да е след запетаята и не преди нея.'
});
}
return b;
});
ct.rules.push(function (s) {
let m1 = { 'start': m.start + m[1].length, 'end': m.end - m[3].length };
if (ct.doNotFix(s, m, false, false, true, true, true, false) ||
ct.inBrackets(s, m1, ['[', ']']) ||
ct.inBrackets(s, m1, ['{', '}']) ||
!isNaN(m[2]) && !isNaN(m[4]) || // m[2] и m[4] са цифри; вероятност за десетично число след копиране
m[4] !== m[4].toUpperCase() // m[4] не е главна буква
) continue;
b.push({
start: m1.start,
end: m1.end,
replacement: '. ',
name: 'точка',
description: 'Премахни интервала преди точката в края на изречението и/или добави такъв след нея',
help: 'Интервалът трябва да е след точката и не преди нея.'
});
}
return b;
});
ct.rules.push(function (s) {
let
for (let i =
let m = a[i];
let lines = m[2] ? '\n' : '\n\n';
a[i] = {
start: m.start,
end: m.end,
replacement: m[1] ? m[1][0] + lines + m[1][m.end - m.start - 1] : '',
name: 'нов ред',
description: 'Премахни излишните празни редове или добави нов ред между отделните абзаци',
help: 'Между отделните абзаци трябва да има един празен ред. Повече от един празен ред е излишен.'
};
}
return a;
});
ct.rules.push(function (s) {
function replace(latin, cyrillic, str, obj) {
if (str.indexOf(latin) > -1) {
obj.replacement = str.replace(latin, cyrillic);
obj.description = 'Замени латинско "' + latin + '" с кирилско.';
}
}
let re = /[А-я] [ec] [А-я]|[a-z][А-я]|[А-я][a-z]/g;
let a = ct.getAllMatches(re, s);
for (let i = 0; i < a.length; i++) {
let m = a[i];
a[i] = {
start: m.start,
end: m.end,
replacement: null,
name: '6lokavica',
description: 'Неизвестна замяна. Проверете текста.',
help: 'Една дума трябва да бъде написана или само на кирилица или само на латиница.'
};
replace('e', 'е', m[0], a[i]);
replace('o', 'о', m[0], a[i]);
replace('x', 'х', m[0], a[i]);
replace('p', 'р', m[0], a[i]);
replace('c', 'с', m[0], a[i]);
}
return a;
});
ct.rules.push(function (s) {
// отварящи кавички ако са в нач. на реда или в списъчен елемент, след '', интервали (непредхождани от единично =), ==
let re = /((?:^|\n)[*#:;]*|''|[^=\s][^\S\n]+|==[^\S\n]*|[>}|\(])(?:"(?![\s.,;])((?:[^"\[\]\s]|\s(?!")|\[\[[^\[\]]+\]\]|\[[^\[\]]+\])+)"|[„“](?![\s.,;])((?:[^„“”\[\]\s]|\s(?![“”])|\[\[[^\[\]]+\]\]|\[[^\[\]]+\])+)”|«(?!\s)((?:[^«»\[\]\s]|\s(?!»)|\[\[[^\[\]]+\]\]|\[[^\[\]]+\])+)»)/g;
let a = ct.getAllMatches(re, s);
let b = [];
for (let i = 0; i < a.length; i++) {
let m = a[i];
if (
str.search(/[а-ъюяѝ]|ь(?=о)/i) === -1 || // не съдържа нито една кирилска буква, ползвана в българския
str.search(/(?![а-ъюяѝ]|ь(?=о))[\u0400-\u04ff]/i) > -1 // или пък съдържа и други кирилски букви, които не се ползват в българския
) continue;
b.push({
start: m.start + m[1].length,
end: m.end,
replacement: '„' +
name: 'кавички',
description: 'Заместване на "прави", “други горни”, „смесени” или «френски» с „български“ кавички.',
Line 546 ⟶ 542:
});
// Премахването на празни параметри от шаблоните като практика не се ползва с
// консенсусна подкрепа сред редакторите, затова на този етап е изключено.
/*
ct.rules.push(function (s) {
let replacement = s.slice(start, end).replace(re, '$1');
let b = [{
start: start,
end: end - 1,
replacement: replacement.slice(0, -1),
name: (n == 1 ? 'параметър' : n + '+ параметъра'),
description: 'Премахва неизползваните параметри от шаблоните',
help: 'Неизползваните параметри са излишни.'
}];
return b;
});
*/
ct.rules.push(function (s) {
}
let decimal = parseInt(charCode, 16);
let bin = Number(decimal).toString(2);
if (decimal < 128) return match; // ASCII, don't decode
let nOfBytes = bin.match(/^1+/)[0].length;
skipNext = nOfBytes - 1;
let urlEncoded = match + s.slice(index + 3, index + 3 * nOfBytes);
let char = decodeURI(urlEncoded);
return (char.length == 1 ? char : urlEncoded);
};
let re = /(https?:\/\/[^\/\s]+\/)([^\s|}<>\]]*)/g;
let a = ct.getAllMatches(re, s);
let b = [];
let decoded;
for (let i = 0; i < a.length; i++) {
let m = a[i];
try {
decoded = m[2].replace(/%([A-F\d]{2})/gi, decoder);
if (m[2] === decoded) continue;
b.push({
start: m.start,
end: m.end,
replacement: m[1] + decoded,
name: 'URL',
description: 'Декодира кодирани URL адреси',
help: 'URL адресите се четат по-лесно когато са декодирани.'
});
} catch (e) {
// не е кодиран Unicode текст
}
}
return b;
});
ct.rules.push(function (s) {
let re = /\([^\S\r\n]+|[^\S\r\n]+\)/g;
let a = ct.getAllMatches(re, s);
for (let i = 0; i < a.length; i++) {
let m = a[i];
if (ct.doNotFix(s, m)) continue;
a[i] = {
start: m.start,
end: m.end,
replacement: m[0].trim(),
name: 'скоба',
description: 'Премахни интервала след отварящата и/или преди затварящата скоба',
help: 'Интервалите са ненужни след отваряща и преди затваряща скоба.'
};
}
return a;
});
ct.rules.push(function (s) {
let re = /((?:[^А-яA-z\d](?:[Оо]т|[Дд]о|[Пп]ре(?:з|ди)|[Сс]лед|[Мм]е(?:жду|сец)|[Ии](?:ли)?|[Вв])|[\d,])[ \u00a0])(Януари|Февруари|Март|Април|Май|Юни|Юли|Август|Септември|Октомври|Ноември|Декември)[^А-яA-z\d]/g;
let
let b = [];
b.push({
replacement: m[2].toLowerCase(),
description: m[2] + ' → ' + m[2].toLowerCase(),
help: 'В българския език имената на месеците се пишат с малка буква.'
});
}
});
ct.rules.push(function (s) {
let re = /№(\d+)/g;
b.push({
start: m.start,
end: m.end,
replacement: '№\u00a0' + m[1],
name: '№+число',
description: 'Добави несекаем интервал между № и последващите числа',
help: 'Между символа за номер и последващите числа трябва да има несекаем интервал.'
});
}
return b;
});
ct.rules.push(function (s) {
function skipReferenceTags(str, index) {
let sliced = str.slice(0, index);
let tag1Pos = sliced.search(/<references\b(?:(?=([^/>]+))\1|\/(?!>))*>(?:(?=([^<]+))\2|<(?!\/references\b))*$/i);
let tag2Pos = sliced.search(/\{\{\s*[Rr]eflist\b(?:(?=([^{}]+))\1|\{(?:(?=([^{}]+))\2|\{(?:(?=([^{}]+))\3|\{(?:(?=([^{}]+))\4|\{(?:(?=([^{}]+))\5|\{(?:(?=([^{}]+))\6|\{(?=([^{}]*))\7\})*\})*\})*\})*\})*\})*$/);
return (tag1Pos > -1 || tag2Pos > -1);
}
let start = -1, end = 0;
let noChange = true;
let replacement = s.replace(/(<\/[Rr][Ee][Ff]\s*>|<[Rr][Ee][Ff]\b[^>]*\/>|\{\{\s*(?:[SsEe]fn|[Hh]rf|[Rr]p)\b[^{}]*\}\})[\s.:,;]+(?=<[Rr][Ee][Ff]\b|\{\{\s*(?:[SsEe]fn|[Hh]rf|[Rr]p)\b)/g, function (m, g1, index, str) {
// Remove punctuation chars and spaces between refs
if (skipReferenceTags(str, index)) return m;
if (start === -1) start = index;
end = index + g1.length;
noChange = false;
return g1;
}).replace(/([^\s.:,;=]\s+|\s*[.,]\s+|[^\S\r\n]*[:;][^\S\r\n]+)(?:<[Rr][Ee][Ff]\b|\{\{\s*(?:[SsEe]fn|[Hh]rf|[Rr]p)\b)|(?:<\/[Rr][Ee][Ff]\s*>|<[Rr][Ee][Ff]\b[^>]*\/>|\{\{\s*(?:[SsEe]fn|[Hh]rf|[Rr]p)\b[^{}]*\}\})(?:\s+(?=[.,])|[^\S\r\n]+(?=[:;]))/g, function (m, g1, index, str) {
// Remove spaces before ref/after ref and between punctuation chars
if (skipReferenceTags(str, index)) return m;
if (g1) m = g1.trim() + m.slice(g1.length);
m = m.trim();
if (start === -1 || start > index) start = index;
if (end < index + m.length) end = index + m.length;
noChange = false;
return m;
}).replace(/([.:,;])((?:<[Rr][Ee][Ff]\b(?:(?=([^>/]+))\3|\/(?!>))*(?:\/|>(?:(?=([^<]+))\4|<(?!\/?[Rr][Ee][Ff]\b))*<\/[Rr][Ee][Ff]\s*)>|\{\{(?:[SsEe]fn|[Hh]rf|[Rr]p)\b[^{}]*\}\})+)\1/g, function (m, g1, g2, g3, g4, index, str) {
// Remove last punctuation char if equal at start/end position for a group of refs
if (skipReferenceTags(str, index)) return m;
if (start === -1 || start > index) start = index;
if (end < index + (g1 + g2).length) end = index + (g1 + g2).length;
noChange = false;
return g1 + g2;
}).replace(ct.fixRegExp(/(?:<\/[Rr][Ee][Ff]\s*>|<[Rr][Ee][Ff]\b[^>]*\/>|\{\{(?:[SsEe]fn|[Hh]rf|[Rr]p)\b[^{}]*\}\})[.:,;]?(?=[^{letter}\d\s<>{}.:,;]*[{letter}\d])/g), function (m, index, str) {
// Add space if closing ref is followed by a word, only if the word is not positioned after opening/closing angular/curly bracket
if (skipReferenceTags(str, index)) return m;
if (start === -1 || start > index) start = index;
if (end < index + m.length + 1) end = index + m.length + 1;
noChange = false;
return m + ' ';
});
if (noChange) return [];
let deltaLength = s.length - replacement.length;
return [{
start: start,
end: end + deltaLength,
replacement: replacement.slice(start, end),
name: 'пунктуация+ref',
description: 'Интервалите и/или част от пунктуационните знаци преди, между и след ref-овете са ненужни',
help: 'Изтрий ненужните пунктуационни знаци и интервали преди, между и след ref-овете.'
}];
});
ct.rules.push(function (s) {
let re = ct.fixRegExp(/(^|\s+)([Вв](?:ъв)?|[Сс](?:ъс)?)(\s+(?:[^{letter}\d\s\[\]{}<>-]*\[\[?[^\[\]]+\]|(?:[^\s\[\]{}<>]+\s+){1,2}))/g);
let a = ct.getAllMatches(re, s);
let b = [];
for (let i = 0; i < a.length; i++) {
let m = a[i];
if (ct.doNotFix(s, m)) continue;
let tooltip;
let preposition = m[2];
let text = m[3].replace(/\[(?:(?:https?:|ftps?:)?\/\/\S+|\[[^|\[\]]+\|)/gi, '')
.replace(ct.fixRegExp(/[^{letter}\d\s-]+/g), '')
.replace(/^\s+/, '');
if (preposition.toLowerCase() === 'в' && text.match(/^(?:[ВвФф][А-Яа-я]|2-р|II(?![А-яA-z\d])|и(?:ли)?\s+)/)) {
preposition += 'ъв';
tooltip = '„в“ трябва да стане „във“, тъй като следващата дума започва с „в“ или „ф“, или попада под логическо ударение.';
}
else if (preposition.toLowerCase() === 'във' && !text.match(/^(?:[ВвФфVvFfWw]|2-р|II(?![А-яA-z\d])|и(?:ли)?\s+)/)) {
preposition = preposition[0];
tooltip = '„във“ трябва да стане „в“, тъй като следващата дума не започва с „в“ или „ф“, или не попада под логическо ударение.';
}
else if (preposition.toLowerCase() === 'с' && text.match(/^(?:[СсЗз][А-Яа-я]|(?:1?7(?:\d|\s*\d{3})?|[17]\d\d)(?!\d)|(?:X?VII|LXX[IVX]*|(?:DC)?C[IVXL]*)(?![А-яA-z\d])|и(?:ли)?\s+без\s+)/)) {
preposition += 'ъс';
tooltip = '„с“ трябва да стане „със“, тъй като следващата дума започва със „з“ или „с“, или попада под логическо ударение.';
}
else if (preposition.toLowerCase() === 'със' && !text.match(/^(?:[СсЗзSsZzCc]|(?:1?7(?:\d|\s*\d{3})?|[17]\d\d)(?!\d)|(?:X?VII|LXX[IVX]*|DCC[IVXL]*)(?![А-яA-z\d])|и(?:ли)?\s+без\s+)/)) {
preposition = preposition[0];
tooltip = '„със“ трябва да стане „с“, тъй като следващата дума не започва със „з“ или „с“, или не попада под логическо ударение.';
}
if (tooltip) {
b.push({
start: m.start + m[1].length,
end: m.end - m[3].length,
replacement: preposition,
name: m[2].toLowerCase() + '→' + preposition.toLowerCase(),
description: 'Поправи „' + m[2] + '“ на „' + preposition + '“',
help: tooltip
});
}
}
return b;
});
|