Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.
- Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
- Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
- Edge: Удерживая Ctrl, нажмите Обновить либо нажмите Ctrl+F5
- Opera: Нажмите Ctrl+F5.
/****************************************************************** Listing Editor v1.4.2 (torty3) ********************************************************************/ ( function ( mw, $ ) { 'use strict'; var namespace = mw.config.get( 'wgNamespaceNumber' ); if (namespace != 0 && namespace != 2 && namespace != 4) { return; } if ( mw.config.get('wgAction') != 'view' || $('#mw-revision-info').length || mw.config.get('wgCurRevisionId') != mw.config.get('wgRevisionId') || $('#ca-viewsource').length ) { return; } // **RUS** Added facebook, vkontakte, skype, format, wdid, unesco, star. Removed tollfree, checkin, checkout. var allFields = { 'type': {size:8, right:true, newline:true, parameter:'type', label:'Тип', tip:'тип объекта, определяющий значок на карте' }, 'name': {size:36, right:false, newline:true, parameter:'name', label:'Название', tip:'название объекта'}, 'alt': {size:36, right:false, newline:false, parameter:'alt', label:'Дополнение', tip:'другое название или пояснение'}, 'url': {size:36, right:false, newline:false, parameter:'url', label:'Веб-сайт', tip:'http://www.example.com'}, 'email': {size:32, right:true, newline:true, parameter:'email', label:'E-mail', tip:'[email protected]'}, 'facebook': {size:36, right:false, newline:true, parameter:'facebook', label:'Facebook', tip:'https://www.facebook.com/example'}, 'vkontakte': {size:36, right:false, newline:true, parameter:'vkontakte', label:'ВКонтакте', tip:'http://vk.com/example'}, 'skype': {size:36, right:false, newline:true, parameter:'skype', label:'Скайп', tip:'контакт в Скайпе'}, 'address': {size:36, right:false, newline:false, parameter:'address', label:'Адрес', tip:'адрес объекта'}, 'lat': {size:10, right:true, newline:false, parameter:'lat', label:'Широта', tip:'11.11111'}, 'long': {size:10, right:true, newline:false, parameter:'long', label:'Долгота', tip:'111.11111'}, 'directions': {size:36, right:false, newline:true, parameter:'directions', label:'Пояснения', tip:'пояснения, в том числе транспорт'}, 'phone': {size:20, right:false, newline:false, parameter:'phone', label:'Телефон', tip: '+55 555 555-5555'}, 'fax': {size:20, right:true, newline:true, parameter:'fax', label:'Факс', tip: '+55 555 555-555'}, 'image': {size:32, right:true, newline:true, parameter:'image', label:'Изображение', tip:'имя файла на Commons'}, 'hours': {size:20, right:false, newline:false, parameter:'hours', label:'Часы работы', tip: '09:00-18:00'}, //'checkin': {size:12, right:true, newline:false, parameter:'checkin', label:'Check-in', tip: 'check in time'}, //'checkout': {size:12, right:true, newline:false, parameter:'checkout', label:'Check-out', tip: 'check out time'}, 'format': {size:8, right:false, newline:true, parameter:'format', label:'Форматирование', tip:''}, 'unesco': {right:true, newline:false, parameter:'unesco', label:'ЮНЕСКО?', tip:''}, 'star': {right:true, newline:false, parameter:'star', label:'Важный?', tip:''}, 'wdid': {size:20, right:false, newline:true, parameter:'wdid', label:'Викиданные', tip:'Qxxxxx'}, //'tollfree': {size:20, right:true, newline:false, parameter:'tollfree', label:'Tollfree', tip:'+1 800 100 1000'}, 'price': {size:20, right:false, newline:true, parameter:'price', label:'Стоимость', tip: '100 руб'}, 'lastedit': {size:10, right:false, newline:true, parameter:'lastedit', label:'Last Updated', tip: '2015-01-15'}, // **RUS** parameter content->description 'description': {cols:34, rows:8, right:false, newline:true, parameter:'description', label:'Описание', tip: 'описание объекта'} }; //**RUS** added RUB sign var currencySigns = ['\u00A3', '\u20AC', '\u00A5', '\u20A9', '\u20bd']; //**RUS** added 'go' and 'vicinity', changed 'listing' to 'other' var listingTypes = {'see':'see', 'do':'do', 'go':'go', 'buy':'buy', 'eat':'eat', 'drink':'drink', 'sleep':'sleep', 'other':'other', 'vicinity':'vicinity'}; //**RUS** translated keys and assigned corresponding values var sectionHeadings = {'Как добраться':'go', 'Достопримечательности':'see', 'Чем заняться':'do', 'Покупки':'buy', 'Еда':'eat', 'Ночная жизнь':'drink', 'Где остановиться':'sleep', 'Связь':'other', 'Окрестности':'vicinity'}; 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 translateStr = { 'add': 'добавить объект', 'edit': 'edit', 'add-dialog': 'Добавить объект', 'edit-dialog': 'Редактировать объект', 'closed': 'Закрылся?', 'saving': 'Сохранение', 'submit': 'Сохранить', 'cancel': 'Отмена', 'validationalert': 'Пожалуйста, укажите название или адрес', 'added': 'Добавлен объект ', 'updated': 'Обновлён объект ', 'removed': 'Удалён объект ', 'cities': 'Города', 'destination': 'Other_destinations', 'geomap': 'найти на карте', 'help-page': 'http://en.wikivoyage.org/wiki/Wikivoyage:Listing_editor', 'enter-captcha': 'Введите CAPTCHA', 'external-links': 'Введённый текст содержит внешние ссылки.', //**RUS** added the following labels 'icon-pencil-title': 'Редактировать объект' }; var EDIT_LINK_CONTAINER = 'span.listing-metadata-items'; var LISTING_CONTAINER = 'span.vcard'; var sectionText, listingText, inlineListing; wrapContent(); addListingButtons(); addEditButtons(); // makes it easier to traverse the DOM - but potential for code incompatibility function wrapContent() { $('h2').each(function(){ $(this).nextUntil("h2").addBack().wrapAll('<div class="mw-h2section" />'); }); } function addListingButtons () { if ($('#'+translateStr['cities']).length || $('#'+translateStr['destination']).length || $('#'+'Islands').length || $('#'+'print-districts').length) { return false; } var editButton = $('<span class="mw-addlisting noprint">') .html(' [<a href="javascript:">'+translateStr['add']+'</a>]' ) .click(function() { var listingEntry = $(this).parent(); popupForm('add', listingEntry); }); for (var key in sectionHeadings) { key = encodeURIComponent(key).replace(/%20/g,'_').replace(/%/g,'.'); $(document.getElementById(key)).parent('h2').addClass('mw-addhere'); $(document.getElementById(key)).closest('div.mw-h2section').children('h3').addClass('mw-addhere'); } $('.mw-addhere').append(editButton); } function addEditButtons () { var editButton = $('<span class="vcard-edit-button noprint">') //**RUS** added class and title parameters .html('<a href="javascript:" class="icon-pencil" title="' + translateStr['icon-pencil-title'] + '">'+translateStr['edit']+'</a>' ) .click(function() { var listingEntry = $(this).closest(LISTING_CONTAINER); popupForm('edit', listingEntry); }); // if there is already metadata present add a separator $(EDIT_LINK_CONTAINER).each(function() { if (!isElementEmpty(this)) { //**RUS** removed '|' sign $(this).append(' '); } }); // append the edit link $(EDIT_LINK_CONTAINER).append( editButton ); } /*** Functions to retrieve entry details ***/ function getIdentifier(entry) { var id = {}; var name = entry.find('.listing-name').text(); var address = entry.find('.label').text(); var alt = entry.find('.listing-alt').text(); if (name) { id['name'] = name; } else if (address) { id['address'] = address; } else { id['alt'] = alt; } return id; } function isInline(entry) { if (entry.parent('p').length == 0) return false; return true; } function findSectionNumber(entry) { var link = entry.find( '.mw-editsection a' ).attr( 'href' ); if (link === undefined) link = entry.closest('div.mw-h2section').find( '.mw-editsection a' ).attr( 'href' ); if (link != undefined) return link.split( '=' ).pop(); return 0; } function findSectionType(entry) { var section = entry.closest('div.mw-h2section').children('h2').find('.mw-headline').attr('id'); //**RUS** added the following line section = decodeURIComponent(section.replace(/\./g,'%').replace(/_/g,'%20')); for (var key in sectionHeadings) { if (section == key) return sectionHeadings[key]; } //**RUS** changed 'listing' to 'other' return listingTypes.other; } function getSectionText(number) { var wikiText = $.ajax({ url: mw.util.wikiScript(''), data: { title:mw.config.get('wgPageName'), action:'raw', section:number }, async: false, cache: false // required }).responseText; return wikiText; } function replaceSpecial( str ) { return str.replace(/([.?*+^$[\]\\(){}|-])/g, "\\$1"); } function getListingWikitextBraces(entry) { sectionText = sectionText.replace(/[^\S\n]+/g,' '); var id = getIdentifier(entry); for (var key in id) break; var search = allFields[key]['parameter']; id[key] = replaceSpecial(id[key]); var listingRegex = new RegExp(search+"\\s?=\\W*?"+id[key]+"\\W*?(\\||}})"); var string = sectionText.match(listingRegex)[0]; var index = sectionText.indexOf(string); var curly = 2; var str1 = '', str2 = ''; // search for open and close braces for (var i=index; i>0; i--) { if (sectionText[i]=='}') ++curly; else if (sectionText[i]=='{') --curly; if(curly == 0) { str1 = sectionText.substr(i,index-i); break; } } if (string.indexOf('}}') < 0) curly = 2; var textLength = sectionText.length; for (var j=index+string.length; j<textLength; j++) { if (sectionText[j]=='{') ++curly; else if (sectionText[j]=='}') --curly; if (curly == 0) { str2 = sectionText.substr(index, j-index+1); break; } } if (str2 === '') str2 = sectionText.substr(index, textLength); string = str1 + str2; return $.trim(string); } function wikiTextToListing(string) { //**RUS** added 'go', 'vicinity', changed 'listing' to 'other' var typeRegex = new RegExp('{{('+listingTypes['go']+listingTypes['see']+'|'+listingTypes['do'] +'|'+listingTypes['buy'] +'|'+listingTypes['eat'] + '|'+listingTypes['drink'] +'|'+listingTypes['sleep']+'|'+listingTypes['other']+listingTypes['vicinity']+')','g'); string = string.slice(0,-2); string = string.replace(typeRegex,'{{listing| '+allFields['type']['parameter']+'=$1'); string = string.replace(/{{vCard/g,'{{listing'); var listing = {}; var lastKey; var listParams = string.split('|'); for (var j=1;j<listParams.length;j++) { var param = listParams[j]; var index = param.indexOf('='); if (index > 0) { var key = $.trim(param.substr(0, index)); var value = $.trim(param.substr(index+1)); listing[key] = value; lastKey = key; } else if (listing[lastKey].length) { listing[lastKey] += '|' + param; } } return listing; } function getListing (entry) { listingText = getListingWikitextBraces(entry); var listing = wikiTextToListing(listingText); return listing; } /*** Functions to handle form creation and editing ***/ function popupForm(mode, entry) { mw.loader.using( ['jquery.ui'], function () { var sectionType, listing; var sectionNumber = findSectionNumber(entry); inlineListing = isInline(entry); sectionText = getSectionText(sectionNumber); if (mode == 'add') { sectionType = findSectionType(entry); listing = {}; } else { sectionType = ''; listing = getListing(entry); } var form = $(createForm(mode, sectionType, listing)); // modal form - must submit or cancel form.dialog({ modal: true, height: 'auto', width: 'auto', title: translateStr[mode + '-dialog'], buttons: [ { text: '?', id: 'listing-help', click: function() { window.open(translateStr['help-page']);}}, { text: translateStr['submit'], click: function() { if(validateForm()) { formToText(mode, sectionNumber); $(this).dialog('close'); } } }, {text: translateStr['cancel'], click: function() {$(this).dialog('destroy').remove()}} ], open: function() { $('.ui-dialog-buttonpane').append('<div style="width:360px;padding-top:0.8em;font-size:xx-small;">'+LICENSE_TEXT+'</div>'); if ($('#input-address').val() != '') { $('#geomap-link').attr('href', $('#geomap-link').attr('href') + '&location=' + encodeURIComponent($('#input-address').val())); } else if ($('#input-name').val() != '') { $('#geomap-link').attr('href', $('#geomap-link').attr('href') + '&location=' + encodeURIComponent($('#input-name').val())); } $('#input-address').change( function () { var link = $('#geomap-link').attr('href'); var index = link.indexOf('&location'); if (index < 0) index = link.length; $('#geomap-link').attr('href', link.substr(0,index) + '&location=' + encodeURIComponent($('#input-address').val())); }); }, close: function() { $(this).dialog('destroy').remove()} }); }); } function createForm(mode, type, listing) { var form = $('<form id="listing-editor">'); var leftFields = $('<fieldset id="left-fields">').appendTo(form); var rightFields = $('<fieldset id="right-fields">').appendTo(form); $('<div style="clear:both">').appendTo(form); //create form according to fields for (var key in allFields) { var keyvalue = allFields[key]; var node = $('<div class="input-text">') .attr('id', 'div_' + key); var label = $('<label>').appendTo(node) .text(keyvalue['label']) .attr('for', 'input-' + key); // input text for everything except content which gets textarea var parameter = keyvalue['parameter']; if (key == 'type') { var subnode = $('<select id="option-type">').appendTo(node); for (var n in listingTypes) { var option = $('<option value="'+listingTypes[n]+'">'); option.text(listingTypes[n]).appendTo(subnode); } if (mode == 'add') { subnode.val(listingTypes[type]); listing[parameter] = listingTypes[type]; } } //**RUS** added 2 following conditions else if (key == 'unesco') { var subnode = $('<input type="checkbox">').appendTo(node); } else if (key == 'star') { var subnode = $('<input type="checkbox">').appendTo(node); } //**RUS** global change 'content'->'description' else if (key != 'description') { var subnode = $('<input type="text">').appendTo(node) .attr('size', keyvalue['size']); } else { var subnode = $('<textarea>').appendTo(node) .attr('cols', keyvalue['cols']) .attr('rows', keyvalue['rows']); } subnode.attr('placeholder', keyvalue['tip']) .attr('id', 'input-' + key); if (listing[parameter]) { //**RUS** added the following condition if ((key == 'star' || key == 'unesco') && (listing[parameter] == 'yes')) { subnode.prop('checked', true); } else { subnode.val(listing[parameter]); } } //**RUS** commented out the next string //if (listing[allFields['type']['parameter']] == listingTypes['sleep'] && key == 'hours') node.hide(); //**RUS** removed checkin, checkout, image conditions. added format one if (key == 'fax' || key == 'format' || key == 'lastedit' ) node.hide(); // some special form features if (key == 'type' && mode == 'edit') { var closedSpan = $('<span id="span_closed">'); var closedLabel = $('<label for="input-closed">').appendTo(closedSpan) .text(translateStr['closed']); var closedInput = $('<input type="checkbox">').appendTo(closedSpan) .attr('id', 'input-closed'); node.append(closedSpan); } if (key == 'price') { var currencySpan = $('<span id="span_currency">'); for (var i=0; i < currencySigns.length; i++) { var currencyButton = $('<span class="currency-signs">') .html(' <u><a href="javascript:">'+currencySigns[i]+'</a></u>' ) .click(function() { var caretPos = document.getElementById('input-price').selectionStart; var price = $('#input-price').val(); $('#input-price').val(price.substring(0, caretPos) + $(this).find('a').text() + price.substring(caretPos) ); }); currencySpan.append(currencyButton); } node.append(currencySpan); } if (key == 'lat') { var latlngStr = '?'; if ($('#geodata').length) { var latlng = $('#geodata').text().split('; '); latlngStr += 'lat='+latlng[0]+'&lon='+latlng[1]+'&zoom=15'; } node.append(' <u><a id="geomap-link" target="_blank" ' +'href="http://maps.wikivoyage-ev.org/w/geomap.php'+latlngStr+'">' +translateStr['geomap']+'</a></u>'); } //**RUS** global change 'content'->'description' if (key == 'description') { form.append(node); } else if (allFields[key]['right'] == true) { rightFields.append(node); } else { leftFields.append(node); } } return form; } function validateForm() { //TODO more form validation? if ($('#input-name').val() == '' && $('#input-address').val() == '' && $('#input-alt').val() == '') { alert(translateStr['validationalert']); return false; } //**RUS** global change 'content'->'description' $('#input-description').val($.trim($('#input-description').val()).replace(/\n+/g, ' ')); var webRegex = new RegExp('^https?://', 'i'); var url = $('#input-url').val(); if (!webRegex.test(url) && url != '') { $('#input-url').val('http://' + url); } return true; } function upperCaseFirst(str) { str = str.toLowerCase().replace(/\b[a-z]/g, function(letter) { return letter.toUpperCase(); }); return str; } function formToText(mode, number) { var listing = {}; for ( var key in allFields ) { var parameter = allFields[key]['parameter']; //**RUS** added the following condition if (key == 'star' || key == 'unesco') { listing[parameter]= $("#input-"+key).is(':checked') ? 'yes' : ''; } else { listing[parameter]= $("#input-"+key).val(); } } //**RUS** check for wdid parater instead of checkin and checkout if (mode == 'add' && listing[allFields['type']['parameter']] != listingTypes.see && listing[allFields['type']['parameter']] != listingTypes.do && listing[allFields['type']['parameter']] != listingTypes.go && listing[allFields['type']['parameter']] != listingTypes.vicinity) { listing[allFields['wdid']['parameter']] = null; } listing[allFields['lastedit']['parameter']] = currentLastEditDate(); var text = listingToStr(listing); var summary = '/* ' +upperCaseFirst($("#input-type").val()) + ' */ '; if (mode == 'add') { summary += translateStr['added']; var index = sectionText.indexOf('==='); if ( index == 0 ) { index = sectionText.indexOf('===='); } if ( index > 0 ) { sectionText = sectionText.substr(0, index) + text + '\n' + sectionText.substr(index); } else { sectionText += '\n'+ text; } } else { if ($('#input-closed').is(':checked')) { text = ''; summary += translateStr['removed']; var listRegex = new RegExp('\\n\\*+\\s?'+replaceSpecial(listingText)); sectionText = sectionText.replace(listRegex, listingText); } else { summary += translateStr['updated']; } sectionText = sectionText.replace(listingText, text); } summary += $("#input-name").val(); saveForm(summary, sectionText, number, '', ''); return; } function savingForm() { var progress = $('<div id="progress-dialog">'+translateStr['saving']+'...</div>'); progress.dialog({ modal: true, height: 100, width: 300, title: '' }); $(".ui-dialog-titlebar").hide(); } function saveForm(summary, content, number, cid, answer) { $.ajax( { url: mw.util.wikiScript( 'api' ), data: { 'format': 'json', 'action': 'edit', 'title': mw.config.get('wgPageName'), 'section': number, 'token': mw.user.tokens.get( 'csrfToken' ), 'text': content, 'summary': summary, 'captchaid': cid, 'captchaword': answer }, type: 'POST', datatype: 'json', success: function( data ) { if ( data && data.edit && data.edit.result == 'Success' ) { window.location.reload(); // reload page if edit was successful } else if ( data && data.error ) { alert( 'Error: API returned error code "' + data.error.code + '": ' + data.error.info ); } else if ( data && data.edit.spamblacklist ) { alert( 'Error: "'+ data.edit.spamblacklist + '" has been blacklisted' ); $('#progress-dialog').dialog('destroy').remove(); } else if ( data && data.edit.captcha ) { var captcha = $('<div id="captcha-dialog">').text(translateStr['external-links']); var image = $('<img class="fancycaptcha-image">') .attr('src', data.edit.captcha.url) .appendTo(captcha); var label = $('<label for="input-captcha">').text(translateStr['enter-captcha']).appendTo(captcha); var input = $('<input id="input-captcha" type="text">').appendTo(captcha); captcha.dialog({ title: translateStr['enter-captcha'], buttons: [ { text: translateStr['submit'], click: function() { saveForm(summary, content, number, data.edit.captcha.id, $('#input-captcha').val()); } }, { text: translateStr['cancel'], click: function() { $(this).dialog('destroy').remove(); $('#progress-dialog').dialog('destroy').remove(); }} ] }); } else { alert( 'Error: Unknown result from API.' ); } }, error: function( xhr ) { alert( 'Error: Request failed.' ); } } ) savingForm(); } //**RUS** almost completely reimplemeted the following method function listingToStr(listing) { var allFields = { 'lat': {newline:false}, 'long': {newline:false}, 'wdid': {newline:true}, 'name': {newline:false}, 'alt': {newline:false}, 'image': {newline:true}, 'address': {newline:false}, 'directions': {newline:true}, 'url': {newline:false}, 'facebook': {newline:false}, 'vkontakte': {newline:true}, 'phone': {newline:false}, 'fax': {newline:false}, 'email': {newline:false}, 'skype': {newline:true}, 'hours': {newline:false}, 'price': {newline:true}, 'lastedit': {newline:true}, 'description': {newline:true}, 'format': {newline:true}, 'unesco': {newline:true}, 'star': {newline:true} }; var saveStr = '{{listing|type=' + listing['type']; for ( var key in allFields ) { // if format, unesco or star parameter is empty - don't include it in the listing if ((key == 'format' && listing['format'] == '') || (key == 'unesco' && listing['unesco'] == '') || (key == 'star' && listing['star'] == '')) { continue; } // wdid exists only for see, do, go, vicinity if (key == 'wdid' && listing['type'] != 'see' && listing['type'] != 'do' && listing['type'] != 'go' && listing['type'] != 'vicinity') { saveStr += '\n'; continue; } saveStr +='| ' + key + '=' + listing[key]; if (allFields[key]['newline']) { saveStr += '\n'; } else { saveStr += ' '; } } saveStr += '}}'; return saveStr; } function currentLastEditDate() { // return the date as "2015-01-15" var d = new Date(); var year = d.getFullYear(); // Date.getMonth() returns 0-11 var month = d.getMonth() + 1; if (month < 10) month = '0' + month; var day = d.getDate(); if (day < 10) day = '0' + day; return year + '-' + month + '-' + day; } function isElementEmpty(element) { var text = $(element).text(); if (!text.trim()) { return true; } return (text.trim() == ' '); } } ( mediaWiki, jQuery ) );