Μετάβαση στο περιεχόμενο

Χρήστης:Gobbler/test.js

Από Βικιταξίδια

Σημείωση: μετά την δημοσίευση, ίσως χρειαστεί να παρακάμψετε την προσωρινή μνήμη του προγράμματος περιήγησής σας για να δείτε τις αλλαγές.

  • 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';
 
    importStylesheet('Mediawiki:Gadget-ListingEditor.css');

    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-diff-ntitle1').length || $('#ca-viewsource').length ) {
        return;
    }
 
    var allFields = {
        'type': {size:8, right:true, newline:true, parameter:'type', label:'Type', tip:'type of listing' },
        'name': {size:36, right:false, newline:false, parameter:'name', label:'Name', tip:'name of place'},
        'alt': {size:32, right:true, newline:false, parameter:'alt', label:'alt', tip:'also known as'},
        'url': {size:36, right:false, newline:false, parameter:'url', label:'Website', tip:'http://www.example.com'},
        'email': {size:32, right:true, newline:true, parameter:'email', label:'Email', tip:'hello@example.com'},
        'address': {size:36, right:false, newline:false, parameter:'address', label:'Address', tip:'address of place'},
        'lat': {size:10, right:true, newline:false, parameter:'lat', label:'Latitude', tip:'11.11111'},
        'long': {size:10, right:true, newline:false, parameter:'long', label:'Longitude', tip:'111.11111'},
        'directions': {size:36, right:false, newline:true, parameter:'directions', label:'Directions', tip:'how to get here'},
        'phone': {size:24, right:false, newline:false, parameter:'phone', label:'Phone', tip: '+55 555 555-5555'},
        'tollfree': {size:20, right:true, newline:false, parameter:'tollfree', label:'Tollfree', tip:'+1 800 100 1000'},
        'fax': {size:20, right:true, newline:false, parameter:'fax', label:'Fax', tip: '+55 555 555-555'},
        'image': {size:20, right:true, newline:true, parameter:'image', label:'Image', tip: 'image of place'},
        'hours': {size:28, right:false, newline:false, parameter:'hours', label:'Hours', tip: '9AM-5PM or 9:00-17: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'},
        'price': {size:28, right:false, newline:true, parameter:'price', label:'Price', tip: 'entry or service price'},
        'content': {cols:34, rows:8, right:false, newline:true, parameter:'content', label:'Content', tip: 'description of place'}
    };
 
    var currencySigns = ['\u00A3', '\u20AC', '\u00A5', '\u20A9'];
    var listingTypes = {'see':'see', 'do':'do', 'buy':'buy', 'eat':'eat', 'drink':'drink', 'sleep':'sleep', 'listing':'listing'};
    var sectionHeadings = {'See':'see', 'Do':'do', 'Buy':'buy', 'Eat':'eat', 'Drink':'drink', 'Sleep':'sleep', 'Connect':'listing', 'Wait':'see', 'See_and_Do':'see', 'Eat_and_Drink':'eat'};
    var LICENSE_TEXT = 'By clicking "Submit", you agree to the <a class="external" target="_blank" href="http://wikimediafoundation.org/wiki/Terms_of_use">Terms of use</a>, and you irrevocably agree to release your contribution under the <a class="external" target="_blank" href="http://en.wikivoyage.org/wiki/Wikivoyage:Full_text_of_the_Attribution-ShareAlike_3.0_license">CC-BY-SA 3.0 License</a>.'
    var translateStr = {
        'add': 'add listing',
        'edit': 'edit',
        'closed': 'Closed?',
        'saving': 'Saving',
        'submit': 'Submit',
        'cancel': 'Cancel',
        'validationalert': 'Please enter either a name or an address',
        'added': 'Added listing for ',
        'updated': 'Updated listing for ',
        'removed': 'Closed listing for ',
        'cities': 'Cities',
        'destination': 'Other_destinations',
        'geomap': 'locate on geomap',
        'help-page': 'http://en.wikivoyage.org/wiki/Wikivoyage:Listing_editor',
        'enter-captcha': 'Enter CAPTCHA',
        'external-links': 'Your edit includes new external links.'
    };
    
    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" style="font-size:small;font-weight:normal;">')
            .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 () {
        // css included as import stylesheet is too slow
        var editButton = $('<span class="vcard-edit-button noprint"' 
                    + 'style="font-size:0.8em; color: rgb(150,150,150);">')
            .html('&nbsp;<a href="javascript:">'+translateStr['edit']+'</a>' )
            .click(function() {
                var listingEntry = $(this).parent();
                popupForm('edit', listingEntry);
            });
        $('span.vcard').append( editButton );
    }
 
    /*** Functions to retrieve entry details ***/
    function getIdentifier(entry) {
        var id = {};
        var name = entry.find('.org').text();
        var address = entry.find('.label').text();
        var alt =  entry.find('.nickname').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');
        for (var key in sectionHeadings) {
            if (section == key) return sectionHeadings[key];        
        }
        return listingTypes.listing;
    }
 
    function getSectionText(number) {
        var wikiText = $.ajax({
            url: mw.util.wikiScript(''),
            data: { title: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) {
        var typeRegex = new RegExp('{{('+listingTypes['see']+'|'+listingTypes['do']
                    +'|'+listingTypes['buy'] +'|'+listingTypes['eat'] + '|'+listingTypes['drink']
                    +'|'+listingTypes['sleep']+'|'+listingTypes['listing']+')','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],
            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:320px;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];
                }
            }
            else if (key != 'content') {
                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]) {  
                subnode.val(listing[parameter]);
            }

            // customise hiding parameters
            if (listing[allFields['type']['parameter']] == listingTypes['sleep'] && key == 'hours') node.hide();
            if (key == 'checkin' || key == 'checkout' || key == 'fax' || key == 'image') 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>');
            }

            if (key == 'content') {
                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;
        }
        $('#input-content').val($.trim($('#input-content').val()).replace(/\n+/g, '<br>'));
        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'];
            listing[parameter]= $("#input-"+key).val();
        }
 
        if (listing[allFields['type']['parameter']] != listingTypes.sleep) {
            listing[allFields['checkin']['parameter']] = null;
            listing[allFields['checkout']['parameter']] = null;
        }
        else {
            listing[allFields['hours']['parameter']] = null;
        }
 
        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'];
                sectionText = sectionText.replace(new RegExp('\\n\\*+\\s?'+listingText), 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();
    }
 
  function listingToStr(listing) {  
    var saveStr = '{{'+listing[allFields['type']['parameter']]; 
    if (!inlineListing && allFields['type']['newline']) saveStr += '\n';
    for ( var key in allFields ) {
        var parameter = allFields[key]['parameter'];
        if (key != 'type' && listing[parameter] != null) {
            if (inlineListing) {
                if (listing[parameter] != '') {
                    saveStr += ' | ' + parameter + '=' +listing[parameter];
                }
            }
            else {
                if (key != 'image' || listing[allFields['image']['parameter']] != '') { 
                    saveStr +='| '+parameter+ '=' + listing[parameter];
                }
                if (allFields[key]['newline']) {
                    saveStr += '\n';
                }
                else {
                    saveStr += ' ';
                }
            }
        }
    }
    saveStr += '}}';
    return saveStr;
  }
 
} ( mediaWiki, jQuery ) );