User:Ruud Koot/Listing editor/develop.js

/* KNOWN ISSUES - edittoken can expire - editing issues - copy & paste requires some care with contenteditable - |    - need better heuristics when user adds an ampersand - bold, italics and other simple wiki markup - html-characters that need escaping, such as '<' and '>' - not all field are handled yet - cannot edit 'url', 'lat', or 'long' - round-tripping is terribly incomplete - e.g. Wikilinks will be turned into HTML anchors - we should check if we can accurately round-trip before editing, and abort and log otherwise - missing (must have) features - add additional fields to listings - add new listings - does not fail gracefully on errors - does not remove "save" button while saving

mw.loader.using( ['mediawiki.util', 'jquery.client'], function {

var version = 'develop'

importStylesheet( 'User:Ruud Koot/Listing editor/' + version + '.css' );

var fields = [ 'name', 'alt', 'address', 'directions', 'lat', 'long', 'phone', 'tollfree', 'email', 'fax', 'url', 'hours', 'checkin', 'checkout', 'price', 'content' ]; var relevantFields = { 'see'   : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price' ],                        [ 'content' ] ], 'do'    : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price' ],                        [ 'content' ] ], 'buy'   : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price' ],                        [ 'content' ] ], 'eat'   : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price' ],                        [ 'content' ] ], 'drink' : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price' ],                        [ 'content' ] ], 'sleep' : [             [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price', 'checkin', 'checkout' ], [ 'content' ] ], 'listing': [ [ 'type' ], [ 'name', 'alt', 'url', 'email' ], [ 'address', 'lat', 'long', 'directions' ], [ 'phone', 'tollfree', 'fax' ], [ 'hours', 'price', 'checkin', 'checkout' ], [ 'content' ] ] };

var savedEntry     = undefined; /* global? */ var wikiTextSection = undefined; /* global? */ var wikitext        = undefined; /* global? */ var listingType     = undefined; /* global? */

function handleException( f, e ) { try { alert( f + ': ' + e );

$.ajax({         url: mw.util.wikiScript( 'api' ),          data: {              format: 'json',              action: 'edit',              title: 'User:Ruud_Koot/Listing_editor/errorlog',              summary: 'Listing editor (' + version + ')',              prependtext: '* ' + f + ': ' + e,              token: mw.user.tokens.get( 'csrfToken' )          },          dataType: 'json',          type: 'POST',          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 {                  alert( 'Error: Unknown result from API.' );              }          }, error: function( xhr ) { alert( 'Error: Request failed.' ); }     });

switch ( f ) { case 'addEditButtons': return; default: window.location.reload; }   } catch ( e ) { alert( 'double fault' ); window.location.reload; } }

function addEditButtons { try { var editButton = $( ' [edit] ' ).click( startEditing ); //.trigger( 'click' ); $( '.vcard' ).append( editButton ); } catch ( e ) { handleException( 'addEditButtons', e ); } }

function removeEditButtons { try { $( '.vcard-edit-button' ).remove } catch ( e ) { handleException( 'removeEditButtons', e ); } }

function addSaveButton( entry ) { try { var saveButton = $( ' [save] ' ).click( entry, saveTheEdits ); entry.append( saveButton ); return saveButton; } catch ( e ) { handleException( 'addSaveButton', e ); } }

function addCancelButton( entry ) { try { var button = $( ' [cancel] ' ).click( entry, cancelEditing ); entry.append( button ); return button; } catch ( e ) { handleException( 'addCancelButton', e ); } }

function startEditing { try { var entry = $(this).parent;

removeEditButtons;

savedEntry = entry.html; wikitext = theWikitextOfUs( entry ); addSaveButton( entry ); addCancelButton( entry );

fields.forEach( function ( element, index, array ) {       if (element === 'url') return;        entry.find( '.listing-' + element ).attr( 'contenteditable', true );      } ); } catch ( e ) { handleException( 'startEditing', e ); } }

function saveTheEdits( event ) { try { var newEntry = serializeListing( event.data ); var newWikitext = wikiTextSection.replace( wikitext, newEntry ); $.ajax({         url: mw.util.wikiScript( 'api' ),          data: {              format: 'json',              action: 'edit',              title: mw.config.get( 'wgPageName' ),              section: theSectionWeAreIn( event.data ),              summary: 'Listing editor (' + version + '): ' + ourIdentifier( event.data ),              text: newWikitext,              token: mw.user.tokens.get( 'csrfToken' )          },          dataType: 'json',          type: 'POST',          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 {                  alert( 'Error: Unknown result from API.' ); }         },          error: function( xhr ) { alert( 'Error: Request failed.' ); }     });    } catch ( e ) {      handleException( 'saveTheEdits', e );    }  }

function cancelEditing( event ) { try { event.data.html( savedEntry ); addEditButtons; } catch ( e ) { handleException( 'cancelEditing', e ); } }

function theSectionWeAreIn( entry ) { try { return entry.parent.parent.prevAll( 'h2' ).find( '.mw-editsection a' ).attr( 'href' ).split( '=' ).pop; } catch ( e ) { handleException( 'theSectionWeAreIn', e ); } }

function theWikitextOfOurSection( entry ) { try { var sectionNumber = theSectionWeAreIn( entry ); var wikiText = $.ajax({       type: "GET",        url: '/w/index.php?title=' + mw.config.get('wgPageName') + '&action=raw&oldid=' + mw.config.get('wgCurRevisionId') + '&section=' + sectionNumber,        dataType: 'text',        async: false      }).responseText;

return wikiText; } catch ( e ) { handleException( 'theWikitextOfOurSection', e ); } }

function ourIdentifier( entry ) { return entry.find( '.org' ).text }

function theWikitextOfUs( entry ) { var identifier = ourIdentifier( entry ); wikiTextSection = theWikitextOfOurSection( entry ); var regex = new RegExp( "\x7B\x7B(see|do|buy|eat|drink|sleep|listing).*\\n?.*\\|.*name.*=.*" + regexQuote( identifier ) + "(.|\\n)*?}}" ); var matched = wikiTextSection.match( regex ); var us = matched[0]; listingType = matched[1]

console.log( us ); return us; }

function ampersandQuote( str ) { return str.replace( /&/g, "&amp;" ); }

function regexQuote( str ) { try { return str.replace(/([.?*+^$[\]\\{}|-])/g, "\\$1"); } catch ( e ) { handleException( 'regexQuote', e ); } }

function convertHtmlToWikitext( str ) { try { return str.replace( /<[/]?i>/ig, "" ).replace( /<[/]?b>/ig, "'"); } catch ( e ) { handleExceptions( 'convertHtmlToWikitext', e ); } }

function serializeListing( entry ) { try { var result = ''; return result; } catch ( e ) { handleException( 'serializeListing', e ); } }

addEditButtons;

} );