Участник:Andyrom75/Sandbox.js

Материал из Wikivoyage

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

  • Firefox / Safari: Удерживая клавишу Shift, нажмите на панели инструментов Обновить либо нажмите Ctrl+F5 или Ctrl+R (⌘+R на Mac)
  • Google Chrome: Нажмите Ctrl+Shift+R (⌘+Shift+R на Mac)
  • Internet Explorer / 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:'hello@example.com'},
     '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 ) );