Участник:AlexeyBaturin/CulturalHeritageKzListingEditor.js
Внешний вид
Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.
- Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
- Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
- Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
- Opera: Нажмите Ctrl+F5.
mw.loader.using(['mediawiki.api'], function() {
var commonMessages = {
addTitle: 'Добавить объект',
editTitle: 'Редактировать объект',
submitApiError: 'Во время сохранения листинга на сервере произошла ошибка, пожайлуста, попробуйте сохранить ещё раз',
submitBlacklistError: 'Ошибка: текст содержит ссылку из чёрного списка, пожайлуста, удалите её и попробуйте сохранить снова',
submitUnknownError: 'Ошибка: при попытке сохранить листинг произошла неизвестная ошибка, пожайлуста, попробуйте сохранить ещё раз',
submitHttpError: 'Ошибка: сервер сообщил о HTTP ошибке, возникшей во время сохранения листинга, пожайлуста, попробуйте сохранить ещё раз',
submitEmptyError: 'Ошибка: сервер вернул пустой ответ при попытке сохранить листинг, пожайлуста, попробуйте сохранить ещё раз',
enterCaptcha: 'Введите CAPTCHA',
changesSummaryAdded: 'Добавлен объект',
changesSummaryUpdated: 'Обновлён объект',
captchaSubmit: 'Продолжить',
captchaCancel: 'Отмена'
};
var StringUtils = {
contains: function contains(string, substring) {
return string.indexOf(substring) >= 0;
},
trim: function trim(string) {
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim
return string.replace(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');
}
};
var ArrayUtils = {
hasElement: function hasElement(array, element) {
return array.indexOf(element) >= 0;
},
inArray: function inArray(element, array) {
return this.hasElement(array, element);
}
};
var AsyncUtils = {
runSequence: function runSequence(functions, onSuccess, results) {
if (!results) {
results = [];
}
if (functions.length > 0) {
var firstFunction = functions[0];
firstFunction(function (result) {
results.push(result);
setTimeout( // hack to break recursion chain
function () {
AsyncUtils.runSequence(functions.slice(1), onSuccess, results);
}, 0);
});
} else {
onSuccess(results);
}
},
runChunks: function runChunks(runSingleChunkFunction, maxChunkSize, data, onSuccess) {
var chunkRunFunctions = [];
var _loop = function _loop(dataNumStart) {
var dataChunk = data.slice(dataNumStart, dataNumStart + maxChunkSize);
chunkRunFunctions.push(function (onSuccess) {
return runSingleChunkFunction(dataChunk, onSuccess);
});
};
for (var dataNumStart = 0; dataNumStart < data.length; dataNumStart += maxChunkSize) {
_loop(dataNumStart);
}
this.runSequence(chunkRunFunctions, function (chunkResults) {
var result = chunkResults.reduce(function (current, total) {
return total.concat(current);
}, []);
onSuccess(result);
});
}
};
var ObjectUtils = {
merge: function merge(obj1, obj2) {
var result = {};
for (var prop in obj1) {
if (obj1.hasOwnProperty(prop)) {
result[prop] = obj1[prop];
}
}
for (var _prop in obj2) {
if (obj2.hasOwnProperty(_prop)) {
result[_prop] = obj2[_prop];
}
}
return result;
}
};
var ValidationUtils = {
normalizeUrl: function normalizeUrl(url) {
var webRegex = new RegExp('^https?://', 'i');
if (!webRegex.test(url) && url !== '') {
return 'http://' + url;
} else {
return url;
}
}
};
var MediaWikiPage = {
getPageName: function getPageName() {
return mw.config.get('wgPageName');
},
isDiffMode: function isDiffMode() {
return $('table.diff').length > 0;
},
isLastRevision: function isLastRevision() {
return mw.config.get('wgCurRevisionId') === mw.config.get('wgRevisionId');
},
isViewAction: function isViewAction() {
return mw.config.get('wgAction') === 'view';
},
isViewSourceMode: function isViewSourceMode() {
return $('#ca-viewsource').length > 0;
},
isViewSpecificRevisionMode: function isViewSpecificRevisionMode() {
return $('#mw-revision-info').length > 0;
},
isRegularNamespace: function isRegularNamespace() {
var namespace = mw.config.get('wgNamespaceNumber');
return namespace === 0 || namespace === 2 || namespace === 4;
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CaptchaDialog = function () {
function CaptchaDialog(captchaImgSrc, onCaptchaSubmit) {
var _this = this;
_classCallCheck(this, CaptchaDialog);
this._captcha = $('<div id="captcha-dialog">');
$('<img class="fancycaptcha-image">').attr('src', captchaImgSrc).appendTo(this._captcha);
$('<input id="input-captcha" type="text">').appendTo(this._captcha);
this._captcha.dialog({
modal: true,
title: commonMessages.enterCaptcha,
buttons: [{
text: commonMessages.captchaSubmit,
click: function click() {
onCaptchaSubmit($('#input-captcha').val());
_this.destroy();
}
}, {
text: commonMessages.captchaCancel,
click: function click() {
return _this.destroy();
}
}]
});
}
_createClass(CaptchaDialog, [{
key: 'destroy',
value: function destroy() {
this._captcha.dialog('destroy').remove();
}
}]);
return CaptchaDialog;
}();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ListingSection = function () {
function ListingSection(headerElement, sectionIndex) {
_classCallCheck(this, ListingSection);
this._headerElement = headerElement;
this._sectionIndex = sectionIndex;
}
_createClass(ListingSection, [{
key: 'getHeaderElement',
value: function getHeaderElement() {
return this._headerElement;
}
}, {
key: 'getSectionIndex',
value: function getSectionIndex() {
return this._sectionIndex;
}
}]);
return ListingSection;
}();
var ListingTable = function () {
function ListingTable(tableElement, sectionIndex, listingIndex) {
_classCallCheck(this, ListingTable);
this._tableElement = tableElement;
this._sectionIndex = sectionIndex;
this._listingIndex = listingIndex;
}
_createClass(ListingTable, [{
key: 'getTableElement',
value: function getTableElement() {
return this._tableElement;
}
}, {
key: 'getSectionIndex',
value: function getSectionIndex() {
return this._sectionIndex;
}
}, {
key: 'getListingIndex',
value: function getListingIndex() {
return this._listingIndex;
}
}]);
return ListingTable;
}();
var ListingPageElements = function () {
function ListingPageElements(sections, listingTables) {
_classCallCheck(this, ListingPageElements);
this._sections = sections;
this._listingTables = listingTables;
}
/**
* @returns {ListingSection[]}
*/
_createClass(ListingPageElements, [{
key: 'getSections',
value: function getSections() {
return this._sections;
}
}, {
key: 'getListingTables',
value: function getListingTables() {
return this._listingTables;
}
}]);
return ListingPageElements;
}();
var ListingEditorUtils = {
isEditablePage: function isEditablePage() {
return MediaWikiPage.isRegularNamespace() && MediaWikiPage.isViewAction() && MediaWikiPage.isLastRevision() && !MediaWikiPage.isDiffMode() && !MediaWikiPage.isViewSpecificRevisionMode() && !MediaWikiPage.isViewSourceMode();
},
/**
* @returns {ListingPageElements}
*/
getListingPageElements: function getListingPageElements() {
var pageBodyContentElement = $('#bodyContent');
var currentSectionIndex = 0;
var currentListingIndex = 0;
var sections = [];
var listingTables = [];
function isTableOfContentsHeader(headerElement) {
return headerElement.parents('.toc').length > 0;
}
// Here we add buttons to:
// - add new listing - for each section header
// - edit existing listing - for each existing listing
//
// - section index, to which we are going to add new listing
// - section index and listing index (within a section) for listing which we are going to edit
// To calculate section index and listing index, we iterate over all section header and listing
// table elements sequentially (in the same order as we have them in HTML).
// When we meet header - we consider that new section is started and increase current section index,
// and reset current listing index (listings are enumerated within section). All listings belong
// to that section until we meet the next header.
// When we meet listing table - we increase current listing index.
pageBodyContentElement.find('h1, h2, h3, h4, h5, h6, table.monument').each(function () {
if (ArrayUtils.inArray(this.tagName, ['H1', 'H2', 'H3', 'H4', 'H5', 'H6'])) {
var headerElement = $(this);
if (!isTableOfContentsHeader(headerElement)) {
currentSectionIndex++;
currentListingIndex = 0;
sections.push(new ListingSection(headerElement, currentSectionIndex));
}
} else if (this.tagName === 'TABLE') {
var listingTable = $(this);
listingTables.push(new ListingTable(listingTable, currentSectionIndex, currentListingIndex));
currentListingIndex++;
}
});
return new ListingPageElements(sections, listingTables);
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ListingEditorButtonEdit = function () {
function ListingEditorButtonEdit(button, listingTable) {
_classCallCheck(this, ListingEditorButtonEdit);
this._button = button;
this._listingTable = listingTable;
}
_createClass(ListingEditorButtonEdit, [{
key: 'click',
value: function click(handler) {
var _this = this;
this._button.click(function () {
return handler(_this._listingTable);
});
}
}]);
return ListingEditorButtonEdit;
}();
var ListingEditorButtonAdd = function () {
function ListingEditorButtonAdd(button, section) {
_classCallCheck(this, ListingEditorButtonAdd);
this._button = button;
this._section = section;
}
_createClass(ListingEditorButtonAdd, [{
key: 'click',
value: function click(handler) {
var _this2 = this;
this._button.click(function () {
return handler(_this2._section);
});
}
}]);
return ListingEditorButtonAdd;
}();
var ListingEditorButtons = {
/**
*
* @param listingTable ListingTable
*/
createListingEditButton: function createListingEditButton(listingTable) {
var editListingButton = $('<span class="vcard-edit-button noprint" style="padding-left: 5px;">');
editListingButton.html('<a href="javascript:" class="icon-pencil" title="Редактировать">Редактировать</a>');
var nameElement = listingTable.getTableElement().find('span.monument-name').first();
if (nameElement) {
nameElement.append(editListingButton);
}
return new ListingEditorButtonEdit(editListingButton, listingTable);
},
createListingAddButton: function createListingAddButton(section) {
var sectionAddButton = $('<a href="javascript:">добавить</a>');
var bracketStart = $('<span class="mw-editsection-bracket">[</span>');
var bracketEnd = $('<span class="mw-editsection-bracket">]</span>');
section.getHeaderElement().append($('<span class="mw-editsection"/>').append(bracketStart).append(sectionAddButton).append(bracketEnd));
return new ListingEditorButtonAdd(sectionAddButton, section);
}
};
var MAX_DIALOG_WIDTH = 1200;
var LICENSE_TEXT = 'Нажимая кнопку «Сохранить», вы соглашаетесь с <a class="external" target="_blank" href="https://wikimediafoundation.org/wiki/Terms_of_Use/ru">условиями использования</a>, а также соглашаетесь на неотзывную публикацию по лицензии <a class="external" target="_blank" href="https://en.wikipedia.org/wiki/ru:Википедия:Текст_Лицензии_Creative_Commons_Attribution-ShareAlike_3.0_Unported">CC-BY-SA 3.0</a>.';
var ListingEditorDialog = {
showDialog: function showDialog(formElement, dialogTitle, onSubmit, onCancel, onHelp) {
var windowWidth = $(window).width();
var dialogWidth = windowWidth > MAX_DIALOG_WIDTH ? MAX_DIALOG_WIDTH : 'auto';
mw.loader.using(['jquery.ui'], function () {
formElement.dialog({
modal: true,
height: 'auto',
width: dialogWidth,
title: dialogTitle,
dialogClass: 'listing-editor-dialog',
buttons: [{
text: '?',
id: 'listing-help',
click: function click() {
onHelp();
}
}, {
text: "Сохранить",
click: function click() {
onSubmit();
}
}, {
text: "Отмена",
click: function click() {
onCancel();
}
}],
create: function create() {
$('.ui-dialog-buttonpane').append('<div class="listing-license">' + LICENSE_TEXT + '</div>');
}
});
});
}
};
var ListingEditorFormComposer = {
createInputFormRow: function createInputFormRow(inputElementId, labelText) {
var rowElement = $('<tr>');
var label = $('<label>', {
'for': inputElementId,
'html': labelText
});
var labelColumn = $('<td>', {
'class': "editor-label-col",
'style': "width: 200px"
}).append(label);
var inputColumnElement = $('<td>');
rowElement.append(labelColumn).append(inputColumnElement);
return {
'rowElement': rowElement,
'inputColumnElement': inputColumnElement
};
},
createInputFormRowCheckbox: function createInputFormRowCheckbox(inputElementId, labelText) {
var row = this.createInputFormRow(inputElementId, labelText);
var inputElement = $('<input>', {
'type': 'checkbox',
'id': inputElementId
});
row.inputColumnElement.append(inputElement);
return {
'rowElement': row.rowElement,
'inputElement': inputElement
};
},
createInputFormRowSelect: function createInputFormRowSelect(inputElementId, labelText, options) {
var row = this.createInputFormRow(inputElementId, labelText);
var inputElement = $('<select>', {
'id': inputElementId
});
options.forEach(function (option) {
var optionElement = $('<option>', {
'value': option.value,
'html': option.title
});
inputElement.append(optionElement);
});
row.inputColumnElement.append(inputElement);
return {
'rowElement': row.rowElement,
'inputElement': inputElement
};
},
createInputFormRowText: function createInputFormRowText(inputElementId, labelText, placeholderText, partialWidth, insertSymbols) {
if (!placeholderText) {
placeholderText = '';
}
var row = this.createInputFormRow(inputElementId, labelText);
var inputElement = $('<input>', {
'type': 'text',
'class': partialWidth ? 'editor-partialwidth' : 'editor-fullwidth',
'style': insertSymbols ? 'width: 90%' : '',
'placeholder': placeholderText,
'id': inputElementId
});
row.inputColumnElement.append(inputElement);
if (insertSymbols) {
var buttonInsertQuotes = $('<a>', {
'class': 'name-quotes-template',
href: 'javascript:;',
html: '«»'
});
var buttonInsertDash = $('<a>', {
'class': 'name-dash-template',
href: 'javascript:;',
html: '—'
});
InputInsertSymbols.addDashInsertHandler(buttonInsertDash, inputElement);
InputInsertSymbols.addQuotesInsertHandler(buttonInsertQuotes, inputElement);
row.inputColumnElement.append(' ');
row.inputColumnElement.append(buttonInsertQuotes);
row.inputColumnElement.append(' ');
row.inputColumnElement.append(buttonInsertDash);
}
return {
'rowElement': row.rowElement,
'inputElement': inputElement
};
},
createRowDivider: function createRowDivider() {
return $('<tr>').append($('<td>', { 'colspan': "2" }).append($('<div>', {
'class': "listing-divider",
'style': "margin: 3px 0"
})));
},
createRowLink: function createRowLink(linkText) {
var linkElement = $("<a>", {
'href': 'javascript:;',
'html': linkText
});
var rowElement = $('<tr>').append($('<td>')).append($('<td>').append(linkElement));
return {
'rowElement': rowElement,
'linkElement': linkElement
};
},
createChangesDescriptionRow: function createChangesDescriptionRow() {
var inputChangesSummary = $('<input>', {
'type': "text",
'class': "editor-partialwidth",
'placeholder': "что именно было изменено",
'id': "input-summary"
});
var inputIsMinorChanges = $('<input>', {
'type': "checkbox",
'id': "input-minor"
});
var labelChangesSummary = $('<label>', {
'for': "input-summary",
'html': 'Описание изменений'
});
var labelIsMinorChanges = $('<label>', {
'for': "input-minor",
'class': "listing-tooltip",
'title': "Установите галочку, если изменение незначительное, например, исправление опечатки",
'html': 'незначительное изменение?'
});
var spanIsMinorChanges = $('<span>', { id: "span-minor" });
spanIsMinorChanges.append(inputIsMinorChanges).append(labelIsMinorChanges);
var row = $('<tr>');
row.append($('<td>', { 'class': "editor-label-col", style: "width: 200px" }).append(labelChangesSummary));
row.append($('<td>').append(inputChangesSummary).append(spanIsMinorChanges));
return {
'row': row,
'inputChangesSummary': inputChangesSummary,
'inputIsMinorChanges': inputIsMinorChanges
};
},
createObjectDescriptionRow: function createObjectDescriptionRow() {
var inputDescription = $('<textarea>', {
'rows': "4",
'class': "editor-fullwidth",
'placeholder': "описание объекта",
'id': "input-description"
});
var labelDescription = $('<label>', {
'for': "input-description",
'html': "Описание"
});
var row = $('<tr>');
row.append($('<td>', { 'class': "editor-label-col", 'style': "width: 200px" }).append(labelDescription));
row.append($('<td>').append(inputDescription));
return {
'row': row,
'inputDescription': inputDescription
};
},
createTableFullWidth: function createTableFullWidth() {
var tableElement = $('<table>', {
'class': 'editor-fullwidth'
});
var wrapperElement = $('<div>');
wrapperElement.append(tableElement);
return {
'wrapperElement': wrapperElement,
'tableElement': tableElement
};
},
createTableTwoColumns: function createTableTwoColumns() {
var leftTableElement = $('<table>', {
'class': "editor-fullwidth"
});
var rightTableElement = $('<table>', {
'class': "editor-fullwidth"
});
var wrapperElement = $('<div>');
wrapperElement.append($('<div>', {
'class': 'listing-col listing-span_1_of_2'
}).append(leftTableElement));
wrapperElement.append($('<div>', {
'class': 'listing-col listing-span_1_of_2'
}).append(rightTableElement));
return {
'wrapperElement': wrapperElement,
'leftTableElement': leftTableElement,
'rightTableElement': rightTableElement
};
},
createForm: function createForm() {
var formElement = $('<form id="listing-editor">');
formElement.append($('<br>'));
return {
'formElement': formElement
};
}
};
var api = new mw.Api();
var MediaWikiPageWikitext = {
loadSectionWikitext: function loadSectionWikitext(sectionIndex, onSuccess) {
$.ajax({
url: mw.util.wikiScript(''),
data: {
title: mw.config.get('wgPageName'),
action: 'raw',
section: sectionIndex
},
cache: false
}).done(function (data) {
onSuccess(data);
}).fail(function (jqXHR, textStatus, errorThrown) {
alert('Ошибка при получении исходного вики-текста статьи: ' + textStatus + ' ' + errorThrown);
});
},
saveSectionWikitext: function saveSectionWikitext(sectionIndex, sectionWikitext, changesSummary, changesIsMinor, captchaId, captchaAnswer, onSuccess, onFailure, onCaptcha) {
var editPayload = {
action: "edit",
title: mw.config.get("wgPageName"),
section: sectionIndex,
text: sectionWikitext,
summary: changesSummary,
captchaid: captchaId,
captchaword: captchaAnswer
};
if (changesIsMinor) {
$.extend(editPayload, { minor: 'true' });
}
api.postWithToken("csrf", editPayload).done(function (data) {
if (data && data.edit && data.edit.result === 'Success') {
onSuccess();
} else if (data && data.error) {
onFailure(commonMessages.submitApiError + ' "' + data.error.code + '": ' + data.error.info);
} else if (data && data.edit.spamblacklist) {
onFailure(commonMessages.submitBlacklistError + ': ' + data.edit.spamblacklist);
} else if (data && data.edit.captcha) {
onCaptcha(data.edit.captcha.url, data.edit.captcha.id);
} else {
onFailure(commonMessages.submitUnknownError);
}
}).fail(function (code, result) {
if (code === "http") {
onFailure(commonMessages.submitHttpError + ': ' + result.textStatus);
} else if (code === "ok-but-empty") {
onFailure(commonMessages.submitEmptyError);
} else {
onFailure(commonMessages.submitUnknownError + ': ' + code);
}
});
},
getSectionName: function getSectionName(sectionWikitext) {
var HEADING_REGEX = /^=+\s*([^=]+)\s*=+\s*\n/;
var result = HEADING_REGEX.exec(sectionWikitext);
return result !== null ? result[1].trim() : "";
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Region = function () {
function Region(id, title) {
_classCallCheck(this, Region);
this._id = id;
this._title = title;
}
_createClass(Region, [{
key: "getId",
value: function getId() {
return this._id;
}
}, {
key: "getTitle",
value: function getTitle() {
return this._title;
}
}]);
return Region;
}();
var regions = [new Region("", "не задан"), new Region("ru-ad", "Адыгея"), new Region("ru-ba", "Башкортостан"), new Region("ru-bu", "Бурятия"), new Region("ru-al", "Алтай"), new Region("ru-da", "Дагестан"), new Region("ru-in", "Ингушетия"), new Region("ru-kb", "Кабардино-Балкария"), new Region("ru-kl", "Калмыкия"), new Region("ru-kc", "Карачаево-Черкесия"), new Region("ru-krl", "Карелия"), new Region("ru-ko", "республика Коми"), new Region("ru-me", "Марий Эл"), new Region("ru-mo", "Мордовия"), new Region("ru-sa", "Якутия (Саха)"), new Region("ru-se", "Северная Осетия"), new Region("ru-ta", "Татарстан"), new Region("ru-ty", "Тува"), new Region("ru-ud", "Удмуртия"), new Region("ru-kk", "Хакасия"), new Region("ru-ce", "Чеченская республика"), new Region("ru-chv", "Чувашия"), new Region("ru-alt", "Алтайский край"), new Region("ru-kda", "Краснодарский край"), new Region("ru-kya", "Красноярский край"), new Region("ru-pri", "Приморский край"), new Region("ru-sta", "Ставропольский край"), new Region("ru-kha", "Хабаровский край"), new Region("ru-amu", "Амурская область"), new Region("ru-ark", "Архангельская область"), new Region("ru-ast", "Астраханская область"), new Region("ru-bel", "Белгородская область"), new Region("ru-bry", "Брянская область"), new Region("ru-vla", "Владимирская область"), new Region("ru-vgg", "Волгоградская область"), new Region("ru-vol", "Вологодская область"), new Region("ru-vor", "Воронежская область"), new Region("ru-iva", "Ивановская область"), new Region("ru-irk", "Иркутская область"), new Region("ru-kal", "Калининградская область"), new Region("ru-klu", "Калужская область"), new Region("ru-kam", "Камчатский край"), new Region("ru-kem", "Кемеровская область"), new Region("ru-kir", "Кировская область"), new Region("ru-kos", "Костромская область"), new Region("ru-kgn", "Курганская область"), new Region("ru-krs", "Курская область"), new Region("ru-len", "Ленинградская область"), new Region("ru-lip", "Липецкая область"), new Region("ru-mag", "Магаданская область"), new Region("ru-mos", "Московская область"), new Region("ru-mur", "Мурманская область"), new Region("ru-niz", "Нижегородская область"), new Region("ru-ngr", "Новгородская область"), new Region("ru-nvs", "Новосибирская область"), new Region("ru-oms", "Омская область"), new Region("ru-ore", "Оренбургская область"), new Region("ru-orl", "Орловская область"), new Region("ru-pnz", "Пензенская область"), new Region("ru-per", "Пермский край"), new Region("ru-psk", "Псковская область"), new Region("ru-ros", "Ростовская область"), new Region("ru-rya", "Рязанская область"), new Region("ru-sam", "Самарская область"), new Region("ru-sar", "Саратовская область"), new Region("ru-sak", "Сахалинская область"), new Region("ru-sve", "Свердловская область"), new Region("ru-smo", "Смоленская область"), new Region("ru-tam", "Тамбовская область"), new Region("ru-tve", "Тверская область"), new Region("ru-tom", "Томская область"), new Region("ru-tul", "Тульская область"), new Region("ru-tyu", "Тюменская область"), new Region("ru-uly", "Ульяновская область"), new Region("ru-che", "Челябинская область"), new Region("ru-zab", "Забайкальский край"), new Region("ru-yar", "Ярославская область"), new Region("ru-mow", "Москва"), new Region("ru-spb", "Санкт-Петербург"), new Region("ru-jew", "Еврейская автономная область"), new Region("ru-km", "Крым"), new Region("ru-nen", "Ненецкий автономный округ"), new Region("ru-khm", "Ханты-Мансийский автономный округ"), new Region("ru-chu", "Чукотский автономный округ"), new Region("ru-yam", "Ямало-Ненецкий автономный округ"), new Region("ru-sev", "Севастополь")];
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CulturalMonumentStyle = function () {
function CulturalMonumentStyle(value, title) {
_classCallCheck(this, CulturalMonumentStyle);
this._value = value;
this._title = title;
}
_createClass(CulturalMonumentStyle, [{
key: 'getTitle',
value: function getTitle() {
return this._title;
}
}, {
key: 'getValue',
value: function getValue() {
return this._value;
}
}]);
return CulturalMonumentStyle;
}();
var culturalMonumentStyles = [new CulturalMonumentStyle('', ''), new CulturalMonumentStyle('конструктивизм', 'конструктивизм'), new CulturalMonumentStyle('модерн', 'модерн')];
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CulturalMonumentType = function () {
function CulturalMonumentType(value, title) {
_classCallCheck(this, CulturalMonumentType);
this._value = value;
this._title = title;
}
_createClass(CulturalMonumentType, [{
key: 'getValue',
value: function getValue() {
return this._value;
}
}, {
key: 'getTitle',
value: function getTitle() {
return this._title;
}
}]);
return CulturalMonumentType;
}();
var culturalMonumentTypes = [new CulturalMonumentType('architecture', 'памятник архитектуры'), new CulturalMonumentType('history', 'памятник истории'), new CulturalMonumentType('monument', 'памятник монументального искусства'), new CulturalMonumentType('archeology', 'памятник археологии')];
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var Protection = function () {
function Protection(value, title) {
_classCallCheck(this, Protection);
this._value = value;
this._title = title;
}
_createClass(Protection, [{
key: 'getTitle',
value: function getTitle() {
return this._title;
}
}, {
key: 'getValue',
value: function getValue() {
return this._value;
}
}]);
return Protection;
}();
var protections = [new Protection('', ''), new Protection('Р', 'республиканского значения'), new Protection('М', 'местного значения'), new Protection('В', 'выявленный')];
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var RegionKz = function () {
function RegionKz(id, title) {
_classCallCheck(this, RegionKz);
this._id = id;
this._title = title;
}
_createClass(RegionKz, [{
key: "getId",
value: function getId() {
return this._id;
}
}, {
key: "getTitle",
value: function getTitle() {
return this._title;
}
}]);
return RegionKz;
}();
var regionsKz = [new RegionKz("", "не задан"), new RegionKz("kz-ala", "Алматы"), new RegionKz("kz-ast", "Астана"), new RegionKz("kz-alm", "Алматинская область"), new RegionKz("kz-akm", "Акмолинская область"), new RegionKz("kz-akt", "Актюбинская область"), new RegionKz("kz-aty", "Атырауская область"), new RegionKz("kz-vos", "Восточно-Казахстанская область"), new RegionKz("kz-zha", "Жамбылская область"), new RegionKz("kz-zap", "Западно-Казахстанская область"), new RegionKz("kz-kar", "Карагандинская область"), new RegionKz("kz-kus", "Костанайская область"), new RegionKz("kz-kzy", "Кызылординская область"), new RegionKz("kz-man", "Мангистауская область"), new RegionKz("kz-pav", "Павлодарская область"), new RegionKz("kz-sev", "Северо-Казахстанская область"), new RegionKz("kz-yuz", "Южно-Казахстанская область")];
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CulturalHeritageKZEditorForm = function () {
function CulturalHeritageKZEditorForm() {
var _this = this;
_classCallCheck(this, CulturalHeritageKZEditorForm);
this._form = ListingEditorFormComposer.createForm();
this._inputObjectName = ListingEditorFormComposer.createInputFormRowText('input-name', 'Название', 'название объекта', false, true);
this._inputType = ListingEditorFormComposer.createInputFormRowSelect('input-type', 'Тип', culturalMonumentTypes.map(function (culturalMonumentType) {
return {
title: culturalMonumentType.getTitle(),
value: culturalMonumentType.getValue()
};
}));
this._inputProtection = ListingEditorFormComposer.createInputFormRowSelect('input-protection', 'Категория охраны', protections.map(function (protection) {
return {
title: protection.getTitle(),
value: protection.getValue()
};
}));
this._inputDestroyed = ListingEditorFormComposer.createInputFormRowCheckbox('input-destroyed', 'Утрачен');
this._inputRegion = ListingEditorFormComposer.createInputFormRowSelect('input-region', 'Регион', regionsKz.map(function (regionKz) {
return {
title: regionKz.getTitle(),
value: regionKz.getId()
};
}));
this._inputDistrict = ListingEditorFormComposer.createInputFormRowText('input-district', 'Район');
this._inputMunicipality = ListingEditorFormComposer.createInputFormRowText('input-municipality', 'Населённый пункт');
this._inputBlock = ListingEditorFormComposer.createInputFormRowText('input-block', 'Квартал');
this._inputAddress = ListingEditorFormComposer.createInputFormRowText('input-address', 'Адрес', 'улица название, номер дома');
this._inputLat = ListingEditorFormComposer.createInputFormRowText('input-lat', 'Широта', '11.11111', true);
this._inputLong = ListingEditorFormComposer.createInputFormRowText('input-long', 'Долгота', '111.11111', true);
this._inputPrecise = ListingEditorFormComposer.createInputFormRowCheckbox('input-precise', 'Точные координаты');
this._inputYear = ListingEditorFormComposer.createInputFormRowText('input-year', 'Год постройки', 'yyyy', true);
this._inputAuthor = ListingEditorFormComposer.createInputFormRowText('input-author', 'Автор объекта', 'архитектор, скульптор, инженер и т.д.');
this._inputStyle = ListingEditorFormComposer.createInputFormRowSelect('input-style', 'Стиль', culturalMonumentStyles.map(function (culturalMonumentStyle) {
return {
title: culturalMonumentStyle.getTitle(),
value: culturalMonumentStyle.getValue()
};
}));
this._inputKnid = ListingEditorFormComposer.createInputFormRowText('input-knid', '№ объекта', 'dddddddddd', true);
this._inputComplex = ListingEditorFormComposer.createInputFormRowText('input-complex', '№ комплекса', 'dddddddddd', true);
this._inputImage = ListingEditorFormComposer.createInputFormRowText('input-image', 'Изображение', 'изображение на Викискладе');
this._inputWiki = ListingEditorFormComposer.createInputFormRowText('input-wiki', 'Википедия', 'статья в русской Википедии');
this._inputWdid = ListingEditorFormComposer.createInputFormRowText('input-wdid', 'Викиданные', 'идентификатор Викиданных', true);
this._inputCommonscat = ListingEditorFormComposer.createInputFormRowText('input-commonscat', 'Викисклад', 'категория Викисклада');
this._inputMunid = ListingEditorFormComposer.createInputFormRowText('input-munid', 'Викиданные нас. пункта', 'идентификатор Викиданных', true);
this._inputDocument = ListingEditorFormComposer.createInputFormRowText('input-document', 'Документ', '', true);
this._inputLink = ListingEditorFormComposer.createInputFormRowText('input-link', 'Ссылка №1', 'внешняя ссылка с дополнительной информацией об объекте');
this._inputLinkExtra = ListingEditorFormComposer.createInputFormRowText('input-linkextra', 'Ссылка №2', 'внешняя ссылка с дополнительной информацией об объекте');
var selectImageLinkRow = ListingEditorFormComposer.createRowLink('выбрать изображение из галереи');
selectImageLinkRow.linkElement.click(function () {
CommonsImagesSelectDialog.showDialog(
/*knidWLM=*/null, _this._inputKnid.inputElement.val(), _this._inputCommonscat.inputElement.val(), function (selectedImage) {
_this._inputImage.inputElement.val(selectedImage);
});
});
var tableObjectName = ListingEditorFormComposer.createTableFullWidth();
tableObjectName.tableElement.append(this._inputObjectName.rowElement);
tableObjectName.tableElement.append(ListingEditorFormComposer.createRowDivider());
this._form.formElement.append(tableObjectName.wrapperElement);
var tableObjectProperties = ListingEditorFormComposer.createTableTwoColumns();
tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.leftTableElement.append(this._inputType.rowElement);
tableObjectProperties.leftTableElement.append(this._inputProtection.rowElement);
tableObjectProperties.leftTableElement.append(this._inputDestroyed.rowElement);
tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.leftTableElement.append(this._inputRegion.rowElement);
tableObjectProperties.leftTableElement.append(this._inputDistrict.rowElement);
tableObjectProperties.leftTableElement.append(this._inputMunicipality.rowElement);
tableObjectProperties.leftTableElement.append(this._inputBlock.rowElement);
tableObjectProperties.leftTableElement.append(this._inputAddress.rowElement);
tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.leftTableElement.append(this._inputLat.rowElement);
tableObjectProperties.leftTableElement.append(this._inputLong.rowElement);
tableObjectProperties.leftTableElement.append(this._inputPrecise.rowElement);
tableObjectProperties.leftTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.leftTableElement.append(this._inputYear.rowElement);
tableObjectProperties.leftTableElement.append(this._inputAuthor.rowElement);
tableObjectProperties.leftTableElement.append(this._inputStyle.rowElement);
tableObjectProperties.rightTableElement.append(this._inputKnid.rowElement);
tableObjectProperties.rightTableElement.append(this._inputComplex.rowElement);
tableObjectProperties.rightTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.rightTableElement.append(this._inputImage.rowElement);
tableObjectProperties.rightTableElement.append(selectImageLinkRow.rowElement);
tableObjectProperties.rightTableElement.append(this._inputWiki.rowElement);
tableObjectProperties.rightTableElement.append(this._inputWdid.rowElement);
tableObjectProperties.rightTableElement.append(this._inputCommonscat.rowElement);
tableObjectProperties.rightTableElement.append(this._inputMunid.rowElement);
tableObjectProperties.rightTableElement.append(this._inputDocument.rowElement);
tableObjectProperties.rightTableElement.append(ListingEditorFormComposer.createRowDivider());
tableObjectProperties.rightTableElement.append(this._inputLink.rowElement);
tableObjectProperties.rightTableElement.append(this._inputLinkExtra.rowElement);
this._form.formElement.append(tableObjectProperties.wrapperElement);
var tableObjectDescription = ListingEditorFormComposer.createTableFullWidth();
var objectDescriptionRow = ListingEditorFormComposer.createObjectDescriptionRow();
this._inputDescription = objectDescriptionRow.inputDescription;
tableObjectDescription.tableElement.append(objectDescriptionRow.row);
tableObjectDescription.tableElement.append(ListingEditorFormComposer.createRowDivider());
this._form.formElement.append(tableObjectDescription.wrapperElement);
var tableChanges = ListingEditorFormComposer.createTableFullWidth();
var changesDescriptionRow = ListingEditorFormComposer.createChangesDescriptionRow();
this._inputChangesSummary = changesDescriptionRow.inputChangesSummary;
this._inputIsMinorChanges = changesDescriptionRow.inputIsMinorChanges;
tableChanges.tableElement.append(ListingEditorFormComposer.createRowDivider());
tableChanges.tableElement.append(changesDescriptionRow.row);
this._form.formElement.append(tableChanges.wrapperElement);
this._directMappingInputs = {
name: this._inputObjectName.inputElement,
type: this._inputType.inputElement,
protection: this._inputProtection.inputElement,
region: this._inputRegion.inputElement,
district: this._inputDistrict.inputElement,
municipality: this._inputMunicipality.inputElement,
block: this._inputBlock.inputElement,
address: this._inputAddress.inputElement,
lat: this._inputLat.inputElement,
long: this._inputLong.inputElement,
year: this._inputYear.inputElement,
author: this._inputAuthor.inputElement,
knid: this._inputKnid.inputElement,
complex: this._inputComplex.inputElement,
image: this._inputImage.inputElement,
wiki: this._inputWiki.inputElement,
wdid: this._inputWdid.inputElement,
commonscat: this._inputCommonscat.inputElement,
munid: this._inputMunid.inputElement,
document: this._inputDocument.inputElement,
link: this._inputLink.inputElement,
linkextra: this._inputLinkExtra.inputElement,
description: this._inputDescription
};
}
_createClass(CulturalHeritageKZEditorForm, [{
key: 'getForm',
value: function getForm() {
return this._form;
}
}, {
key: 'setData',
value: function setData(listingData) {
var _this2 = this;
Object.keys(this._directMappingInputs).forEach(function (key) {
if (listingData[key]) {
_this2._directMappingInputs[key].val(listingData[key]);
}
});
if (listingData['style']) {
this._inputStyle.inputElement.val(listingData['style'].toLowerCase());
}
this._inputDestroyed.inputElement.attr('checked', listingData['status'] === 'destroyed');
this._inputPrecise.inputElement.attr('checked', listingData['precise'] === 'yes');
}
}, {
key: 'getData',
value: function getData() {
var _this3 = this;
var data = {};
Object.keys(this._directMappingInputs).forEach(function (key) {
data[key] = _this3._directMappingInputs[key].val();
});
if (this._inputDestroyed.inputElement.is(':checked')) {
data['status'] = 'destroyed';
} else {
data['status'] = '';
}
if (this._inputPrecise.inputElement.is(':checked')) {
data['precise'] = 'yes';
} else {
data['precise'] = 'no';
}
data['link'] = ValidationUtils.normalizeUrl(data['link']);
data['linkextra'] = ValidationUtils.normalizeUrl(data['linkextra']);
data['style'] = this._inputStyle.inputElement.val();
return data;
}
}, {
key: 'getObjectName',
value: function getObjectName() {
return this._inputObjectName.inputElement.val();
}
}, {
key: 'getChangesSummary',
value: function getChangesSummary() {
return this._inputChangesSummary.val();
}
}, {
key: 'getChangesIsMinor',
value: function getChangesIsMinor() {
return this._inputIsMinorChanges.is(':checked');
}
}]);
return CulturalHeritageKZEditorForm;
}();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var CulturalEditorKZListingSerializer = function () {
function CulturalEditorKZListingSerializer() {
_classCallCheck(this, CulturalEditorKZListingSerializer);
}
_createClass(CulturalEditorKZListingSerializer, [{
key: "serializeListingData",
value: function serializeListingData(listingData) {
var listingSerializer = new ListingSerializer('monument kz', listingData);
listingSerializer.writeListingStart();
listingSerializer.writeParametersLine(["type", "status"]);
listingSerializer.writeParametersLine(["lat", "long", "precise"]);
listingSerializer.writeParameterLine("name");
listingSerializer.writeParameterLine("knid");
listingSerializer.writeParameterLine("complex", true);
listingSerializer.writeParametersLine(["region", "district"]);
listingSerializer.writeParametersLine(["municipality", "munid"]);
listingSerializer.writeParameterLine("block", true);
listingSerializer.writeParameterLine("address");
listingSerializer.writeParametersLine(["year", "author"]);
listingSerializer.writeParameterLine("style", true);
listingSerializer.writeParameterLine("description");
listingSerializer.writeParameterLine("image");
listingSerializer.writeParameterLine("wdid");
listingSerializer.writeParameterLine("wiki");
listingSerializer.writeParameterLine("commonscat");
listingSerializer.writeParameterLine("link");
listingSerializer.writeParameterLine("linkextra", true);
listingSerializer.writeParameterLine("document", true);
listingSerializer.writeParameterLine("doc", true);
listingSerializer.writeParameterLine("style", true);
listingSerializer.writeParameterLine("protection", true);
listingSerializer.writeParameterLine("dismissed", true);
listingSerializer.writeOtherNonEmptyParameters();
listingSerializer.writeListingEnd();
return listingSerializer.getSerializedListing();
}
}]);
return CulturalEditorKZListingSerializer;
}();
var WikitextParser = {
/**
* Given a listing index, return the full wikitext for that listing
* ("{{listing|key=value|...}}"). An index of 0 returns the first listing
* template invocation, 1 returns the second, etc.
*/
getListingWikitextBraces: function getListingWikitextBraces(wikitext, listingName, listingIndex) {
// find the listing wikitext that matches the same index as the listing index
var listingRegex = new RegExp('{{\\s*(' + listingName + ')(\\s|\\|)', 'ig');
// look through all matches for "{{listing|see|do...}}" within the section
// wikitext, returning the nth match, where 'n' is equal to the index of the
// edit link that was clicked
var listingSyntax = void 0,
regexResult = void 0,
listingMatchIndex = void 0;
for (var i = 0; i <= listingIndex; i++) {
regexResult = listingRegex.exec(wikitext);
listingMatchIndex = regexResult.index;
listingSyntax = regexResult[0];
}
// listings may contain nested templates, so step through all section
// text after the matched text to find MATCHING closing braces
// the first two braces are matched by the listing regex and already
// captured in the listingSyntax variable
var curlyBraceCount = 2;
var endPos = wikitext.length;
var startPos = listingMatchIndex + listingSyntax.length;
var matchFound = false;
for (var j = startPos; j < endPos; j++) {
if (wikitext[j] === '{') {
++curlyBraceCount;
} else if (wikitext[j] === '}') {
--curlyBraceCount;
}
if (curlyBraceCount === 0 && j + 1 < endPos) {
listingSyntax = wikitext.substring(listingMatchIndex, j + 1);
matchFound = true;
break;
}
}
if (!matchFound) {
listingSyntax = wikitext.substring(listingMatchIndex);
}
return StringUtils.trim(listingSyntax);
},
/**
* Convert raw wiki listing syntax into a mapping of key-value pairs
* corresponding to the listing template parameters.
*/
wikiTextToListing: function wikiTextToListing(wikitext) {
// remove the trailing braces if there are some
for (var i = 0; i < 2; i++) {
if (wikitext[wikitext.length - 1] === '}') {
wikitext = wikitext.slice(0, -1);
}
}
var listingData = {};
var lastKey = void 0;
var listParams = WikitextParser.listingTemplateToParamsArray(wikitext);
for (var _i = 1; _i < listParams.length; _i++) {
var param = listParams[_i];
var index = param.indexOf('=');
if (index > 0) {
// param is of the form key=value
var key = StringUtils.trim(param.substr(0, index));
listingData[key] = StringUtils.trim(param.substr(index + 1));
lastKey = key;
} else if (listingData[lastKey].length) {
// there was a pipe character within a param value, such as
// "key=value1|value2", so just append to the previous param
listingData[lastKey] += '|' + param;
}
}
return listingData;
},
/**
* Split the raw template wikitext into an array of params. The pipe
* symbol delimits template params, but this method will also inspect the
* description to deal with nested templates or wikilinks that might contain
* pipe characters that should not be used as delimiters.
*/
listingTemplateToParamsArray: function listingTemplateToParamsArray(wikitext) {
var results = [];
var paramValue = '';
var pos = 0;
while (pos < wikitext.length) {
var remainingString = wikitext.substr(pos);
// check for a nested template or wikilink
var patternMatch = WikitextParser.findPatternMatch(remainingString, "{{", "}}");
if (patternMatch.length === 0) {
patternMatch = WikitextParser.findPatternMatch(remainingString, "[[", "]]");
}
if (patternMatch.length > 0) {
paramValue += patternMatch;
pos += patternMatch.length;
} else if (wikitext.charAt(pos) === '|') {
// delimiter - push the previous param and move on to the next
results.push(paramValue);
paramValue = '';
pos++;
} else {
// append the character to the param value being built
paramValue += wikitext.charAt(pos);
pos++;
}
}
if (paramValue.length > 0) {
// append the last param value
results.push(paramValue);
}
return results;
},
/**
* Utility method for finding a matching end pattern for a specified start
* pattern, including nesting. The specified value must start with the
* start value, otherwise an empty string will be returned.
*/
findPatternMatch: function findPatternMatch(value, startPattern, endPattern) {
var matchString = '';
var startRegex = new RegExp('^' + WikitextParser.replaceSpecial(startPattern), 'i');
if (startRegex.test(value)) {
var endRegex = new RegExp('^' + WikitextParser.replaceSpecial(endPattern), 'i');
var matchCount = 1;
for (var i = startPattern.length; i < value.length; i++) {
var remainingValue = value.substr(i);
if (startRegex.test(remainingValue)) {
matchCount++;
} else if (endRegex.test(remainingValue)) {
matchCount--;
}
if (matchCount === 0) {
matchString = value.substr(0, i);
break;
}
}
}
return matchString;
},
replaceSpecial: function replaceSpecial(str) {
return str.replace(/[.?*+^$[\]\\(){}|-]/g, "\\$&");
}
};
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var WikitextSectionEditor = function () {
function WikitextSectionEditor(sectionText, listingName) {
_classCallCheck(this, WikitextSectionEditor);
this._sectionText = sectionText;
this._listingName = listingName;
this._commentReplacements = {};
this._stripComments();
}
_createClass(WikitextSectionEditor, [{
key: 'getListingData',
value: function getListingData(listingIndex) {
var listingText = WikitextParser.getListingWikitextBraces(this._sectionText, this._listingName, listingIndex);
var listingData = WikitextParser.wikiTextToListing(listingText);
for (var key in listingData) {
if (!listingData.hasOwnProperty(key)) {
continue;
}
listingData[key] = this._restoreComments(listingData[key]);
}
return listingData;
}
}, {
key: 'getSectionTextWithReplacedListing',
value: function getSectionTextWithReplacedListing(listingIndex, newListingText) {
var oldListingText = WikitextParser.getListingWikitextBraces(this._sectionText, this._listingName, listingIndex);
var result = this._sectionText;
result = result.replace(oldListingText, newListingText);
result = this._restoreComments(result);
return result;
}
}, {
key: 'getSectionTextWithAddedListing',
value: function getSectionTextWithAddedListing(newListingText) {
var result = this._sectionText;
var index = result.indexOf('{{footer');
if (index > 0) {
result = result.substr(0, index) + '\n' + newListingText + '\n' + result.substr(index);
} else {
result += '\n' + newListingText;
}
result = this._restoreComments(result);
return result;
}
/**
* Commented-out listings can result in the wrong listing being edited, so
* strip out any comments and replace them with placeholders that can be
* restored prior to saving changes.
*/
}, {
key: '_stripComments',
value: function _stripComments() {
var comments = this._sectionText.match(/<!--[\s\S]*?-->/mig);
if (comments !== null) {
for (var i = 0; i < comments.length; i++) {
var comment = comments[i];
var rep = '<<<COMMENT' + i + '>>>';
this._sectionText = this._sectionText.replace(comment, rep);
this._commentReplacements[rep] = comment;
}
}
}
/**
* Search the text provided, and if it contains any text that was
* previously stripped out for replacement purposes, restore it.
*/
}, {
key: '_restoreComments',
value: function _restoreComments(sectionText) {
for (var key in this._commentReplacements) {
var val = this._commentReplacements[key];
sectionText = sectionText.replace(key, val);
}
return sectionText;
}
}]);
return WikitextSectionEditor;
}();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var ListingSerializer = function () {
function ListingSerializer(listingType, listingData) {
_classCallCheck(this, ListingSerializer);
this._listingType = listingType;
this._listingData = listingData;
this._serializedListing = '';
this._serializedParameters = [];
}
_createClass(ListingSerializer, [{
key: 'writeListingStart',
value: function writeListingStart(addNewline) {
this._serializedListing += '{{' + this._listingType;
if (addNewline) {
this._serializedListing += "\n";
} else {
this._serializedListing += ' ';
}
}
}, {
key: 'writeParameterLine',
value: function writeParameterLine(parameterName, optional) {
var parameterValue = this._listingData[parameterName];
if (optional && (parameterValue === '' || parameterValue === undefined)) {
return;
}
if (parameterValue === undefined) {
parameterValue = '';
}
this._serializedListing += '|' + parameterName + "=" + parameterValue + "\n";
this._serializedParameters.push(parameterName);
}
}, {
key: 'writeParametersLine',
value: function writeParametersLine(parameterNames) {
for (var i = 0; i < parameterNames.length; i++) {
var parameterName = parameterNames[i];
var parameterValue = this._listingData[parameterName];
if (parameterValue === undefined) {
parameterValue = '';
}
if (i > 0) {
this._serializedListing += " ";
}
this._serializedListing += "|" + parameterName + "=" + parameterValue;
this._serializedParameters.push(parameterName);
}
this._serializedListing += "\n";
}
}, {
key: 'writeOtherNonEmptyParameters',
value: function writeOtherNonEmptyParameters() {
for (var parameterName in this._listingData) {
if (!this._listingData.hasOwnProperty(parameterName)) {
continue;
}
if (!ArrayUtils.hasElement(this._serializedParameters, parameterName)) {
var parameterValue = this._listingData[parameterName];
if (parameterValue !== '' && parameterValue !== undefined) {
this._serializedListing += '|' + parameterName + "=" + parameterValue + "\n";
}
}
}
}
}, {
key: 'writeListingEnd',
value: function writeListingEnd() {
this._serializedListing += '}}';
}
}, {
key: 'getSerializedListing',
value: function getSerializedListing() {
return this._serializedListing;
}
}]);
return ListingSerializer;
}();
var _createClass = function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; }();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
var SavingForm = function () {
function SavingForm() {
_classCallCheck(this, SavingForm);
this._progress = $('<div id="progress-dialog">' + 'Сохранение...' + '</div>');
this._progress.dialog({
modal: true,
height: 100,
width: 300,
title: ''
});
$(".ui-dialog-titlebar").hide();
}
_createClass(SavingForm, [{
key: 'destroy',
value: function destroy() {
this._progress.dialog('destroy').remove();
}
}]);
return SavingForm;
}();
InputInsertSymbols = {
addQuotesInsertHandler: function addQuotesInsertHandler(insertButton, insertToInput) {
insertButton.click(function () {
var selectionStart = insertToInput[0].selectionStart;
var selectionEnd = insertToInput[0].selectionEnd;
var oldValue = insertToInput.val();
var newValue = oldValue.substring(0, selectionStart) + "«" + oldValue.substring(selectionStart, selectionEnd) + "»" + oldValue.substring(selectionEnd);
insertToInput.val(newValue);
InputInsertSymbols._selectRange(insertToInput[0], selectionStart + 1, selectionEnd + 1);
});
},
addDashInsertHandler: function addDashInsertHandler(insertButton, insertToInput) {
insertButton.click(function () {
var caretPos = insertToInput[0].selectionStart;
var oldValue = insertToInput.val();
var newValue = oldValue.substring(0, caretPos) + "—" + oldValue.substring(caretPos);
insertToInput.val(newValue);
InputInsertSymbols._selectRange(insertToInput[0], caretPos + 1);
});
},
_selectRange: function _selectRange(element, start, end) {
if (end === undefined) {
end = start;
}
element.focus();
if ('selectionStart' in element) {
element.selectionStart = start;
element.selectionEnd = end;
} else if (element.setSelectionRange) {
element.setSelectionRange(start, end);
} else if (element.createTextRange) {
var range = element.createTextRange();
range.collapse(true);
range.moveEnd('character', end);
range.moveStart('character', start);
range.select();
}
}
};
var CommonsApi = {
baseUrl: 'https://commons.wikimedia.org/w/api.php',
executeRequest: function executeRequest(parameters, onSuccess) {
$.ajax({
url: this.baseUrl,
data: parameters,
crossDomain: true,
dataType: 'jsonp'
}).done(function (data) {
onSuccess(data);
});
},
getCategoryFiles: function getCategoryFiles(category, limit, onSuccess) {
var self = this;
self.executeRequest({
'action': 'query',
'list': 'categorymembers',
'cmtype': 'file',
'cmtitle': 'Category:' + category,
'cmlimit': 'max',
'format': 'json'
}, function (data) {
if (data.query && data.query.categorymembers) {
var files = [];
data.query.categorymembers.forEach(function (member) {
if (member.title) {
files.push(member.title);
}
});
onSuccess(files);
}
});
},
getCategoryImages: function getCategoryImages(category, limit, onSucess) {
this.getCategoryFiles(category, limit, function (files) {
var images = [];
files.forEach(function (file) {
var extension = file.toLowerCase().substr(file.length - 4);
if (extension === '.jpg' || extension === '.png' || extension === '.gif') {
images.push(file);
}
});
onSucess(images);
});
},
getImageInfo: function getImageInfo(image, onSuccess) {
var self = this;
self.executeRequest({
'action': 'query',
'titles': image,
'prop': 'imageinfo|revisions',
'iiprop': 'url',
'iiurlwidth': '200',
'iiurlheight': '200',
'rvprop': 'content',
'rvlimit': '1',
'format': 'json'
}, function (data) {
if (!data.query || !data.query.pages) {
return;
}
var pages = data.query.pages;
var firstPage = pages[Object.keys(pages)[0]];
if (!firstPage || !firstPage.imageinfo || firstPage.imageinfo.length <= 0) {
return;
}
var text = '';
if (firstPage.revisions && firstPage.revisions.length > 0) {
var revision = firstPage.revisions[0];
if (revision['*']) {
text = revision['*'];
}
}
var imageInfo = firstPage.imageinfo[0];
onSuccess({
'image': image,
'thumb': imageInfo.thumburl,
'text': text,
'url': imageInfo.url
});
});
},
getImagesInfo: function getImagesInfo(images, onSuccess) {
var self = this;
AsyncUtils.runSequence(images.map(function (image) {
return function (onSuccess) {
self.getImageInfo(image, onSuccess);
};
}), function (imageInfos) {
onSuccess(imageInfos);
});
},
/**
*
* @param categories list of category titles, e.g. ['Novosibirsk', 'Tomsk', 'Culture_of_Novosibirsk']
* @param onSuccess function which accepts single argument - list which has category
* titles for each category which has at least one file, e.g.
* ['Novosibirsk': 'Culture_of_Novosibirsk']
*/
hasCategoriesFiles: function hasCategoriesFiles(categories, onSuccess) {
var _this = this;
var maxChunkSize = 30;
AsyncUtils.runChunks(function (categoriesChunk, onSuccess) {
_this.executeRequest({
action: 'query',
titles: categoriesChunk.join("|"),
prop: 'categoryinfo',
format: 'json'
}, function (data) {
var result = [];
if (!data || !data.query || !data.query.pages) {
return;
}
Object.keys(data.query.pages).forEach(function (key) {
var pageInfo = data.query.pages[key];
if (pageInfo.title && pageInfo.categoryinfo && pageInfo.categoryinfo.files && pageInfo.categoryinfo.files > 0) {
result.push(pageInfo.title);
}
});
onSuccess(result);
});
}, maxChunkSize, categories, onSuccess);
}
};
var CommonsImagesLoader = {
loadImagesFromWLMCategory: function loadImagesFromWLMCategory(knid, onSuccess) {
var _this = this;
if (!knid) {
onSuccess([]);
} else {
CommonsApi.getCategoryImages('WLM/' + knid, 'max', function (images) {
return _this.loadImages(images, 'wlm', onSuccess);
});
}
},
loadImagesFromWLECategory: function loadImagesFromWLECategory(knid, onSuccess) {
var _this2 = this;
if (!knid) {
onSuccess([]);
} else {
CommonsApi.getCategoryImages('Protected_areas_of_Russia/' + knid, 'max', function (images) {
return _this2.loadImages(images, 'wlm', onSuccess);
});
}
},
loadImagesFromCommonsCategory: function loadImagesFromCommonsCategory(commonsCat, onSuccess) {
var _this3 = this;
if (!commonsCat) {
onSuccess([]);
} else {
CommonsApi.getCategoryImages(commonsCat, 'max', function (images) {
return _this3.loadImages(images, 'commons', onSuccess);
});
}
},
loadImages: function loadImages(images, categoryType, onSuccess) {
CommonsApi.getImagesInfo(images, onSuccess);
}
};
var CommonsImagesSelectDialog = {
showDialog: function showDialog(knidWLM, knidWLE, commonsCat, onImageSelected) {
var dialogElement = $('<div>');
dialogElement.dialog({
modal: true,
height: 400,
width: 800,
title: 'Выбор изображения из галереи'
});
var loadingElement = $('<div>', { 'html': 'загрузка...' });
var contentElement = $('<div>');
dialogElement.append(contentElement);
dialogElement.append(loadingElement);
function createImageElement(image) {
var imageThumbElement = $('<img>', { 'alt': 'Image', 'src': image.thumb });
var commonsUrl = 'https://commons.wikimedia.org/wiki/' + image.image;
var selectLink = $('<a>', {
href: 'javascript:;',
html: '[выбрать]'
});
var viewLink = $('<a>', {
href: commonsUrl,
target: '_blank',
html: '[смотреть]'
});
selectLink.click(function () {
var imageName = image.image.replace(/^File:/, '').replace(' ', '_');
onImageSelected(imageName);
dialogElement.dialog('destroy');
});
var imageBlock = $('<div>', {
style: 'padding: 5px; width: 210px; display: flex; flex-direction: column;' + 'justify-content: center; align-items: center; align-content: center;'
});
imageBlock.append(imageThumbElement);
imageBlock.append(selectLink);
imageBlock.append(viewLink);
return imageBlock;
}
function createImagesBlock(blockTitle, images) {
var block = $('<div>');
block.append($('<h5>', { 'html': blockTitle }));
var currentRow = null;
var imagesInRow = 0;
function addImage(image) {
if (!currentRow || imagesInRow >= 4) {
currentRow = $('<div>', {
style: 'display: flex; flex-direction: row'
});
block.append(currentRow);
imagesInRow = 0;
}
currentRow.append(createImageElement(image));
imagesInRow++;
}
images.forEach(function (image) {
addImage(image);
});
return block;
}
CommonsImagesLoader.loadImagesFromWLMCategory(knidWLM, function (wlmImages) {
if (wlmImages.length > 0) {
contentElement.append(createImagesBlock("Изображения из категории WLM", wlmImages));
}
CommonsImagesLoader.loadImagesFromWLECategory(knidWLE, function (wleImages) {
if (wleImages.length > 0) {
contentElement.append(createImagesBlock("Изображения из категории WLE", wleImages));
}
CommonsImagesLoader.loadImagesFromCommonsCategory(commonsCat, function (commonsCatImages) {
if (commonsCatImages.length > 0) {
contentElement.append(createImagesBlock("Изображения из категории Commons", commonsCatImages));
}
if (wlmImages.length === 0 && wleImages.length === 0 && commonsCatImages.length === 0) {
contentElement.append($('<div>', { 'html': "Для данного объекта нет ни одного изображения" }));
}
loadingElement.hide();
});
});
});
}
};
function initListingEditor(_ref) {
var listingPageNamespace = _ref.listingPageNamespace,
formClass = _ref.formClass,
listingSerializerClass = _ref.listingSerializerClass,
listingTemplateName = _ref.listingTemplateName,
helpPageUrl = _ref.helpPageUrl;
function isListingPage() {
return StringUtils.contains(MediaWikiPage.getPageName(), listingPageNamespace);
}
if (!ListingEditorUtils.isEditablePage() || !isListingPage()) {
return;
}
function showHelp() {
window.open(helpPageUrl);
}
function showListingEditorDialogAdd(sectionIndex, sectionWikitext) {
var sectionEditor = new WikitextSectionEditor(sectionWikitext, listingTemplateName);
var form = new formClass();
function onFormSubmit(captchaId, captchaAnswer) {
var listingSerializer = new listingSerializerClass();
var newListingText = listingSerializer.serializeListingData(form.getData());
var updatedWikitext = sectionEditor.getSectionTextWithAddedListing(newListingText);
var changesSummary = composeChangesSummary(sectionWikitext, form, commonMessages.changesSummaryAdded);
var savingForm = new SavingForm();
MediaWikiPageWikitext.saveSectionWikitext(sectionIndex, updatedWikitext, changesSummary, form.getChangesIsMinor(), captchaId, captchaAnswer,
/*onSuccess=*/function () {
window.location.reload();
},
/*onFailure*/function (message) {
savingForm.destroy();
alert(message);
},
/*onCaptcha*/function (captchaImgSrc, captchaId) {
savingForm.destroy();
new CaptchaDialog(captchaImgSrc, function (captchaAnswer) {
onFormSubmit(captchaId, captchaAnswer);
});
});
}
ListingEditorDialog.showDialog(form.getForm().formElement, commonMessages.addTitle,
/*onSubmit=*/onFormSubmit,
/*onCancel=*/function () {
form.getForm().formElement.dialog('destroy').remove();
},
/*onHelp=*/showHelp);
}
function showListingEditorDialogEdit(sectionIndex, listingIndex, sectionWikitext) {
var sectionEditor = new WikitextSectionEditor(sectionWikitext, listingTemplateName);
var listingData = sectionEditor.getListingData(listingIndex);
var form = new formClass();
form.setData(listingData);
function onFormSubmit(captchaId, captchaAnswer) {
var listingSerializer = new listingSerializerClass();
var newListingText = listingSerializer.serializeListingData(ObjectUtils.merge(listingData, form.getData()));
var updatedWikitext = sectionEditor.getSectionTextWithReplacedListing(listingIndex, newListingText);
var changesSummary = composeChangesSummary(sectionWikitext, form, commonMessages.changesSummaryUpdated);
var savingForm = new SavingForm();
MediaWikiPageWikitext.saveSectionWikitext(sectionIndex, updatedWikitext, changesSummary, form.getChangesIsMinor(), captchaId, captchaAnswer,
/*onSuccess=*/function () {
window.location.reload();
},
/*onFailure*/function (message) {
savingForm.destroy();
alert(message);
},
/*onCaptcha*/function (captchaImgSrc, captchaId) {
savingForm.destroy();
new CaptchaDialog(captchaImgSrc, function (captchaAnswer) {
onFormSubmit(captchaId, captchaAnswer);
});
});
}
ListingEditorDialog.showDialog(form.getForm().formElement, commonMessages.editTitle,
/*onSubmit=*/onFormSubmit,
/*onCancel=*/function () {
form.getForm().formElement.dialog('destroy').remove();
},
/*onHelp=*/showHelp);
}
function composeChangesSummary(sectionWikitext, form, changesType) {
var changesSummary = getChangesSummarySection(sectionWikitext);
changesSummary += changesType + " " + form.getObjectName();
var userChangesSummary = StringUtils.trim(form.getChangesSummary());
if (userChangesSummary.length > 0) {
changesSummary += " - " + userChangesSummary;
}
return changesSummary;
}
function onAddNewListing(sectionIndex) {
MediaWikiPageWikitext.loadSectionWikitext(sectionIndex, function (wikitext) {
return showListingEditorDialogAdd(sectionIndex, wikitext);
});
}
function onEditListing(sectionIndex, listingIndex) {
MediaWikiPageWikitext.loadSectionWikitext(sectionIndex, function (wikitext) {
return showListingEditorDialogEdit(sectionIndex, listingIndex, wikitext);
});
}
function getChangesSummarySection(sectionWikitext) {
var sectionName = MediaWikiPageWikitext.getSectionName(sectionWikitext);
return sectionName.length ? '/* ' + sectionName + ' */ ' : "";
}
var listingPageElements = ListingEditorUtils.getListingPageElements();
var sections = listingPageElements.getSections();
for (var i = 0; i < sections.length; i++) {
var addButton = ListingEditorButtons.createListingAddButton(sections[i]);
addButton.click(function (section) {
onAddNewListing(section.getSectionIndex());
});
}
var listingTables = listingPageElements.getListingTables();
for (var _i = 0; _i < listingTables.length; _i++) {
var editButton = ListingEditorButtons.createListingEditButton(listingTables[_i]);
editButton.click(function (listingTable) {
onEditListing(listingTable.getSectionIndex(), listingTable.getListingIndex());
});
}
}
function culturalHeritageKZEditorMain() {
var helpPageUrl = "https://ru.wikivoyage.org/wiki/%D0%9E%D0%B1%D1%81%D1%83%D0%B6%D0%B4%D0%B5%D0%BD%D0%B8%D0%B5:%D0%9A%D1%83%D0%BB%D1%8C%D1%82%D1%83%D1%80%D0%BD%D0%BE%D0%B5_%D0%BD%D0%B0%D1%81%D0%BB%D0%B5%D0%B4%D0%B8%D0%B5_%D0%9A%D0%B0%D0%B7%D0%B0%D1%85%D1%81%D1%82%D0%B0%D0%BD%D0%B0";
initListingEditor({
listingPageNamespace: 'Культурное_наследие_Казахстана',
formClass: CulturalHeritageKZEditorForm,
listingSerializerClass: CulturalEditorKZListingSerializer,
listingTemplateName: "monument kz",
helpPageUrl: helpPageUrl
});
}
culturalHeritageKZEditorMain();
});