Замечание: Возможно, после публикации вам придётся очистить кэш своего браузера, чтобы увидеть изменения.

  • 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('&nbsp;[<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('&nbsp;');              }          });          // 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('&#32;<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('&nbsp;<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() == '&nbsp;'); }  } ( mediaWiki, jQuery ) );