Index: trunk/phase3/resources/Resources.php |
— | — | @@ -497,10 +497,45 @@ |
498 | 498 | 'debugScripts' => 'resources/mediawiki/mediawiki.log.js', |
499 | 499 | 'debugRaw' => false, |
500 | 500 | ), |
| 501 | + 'mediawiki.api' => array( |
| 502 | + 'scripts' => 'resources/mediawiki/mediawiki.api.js', |
| 503 | + ), |
| 504 | + 'mediawiki.api.category' => array( |
| 505 | + 'scripts' => 'resources/mediawiki/mediawiki.api.category.js', |
| 506 | + 'dependencies' => array( |
| 507 | + 'mediawiki.api', |
| 508 | + 'mediawiki.Title' |
| 509 | + ), |
| 510 | + ), |
| 511 | + 'mediawiki.api.edit' => array( |
| 512 | + 'scripts' => 'resources/mediawiki/mediawiki.api.edit.js', |
| 513 | + 'dependencies' => array( |
| 514 | + 'mediawiki.api', |
| 515 | + 'mediawiki.Title' |
| 516 | + ), |
| 517 | + ), |
| 518 | + 'mediawiki.api.parse' => array( |
| 519 | + 'scripts' => 'resources/mediawiki/mediawiki.api.parse.js', |
| 520 | + 'dependencies' => 'mediawiki.api', |
| 521 | + ), |
| 522 | + 'mediawiki.api.titleblacklist' => array( |
| 523 | + 'scripts' => 'resources/mediawiki/mediawiki.api.titleblacklist.js', |
| 524 | + 'dependencies' => array( |
| 525 | + 'mediawiki.api', |
| 526 | + 'mediawiki.Title' |
| 527 | + ), |
| 528 | + ), |
501 | 529 | 'mediawiki.debug' => array( |
502 | 530 | 'scripts' => 'resources/mediawiki/mediawiki.debug.js', |
503 | 531 | 'styles' => 'resources/mediawiki/mediawiki.debug.css', |
504 | 532 | ), |
| 533 | + 'mediawiki.feedback' => array( |
| 534 | + 'scripts' => 'resources/mediawiki/mediawiki.feedback.js', |
| 535 | + 'dependencies' => array( |
| 536 | + 'mediawiki.api.edit', |
| 537 | + 'mediawiki.Title' |
| 538 | + ), |
| 539 | + ), |
505 | 540 | 'mediawiki.htmlform' => array( |
506 | 541 | 'scripts' => 'resources/mediawiki/mediawiki.htmlform.js', |
507 | 542 | ), |
Index: trunk/phase3/resources/mediawiki/mediawiki.api.parse.js |
— | — | @@ -0,0 +1,29 @@ |
| 2 | +// library to assist with action=parse, that is, get rendered HTML of wikitext |
| 3 | + |
| 4 | +( function( mw, $ ) { |
| 5 | + |
| 6 | + $.extend( mw.Api.prototype, { |
| 7 | + /** |
| 8 | + * Parse wikitext into HTML |
| 9 | + * @param {String} wikitext |
| 10 | + * @param {Function} callback to which to pass success HTML |
| 11 | + * @param {Function} callback if error (optional) |
| 12 | + */ |
| 13 | + parse: function( wikiText, useHtml, error ) { |
| 14 | + var params = { |
| 15 | + text: wikiText, |
| 16 | + action: 'parse' |
| 17 | + }; |
| 18 | + var ok = function( data ) { |
| 19 | + if ( data && data.parse && data.parse.text && data.parse.text['*'] ) { |
| 20 | + useHtml( data.parse.text['*'] ); |
| 21 | + } |
| 22 | + }; |
| 23 | + this.get( params, ok, error ); |
| 24 | + } |
| 25 | + |
| 26 | + |
| 27 | + } ); // end extend |
| 28 | +} )( window.mediaWiki, jQuery ); |
| 29 | + |
| 30 | + |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.api.parse.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 31 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.api.titleblacklist.js |
— | — | @@ -0,0 +1,48 @@ |
| 2 | +// library to assist with API calls on titleblacklist |
| 3 | + |
| 4 | +( function( mw, $ ) { |
| 5 | + |
| 6 | + // cached token so we don't have to keep fetching new ones for every single post |
| 7 | + var cachedToken = null; |
| 8 | + |
| 9 | + $.extend( mw.Api.prototype, { |
| 10 | + /** |
| 11 | + * @param {mw.Title} |
| 12 | + * @param {Function} callback to pass false on Title not blacklisted, or error text when blacklisted |
| 13 | + * @param {Function} optional callback to run if api error |
| 14 | + * @return ajax call object |
| 15 | + */ |
| 16 | + isBlacklisted: function( title, callback, err ) { |
| 17 | + var params = { |
| 18 | + 'action': 'titleblacklist', |
| 19 | + 'tbaction': 'create', |
| 20 | + 'tbtitle': title.toString() |
| 21 | + }; |
| 22 | + |
| 23 | + var ok = function( data ) { |
| 24 | + // this fails open (if nothing valid is returned by the api, allows the title) |
| 25 | + // also fails open when the API is not present, which will be most of the time. |
| 26 | + if ( data.titleblacklist && data.titleblacklist.result && data.titleblacklist.result == 'blacklisted') { |
| 27 | + var result; |
| 28 | + if ( data.titleblacklist.reason ) { |
| 29 | + result = { |
| 30 | + reason: data.titleblacklist.reason, |
| 31 | + line: data.titleblacklist.line, |
| 32 | + message: data.titleblacklist.message |
| 33 | + }; |
| 34 | + } else { |
| 35 | + mw.log("mw.Api.titleblacklist::isBlacklisted> no reason data for blacklisted title", 'debug'); |
| 36 | + result = { reason: "Blacklisted, but no reason supplied", line: "Unknown" }; |
| 37 | + } |
| 38 | + callback( result ); |
| 39 | + } else { |
| 40 | + callback ( false ); |
| 41 | + } |
| 42 | + }; |
| 43 | + |
| 44 | + return this.get( params, ok, err ); |
| 45 | + |
| 46 | + } |
| 47 | + |
| 48 | + } ); |
| 49 | +} )( window.mediaWiki, jQuery ); |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.api.titleblacklist.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 50 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.feedback.js |
— | — | @@ -0,0 +1,138 @@ |
| 2 | +( function( mw, $, undefined ) { |
| 3 | + |
| 4 | + /** |
| 5 | + * Thingy for collecting user feedback on a wiki page |
| 6 | + * @param {mw.Api} api properly configured to talk to this wiki |
| 7 | + * @param {mw.Title} the title of the page where you collect feedback |
| 8 | + * @param {id} a string identifying this feedback form to separate it from others on the same page |
| 9 | + */ |
| 10 | + mw.Feedback = function( api, feedbackTitle ) { |
| 11 | + var _this = this; |
| 12 | + this.api = api; |
| 13 | + this.feedbackTitle = feedbackTitle; |
| 14 | + this.setup(); |
| 15 | + }; |
| 16 | + |
| 17 | + mw.Feedback.prototype = { |
| 18 | + setup: function() { |
| 19 | + var _this = this; |
| 20 | + |
| 21 | + // Set up buttons for dialog box. We have to do it the hard way since the json keys are localized |
| 22 | + _this.buttons = {}; |
| 23 | + _this.buttons[ gM( 'mwe-upwiz-feedback-cancel' ) ] = function() { _this.cancel(); }; |
| 24 | + _this.buttons[ gM( 'mwe-upwiz-feedback-submit' ) ] = function() { _this.submit(); }; |
| 25 | + |
| 26 | + var $feedbackPageLink = $j( '<a></a>' ).attr( { 'href': _this.feedbackTitle.getUrl(), 'target': '_blank' } ); |
| 27 | + this.$dialog = |
| 28 | + $( '<div style="position:relative;"></div>' ).append( |
| 29 | + $( '<div class="mwe-upwiz-feedback-mode mwe-upwiz-feedback-form"></div>' ).append( |
| 30 | + $( '<div style="margin-top:0.4em;"></div>' ).append( |
| 31 | + $( '<small></small>' ).msg( 'mwe-upwiz-feedback-note', |
| 32 | + _this.feedbackTitle.getNameText(), |
| 33 | + $feedbackPageLink ) |
| 34 | + ), |
| 35 | + $( '<div style="margin-top:1em;"></div>' ).append( |
| 36 | + gM( 'mwe-upwiz-feedback-subject' ), |
| 37 | + $( '<br/>' ), |
| 38 | + $( '<input type="text" class="mwe-upwiz-feedback-subject" name="subject" maxlength="60" style="width:99%;"/>' ) |
| 39 | + ), |
| 40 | + $( '<div style="margin-top:0.4em;"></div>' ).append( |
| 41 | + gM( 'mwe-upwiz-feedback-message' ), |
| 42 | + $( '<br/>' ), |
| 43 | + $( '<textarea name="message" class="mwe-upwiz-feedback-message" style="width:99%;" rows="5" cols="60"></textarea>' ) |
| 44 | + ) |
| 45 | + ), |
| 46 | + $( '<div class="mwe-upwiz-feedback-mode mwe-upwiz-feedback-submitting" style="text-align:center;margin:3em 0;"></div>' ).append( |
| 47 | + gM( 'mwe-upwiz-feedback-adding' ), |
| 48 | + $( '<br/>' ), |
| 49 | + $( '<img src="http://upload.wikimedia.org/wikipedia/commons/4/42/Loading.gif" />' ) |
| 50 | + ), |
| 51 | + $( '<div class="mwe-upwiz-feedback-mode mwe-upwiz-feedback-error" style="position:relative;"></div>' ).append( |
| 52 | + $( '<div class="mwe-upwiz-feedback-error-msg style="color:#990000;margin-top:0.4em;"></div>' ) |
| 53 | + |
| 54 | + ) |
| 55 | + ).dialog({ |
| 56 | + width: 500, |
| 57 | + autoOpen: false, |
| 58 | + title: gM( 'mwe-upwiz-feedback-title' ), |
| 59 | + modal: true, |
| 60 | + buttons: _this.buttons |
| 61 | + }); |
| 62 | + |
| 63 | + this.subjectInput = this.$dialog.find( 'input.mwe-upwiz-feedback-subject' ).get(0); |
| 64 | + this.messageInput = this.$dialog.find( 'textarea.mwe-upwiz-feedback-message' ).get(0); |
| 65 | + this.displayForm(); |
| 66 | + }, |
| 67 | + |
| 68 | + display: function( s ) { |
| 69 | + this.$dialog.dialog( { buttons:{} } ); // hide the buttons |
| 70 | + this.$dialog.find( '.mwe-upwiz-feedback-mode' ).hide(); // hide everything |
| 71 | + this.$dialog.find( '.mwe-upwiz-feedback-' + s ).show(); // show the desired div |
| 72 | + }, |
| 73 | + |
| 74 | + displaySubmitting: function() { |
| 75 | + this.display( 'submitting' ); |
| 76 | + }, |
| 77 | + |
| 78 | + displayForm: function( contents ) { |
| 79 | + this.subjectInput.value = (contents && contents.subject) ? contents.subject : ''; |
| 80 | + this.messageInput.value = (contents && contents.message) ? contents.message : ''; |
| 81 | + |
| 82 | + this.display( 'form' ); |
| 83 | + this.$dialog.dialog( { buttons: this.buttons } ); // put the buttons back |
| 84 | + }, |
| 85 | + |
| 86 | + displayError: function( message ) { |
| 87 | + this.display( 'error' ); |
| 88 | + this.$dialog.find( '.mwe-upwiz-feedback-error-msg' ).msg( message ); |
| 89 | + }, |
| 90 | + |
| 91 | + cancel: function() { |
| 92 | + this.$dialog.dialog( 'close' ); |
| 93 | + }, |
| 94 | + |
| 95 | + submit: function() { |
| 96 | + var _this = this; |
| 97 | + |
| 98 | + // get the values to submit |
| 99 | + var subject = this.subjectInput.value; |
| 100 | + |
| 101 | + var message = "<small>User agent: " + navigator.userAgent + "</small>\n\n" |
| 102 | + + this.messageInput.value; |
| 103 | + if ( message.indexOf( '~~~' ) == -1 ) { |
| 104 | + message += " ~~~~"; |
| 105 | + } |
| 106 | + |
| 107 | + this.displaySubmitting(); |
| 108 | + |
| 109 | + var ok = function( result ) { |
| 110 | + if ( result.edit !== undefined ) { |
| 111 | + if ( result.edit.result === 'Success' ) { |
| 112 | + _this.$dialog.dialog( 'close' ); // edit complete, close dialog box |
| 113 | + } else { |
| 114 | + _this.displayError( 'mwe-upwiz-feedback-error1' ); // unknown API result |
| 115 | + } |
| 116 | + } else { |
| 117 | + displayError( 'mwe-upwiz-feedback-error2' ); // edit failed |
| 118 | + } |
| 119 | + }; |
| 120 | + |
| 121 | + var err = function( code, info ) { |
| 122 | + displayError( 'mwe-upwiz-feedback-error3' ); // ajax request failed |
| 123 | + }; |
| 124 | + |
| 125 | + this.api.newSection( this.feedbackTitle, subject, message, ok, err ); |
| 126 | + |
| 127 | + }, // close submit button function |
| 128 | + |
| 129 | + |
| 130 | + launch: function( contents ) { |
| 131 | + this.displayForm( contents ); |
| 132 | + this.$dialog.dialog( 'open' ); |
| 133 | + this.subjectInput.focus(); |
| 134 | + } |
| 135 | + |
| 136 | + }; |
| 137 | + |
| 138 | + |
| 139 | +} )( window.mediaWiki, jQuery ); |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.feedback.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 140 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.api.category.js |
— | — | @@ -0,0 +1,106 @@ |
| 2 | +// library to assist with API calls on categories |
| 3 | + |
| 4 | +( function( mw, $ ) { |
| 5 | + |
| 6 | + $.extend( mw.Api.prototype, { |
| 7 | + /** |
| 8 | + * Determine if a category exists |
| 9 | + * @param {mw.Title} |
| 10 | + * @param {Function} callback to pass boolean of category's existence |
| 11 | + * @param {Function} optional callback to run if api error |
| 12 | + * @return ajax call object |
| 13 | + */ |
| 14 | + isCategory: function( title, callback, err ) { |
| 15 | + var params = { |
| 16 | + 'prop': 'categoryinfo', |
| 17 | + 'titles': title.toString() |
| 18 | + }; |
| 19 | + |
| 20 | + var ok = function( data ) { |
| 21 | + var exists = false; |
| 22 | + if ( data.query && data.query.pages ) { |
| 23 | + $.each( data.query.pages, function( id, page ) { |
| 24 | + if ( page.categoryinfo ) { |
| 25 | + exists = true; |
| 26 | + } |
| 27 | + } ); |
| 28 | + } |
| 29 | + callback( exists ); |
| 30 | + }; |
| 31 | + |
| 32 | + return this.get( params, { ok: ok, err: err } ); |
| 33 | + |
| 34 | + }, |
| 35 | + |
| 36 | + /** |
| 37 | + * Get a list of categories that match a certain prefix. |
| 38 | + * e.g. given "Foo", return "Food", "Foolish people", "Foosball tables" ... |
| 39 | + * @param {String} prefix to match |
| 40 | + * @param {Function} callback to pass matched categories to |
| 41 | + * @param {Function} optional callback to run if api error |
| 42 | + * @return ajax call object |
| 43 | + */ |
| 44 | + getCategoriesByPrefix: function( prefix, callback, err ) { |
| 45 | + |
| 46 | + // fetch with allpages to only get categories that have a corresponding description page. |
| 47 | + var params = { |
| 48 | + 'list': 'allpages', |
| 49 | + 'apprefix': prefix, |
| 50 | + 'apnamespace': mw.config.get('wgNamespaceIds').category |
| 51 | + }; |
| 52 | + |
| 53 | + var ok = function( data ) { |
| 54 | + var texts = []; |
| 55 | + if ( data.query && data.query.allpages ) { |
| 56 | + $.each( data.query.allpages, function( i, category ) { |
| 57 | + texts.push( new mw.Title( category.title ).getNameText() ); |
| 58 | + } ); |
| 59 | + } |
| 60 | + callback( texts ); |
| 61 | + }; |
| 62 | + |
| 63 | + return this.get( params, { ok: ok, err: err } ); |
| 64 | + |
| 65 | + }, |
| 66 | + |
| 67 | + |
| 68 | + /** |
| 69 | + * Get the categories that a particular page on the wiki belongs to |
| 70 | + * @param {mw.Title} |
| 71 | + * @param {Function} callback to pass categories to (or false, if title not found) |
| 72 | + * @param {Function} optional callback to run if api error |
| 73 | + * @param {Boolean} optional asynchronousness (default = true = async) |
| 74 | + * @return ajax call object |
| 75 | + */ |
| 76 | + getCategories: function( title, callback, err, async ) { |
| 77 | + var params = { |
| 78 | + prop: 'categories', |
| 79 | + titles: title.toString() |
| 80 | + }; |
| 81 | + if ( async === undefined ) { |
| 82 | + async = true; |
| 83 | + } |
| 84 | + |
| 85 | + var ok = function( data ) { |
| 86 | + var ret = false; |
| 87 | + if ( data.query && data.query.pages ) { |
| 88 | + $.each( data.query.pages, function( id, page ) { |
| 89 | + if ( page.categories ) { |
| 90 | + if ( typeof ret !== 'object' ) { |
| 91 | + ret = []; |
| 92 | + } |
| 93 | + $.each( page.categories, function( i, cat ) { |
| 94 | + ret.push( new mw.Title( cat.title ) ); |
| 95 | + } ); |
| 96 | + } |
| 97 | + } ); |
| 98 | + } |
| 99 | + callback( ret ); |
| 100 | + }; |
| 101 | + |
| 102 | + return this.get( params, { ok: ok, err: err, async: async } ); |
| 103 | + |
| 104 | + } |
| 105 | + |
| 106 | + } ); |
| 107 | +} )( window.mediaWiki, jQuery ); |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.api.category.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 108 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.api.js |
— | — | @@ -0,0 +1,208 @@ |
| 2 | +/* mw.Api objects represent the API of a particular MediaWiki server. */ |
| 3 | + |
| 4 | +( function( mw, $j, undefined ) { |
| 5 | + |
| 6 | + /** |
| 7 | + * Represents the API of a particular MediaWiki server. |
| 8 | + * |
| 9 | + * Required options: |
| 10 | + * url - complete URL to API endpoint. Usually equivalent to wgServer + wgScriptPath + '/api.php' |
| 11 | + * |
| 12 | + * Other options: |
| 13 | + * can override the parameter defaults and ajax default options. |
| 14 | + * XXX document! |
| 15 | + * |
| 16 | + * ajax options can also be overriden on every get() or post() |
| 17 | + * |
| 18 | + * @param options {Mixed} can take many options, but must include at minimum the API url. |
| 19 | + */ |
| 20 | + mw.Api = function( options ) { |
| 21 | + |
| 22 | + // make sure we at least have a URL endpoint for the API |
| 23 | + if ( options.url === undefined ) { |
| 24 | + throw new Error( 'Configuration error - needs url property' ); |
| 25 | + } |
| 26 | + |
| 27 | + this.url = options.url; |
| 28 | + |
| 29 | + /* We allow people to omit these default parameters from API requests */ |
| 30 | + // there is very customizable error handling here, on a per-call basis |
| 31 | + // wondering, would it be simpler to make it easy to clone the api object, change error handling, and use that instead? |
| 32 | + this.defaults = { |
| 33 | + parameters: { |
| 34 | + action: 'query', |
| 35 | + format: 'json' |
| 36 | + }, |
| 37 | + |
| 38 | + ajax: { |
| 39 | + // force toString if we got a mw.Uri object |
| 40 | + url: new String( this.url ), |
| 41 | + |
| 42 | + /* default function for success and no API error */ |
| 43 | + ok: function() {}, |
| 44 | + |
| 45 | + // caller can supply handlers for http transport error or api errors |
| 46 | + err: function( code, result ) { |
| 47 | + mw.log( "mw.Api error: " + code, 'debug' ); |
| 48 | + }, |
| 49 | + |
| 50 | + timeout: 30000, /* 30 seconds */ |
| 51 | + |
| 52 | + dataType: 'json' |
| 53 | + |
| 54 | + } |
| 55 | + }; |
| 56 | + |
| 57 | + |
| 58 | + if ( options.parameters ) { |
| 59 | + $j.extend( this.defaults.parameters, options.parameters ); |
| 60 | + } |
| 61 | + |
| 62 | + if ( options.ajax ) { |
| 63 | + $j.extend( this.defaults.ajax, options.ajax ); |
| 64 | + } |
| 65 | + }; |
| 66 | + |
| 67 | + mw.Api.prototype = { |
| 68 | + |
| 69 | + /** |
| 70 | + * For api queries, in simple cases the caller just passes a success callback. |
| 71 | + * In complex cases they pass an object with a success property as callback and probably other options. |
| 72 | + * Normalize the argument so that it's always the latter case. |
| 73 | + * |
| 74 | + * @param {Object|Function} ajax properties, or just a success function |
| 75 | + * @return Function |
| 76 | + */ |
| 77 | + normalizeAjaxOptions: function( arg ) { |
| 78 | + if ( typeof arg === 'function' ) { |
| 79 | + var ok = arg; |
| 80 | + arg = { 'ok': ok }; |
| 81 | + } |
| 82 | + if (! arg.ok ) { |
| 83 | + throw Error( "ajax options must include ok callback" ); |
| 84 | + } |
| 85 | + return arg; |
| 86 | + }, |
| 87 | + |
| 88 | + /** |
| 89 | + * Perform API get request |
| 90 | + * |
| 91 | + * @param {Object} request parameters |
| 92 | + * @param {Object|Function} ajax properties, or just a success function |
| 93 | + */ |
| 94 | + get: function( parameters, ajaxOptions ) { |
| 95 | + ajaxOptions = this.normalizeAjaxOptions( ajaxOptions ); |
| 96 | + ajaxOptions.type = 'GET'; |
| 97 | + this.ajax( parameters, ajaxOptions ); |
| 98 | + }, |
| 99 | + |
| 100 | + /** |
| 101 | + * Perform API post request |
| 102 | + * TODO post actions for nonlocal will need proxy |
| 103 | + * |
| 104 | + * @param {Object} request parameters |
| 105 | + * @param {Object|Function} ajax properties, or just a success function |
| 106 | + */ |
| 107 | + post: function( parameters, ajaxOptions ) { |
| 108 | + ajaxOptions = this.normalizeAjaxOptions( ajaxOptions ); |
| 109 | + ajaxOptions.type = 'POST'; |
| 110 | + this.ajax( parameters, ajaxOptions ); |
| 111 | + }, |
| 112 | + |
| 113 | + /** |
| 114 | + * Perform the API call. |
| 115 | + * |
| 116 | + * @param {Object} request parameters |
| 117 | + * @param {Object} ajax properties |
| 118 | + */ |
| 119 | + ajax: function( parameters, ajaxOptions ) { |
| 120 | + parameters = $j.extend( {}, this.defaults.parameters, parameters ); |
| 121 | + ajaxOptions = $j.extend( {}, this.defaults.ajax, ajaxOptions ); |
| 122 | + |
| 123 | + // Some deployed MediaWiki >= 1.17 forbid periods in URLs, due to an IE XSS bug |
| 124 | + // So let's escape them here. See bug #28235 |
| 125 | + // This works because jQuery accepts data as a query string or as an Object |
| 126 | + ajaxOptions.data = $j.param( parameters ).replace( /\./g, '%2E' ); |
| 127 | + |
| 128 | + ajaxOptions.error = function( xhr, textStatus, exception ) { |
| 129 | + ajaxOptions.err( 'http', { xhr: xhr, textStatus: textStatus, exception: exception } ); |
| 130 | + }; |
| 131 | + |
| 132 | + |
| 133 | + /* success just means 200 OK; also check for output and API errors */ |
| 134 | + ajaxOptions.success = function( result ) { |
| 135 | + if ( result === undefined || result === null || result === '' ) { |
| 136 | + ajaxOptions.err( "ok-but-empty", "OK response but empty result (check HTTP headers?)" ); |
| 137 | + } else if ( result.error ) { |
| 138 | + var code = result.error.code === undefined ? 'unknown' : result.error.code; |
| 139 | + ajaxOptions.err( code, result ); |
| 140 | + } else { |
| 141 | + ajaxOptions.ok( result ); |
| 142 | + } |
| 143 | + }; |
| 144 | + |
| 145 | + $j.ajax( ajaxOptions ); |
| 146 | + |
| 147 | + } |
| 148 | + |
| 149 | + }; |
| 150 | + |
| 151 | + /** |
| 152 | + * This is a list of errors we might receive from the API. |
| 153 | + * For now, this just documents our expectation that there should be similar messages |
| 154 | + * available. |
| 155 | + */ |
| 156 | + mw.Api.errors = [ |
| 157 | + /* occurs when POST aborted - jQuery 1.4 can't distinguish abort or lost connection from 200 OK + empty result */ |
| 158 | + 'ok-but-empty', |
| 159 | + |
| 160 | + // timeout |
| 161 | + 'timeout', |
| 162 | + |
| 163 | + /* really a warning, but we treat it like an error */ |
| 164 | + 'duplicate', |
| 165 | + 'duplicate-archive', |
| 166 | + |
| 167 | + /* upload succeeded, but no image info. |
| 168 | + this is probably impossible, but might as well check for it */ |
| 169 | + 'noimageinfo', |
| 170 | + |
| 171 | + /* remote errors, defined in API */ |
| 172 | + 'uploaddisabled', |
| 173 | + 'nomodule', |
| 174 | + 'mustbeposted', |
| 175 | + 'badaccess-groups', |
| 176 | + 'stashfailed', |
| 177 | + 'missingresult', |
| 178 | + 'missingparam', |
| 179 | + 'invalid-file-key', |
| 180 | + 'copyuploaddisabled', |
| 181 | + 'mustbeloggedin', |
| 182 | + 'empty-file', |
| 183 | + 'file-too-large', |
| 184 | + 'filetype-missing', |
| 185 | + 'filetype-banned', |
| 186 | + 'filename-tooshort', |
| 187 | + 'illegal-filename', |
| 188 | + 'verification-error', |
| 189 | + 'hookaborted', |
| 190 | + 'unknown-error', |
| 191 | + 'internal-error', |
| 192 | + 'overwrite', |
| 193 | + 'badtoken', |
| 194 | + 'fetchfileerror', |
| 195 | + 'fileexists-shared-forbidden' |
| 196 | + ]; |
| 197 | + |
| 198 | + /** |
| 199 | + * This is a list of warnings we might receive from the API. |
| 200 | + * For now, this just documents our expectation that there should be similar messages |
| 201 | + * available. |
| 202 | + */ |
| 203 | + |
| 204 | + mw.Api.warnings = [ |
| 205 | + 'duplicate', |
| 206 | + 'exists' |
| 207 | + ]; |
| 208 | + |
| 209 | +}) ( window.mediaWiki, jQuery ); |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.api.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 210 | + native |
Index: trunk/phase3/resources/mediawiki/mediawiki.api.edit.js |
— | — | @@ -0,0 +1,117 @@ |
| 2 | +// library to assist with edits |
| 3 | + |
| 4 | +( function( mw, $, undefined ) { |
| 5 | + |
| 6 | + // cached token so we don't have to keep fetching new ones for every single post |
| 7 | + var cachedToken = null; |
| 8 | + |
| 9 | + $.extend( mw.Api.prototype, { |
| 10 | + |
| 11 | + /* Post to API with edit token. If we have no token, get one and try to post. |
| 12 | + * If we have a cached token try using that, and if it fails, blank out the |
| 13 | + * cached token and start over. |
| 14 | + * |
| 15 | + * @param params API parameters |
| 16 | + * @param ok callback for success |
| 17 | + * @param err (optional) error callback |
| 18 | + */ |
| 19 | + postWithEditToken: function( params, ok, err ) { |
| 20 | + var api = this; |
| 21 | + if ( cachedToken === null ) { |
| 22 | + // We don't have a valid cached token, so get a fresh one and try posting. |
| 23 | + // We do not trap any 'badtoken' or 'notoken' errors, because we don't want |
| 24 | + // an infinite loop. If this fresh token is bad, something else is very wrong. |
| 25 | + var useTokenToPost = function( token ) { |
| 26 | + params.token = token; |
| 27 | + api.post( params, ok, err ); |
| 28 | + }; |
| 29 | + api.getEditToken( useTokenToPost, err ); |
| 30 | + } else { |
| 31 | + // We do have a token, but it might be expired. So if it is 'bad' then |
| 32 | + // start over with a new token. |
| 33 | + params.token = cachedToken; |
| 34 | + var getTokenIfBad = function( code, result ) { |
| 35 | + if ( code === 'badtoken' ) { |
| 36 | + cachedToken = null; // force a new token |
| 37 | + api.postWithEditToken( params, ok, err ); |
| 38 | + } else { |
| 39 | + err( code, result ); |
| 40 | + } |
| 41 | + }; |
| 42 | + api.post( params, { 'ok' : ok, 'err' : getTokenIfBad }); |
| 43 | + } |
| 44 | + }, |
| 45 | + |
| 46 | + /** |
| 47 | + * Api helper to grab an edit token |
| 48 | + * |
| 49 | + * token callback has signature ( String token ) |
| 50 | + * error callback has signature ( String code, Object results, XmlHttpRequest xhr, Exception exception ) |
| 51 | + * Note that xhr and exception are only available for 'http_*' errors |
| 52 | + * code may be any http_* error code (see mw.Api), or 'token_missing' |
| 53 | + * |
| 54 | + * @param {Function} received token callback |
| 55 | + * @param {Function} error callback |
| 56 | + */ |
| 57 | + getEditToken: function( tokenCallback, err ) { |
| 58 | + var api = this; |
| 59 | + |
| 60 | + var parameters = { |
| 61 | + 'prop': 'info', |
| 62 | + 'intoken': 'edit', |
| 63 | + /* we need some kind of dummy page to get a token from. This will return a response |
| 64 | + complaining that the page is missing, but we should also get an edit token */ |
| 65 | + 'titles': 'DummyPageForEditToken' |
| 66 | + }; |
| 67 | + |
| 68 | + var ok = function( data ) { |
| 69 | + var token; |
| 70 | + $.each( data.query.pages, function( i, page ) { |
| 71 | + if ( page['edittoken'] ) { |
| 72 | + token = page['edittoken']; |
| 73 | + return false; |
| 74 | + } |
| 75 | + } ); |
| 76 | + if ( token !== undefined ) { |
| 77 | + cachedToken = token; |
| 78 | + tokenCallback( token ); |
| 79 | + } else { |
| 80 | + err( 'token-missing', data ); |
| 81 | + } |
| 82 | + }; |
| 83 | + |
| 84 | + var ajaxOptions = { |
| 85 | + 'ok': ok, |
| 86 | + 'err': err, |
| 87 | + // Due to the API assuming we're logged out if we pass the callback-parameter, |
| 88 | + // we have to disable jQuery's callback system, and instead parse JSON string, |
| 89 | + // by setting 'jsonp' to false. |
| 90 | + 'jsonp': false |
| 91 | + }; |
| 92 | + |
| 93 | + api.get( parameters, ajaxOptions ); |
| 94 | + }, |
| 95 | + |
| 96 | + /** |
| 97 | + * Create a new section of the page. |
| 98 | + * @param {mw.Title|String} target page |
| 99 | + * @param {String} header |
| 100 | + * @param {String} wikitext message |
| 101 | + * @param {Function} success handler |
| 102 | + * @param {Function} error handler |
| 103 | + */ |
| 104 | + newSection: function( title, header, message, ok, err ) { |
| 105 | + var params = { |
| 106 | + action: 'edit', |
| 107 | + section: 'new', |
| 108 | + format: 'json', |
| 109 | + title: title.toString(), |
| 110 | + summary: header, |
| 111 | + text: message |
| 112 | + }; |
| 113 | + this.postWithEditToken( params, ok, err ); |
| 114 | + } |
| 115 | + |
| 116 | + } ); // end extend |
| 117 | + |
| 118 | +} )( window.mediaWiki, jQuery ); |
Property changes on: trunk/phase3/resources/mediawiki/mediawiki.api.edit.js |
___________________________________________________________________ |
Added: svn:eol-style |
1 | 119 | + native |