r92151 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r92150‎ | r92151 | r92152 >
Date:11:36, 14 July 2011
Author:diebuche
Status:deferred (Comments)
Tags:
Comment:
AjaxCategories:
* Restructuring to allow both private and public functions/objects.
* Add an error when category alread present, instead of quitting silently.
* Add documentation to most functions.
* Remove hardcoded api.php (Thanks Krinkle)
Ping r92062
Modified paths:
  • /trunk/phase3/languages/messages/MessagesEn.php (modified) (history)
  • /trunk/phase3/maintenance/language/messages.inc (modified) (history)
  • /trunk/phase3/resources/mediawiki.page/mediawiki.page.ajaxCategories.js (modified) (history)

Diff [purge]

Index: trunk/phase3/maintenance/language/messages.inc
@@ -3475,6 +3475,7 @@
34763476 'ajax-error-dismiss',
34773477 'ajax-remove-category-error',
34783478 'ajax-edit-category-error',
 3479+ 'ajax-category-already-present',
34793480 ),
34803481
34813482 );
Index: trunk/phase3/languages/messages/MessagesEn.php
@@ -4606,4 +4606,5 @@
46074607 This usually occurs when the category has been added to the page in a template.',
46084608 'ajax-edit-category-error' => 'It was not possible to edit this category.
46094609 This usually occurs when the category has been added to the page in a template.',
 4610+'ajax-category-already-present' => 'This page already has the category you specified.',
46104611 );
Index: trunk/phase3/resources/mediawiki.page/mediawiki.page.ajaxCategories.js
@@ -7,31 +7,37 @@
88 // * Add Hooks for change, delete, add
99 // * Add Hooks for soft redirect
1010 // * Handle normal redirects
11 -// * api.php / api.php5
1211 // * Simple / MultiEditMode
1312
1413 ( function( $, mw ) {
15 - var catLinkWrapper = '<li/>'
 14+
 15+var ajaxCategories = function ( options ) {
 16+ // TODO grab these out of option object.
 17+
 18+ var catLinkWrapper = '<li/>';
1619 var $container = $( '.catlinks' );
1720
1821 var categoryLinkSelector = '#mw-normal-catlinks li a';
1922 var _request;
2023
2124 var _catElements = {};
22 - var _otherElements = {};
2325
2426 var namespaceIds = mw.config.get( 'wgNamespaceIds' )
2527 var categoryNamespaceId = namespaceIds['category'];
2628 var categoryNamespace = mw.config.get( 'wgFormattedNamespaces' )[categoryNamespaceId];
27 - var wgScriptPath = mw.config.get( 'wgScriptPath' );
28 -
29 - function _fetchSuggestions ( query ) {
30 - //SYNCED
 29+
 30+
 31+ /**
 32+ * Helper function for $.fn.suggestion
 33+ *
 34+ * @param string Query string.
 35+ */
 36+ _fetchSuggestions = function ( query ) {
3137 var _this = this;
3238 // ignore bad characters, they will be stripped out
3339 var catName = _stripIllegals( $( this ).val() );
3440 var request = $.ajax( {
35 - url: wgScriptPath + '/api.php',
 41+ url: mw.util.wikiScript( 'api' ),
3642 data: {
3743 'action': 'query',
3844 'list': 'allpages',
@@ -55,13 +61,19 @@
5662 } );
5763 //TODO
5864 _request = request;
59 - }
 65+ };
6066
61 - function _stripIllegals( cat ) {
 67+ _stripIllegals = function ( cat ) {
6268 return cat.replace( /[\x00-\x1f\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f]+/g, '' );
63 - }
 69+ };
6470
65 - function _insertCatDOM( cat, isHidden ) {
 71+ /**
 72+ * Insert a newly added category into the DOM
 73+ *
 74+ * @param string category name.
 75+ * @param boolean isHidden (unused)
 76+ */
 77+ _insertCatDOM = function ( cat, isHidden ) {
6678 // User can implicitely state a sort key.
6779 // Remove before display
6880 cat = cat.replace(/\|.*/, '');
@@ -83,9 +95,9 @@
8496 $container.find( '#mw-normal-catlinks ul' ).append( $catLinkWrapper );
8597 }
8698 _createCatButtons( $anchor.get(0) );
87 - }
 99+ };
88100
89 - function _makeSuggestionBox( prefill, callback, buttonVal ) {
 101+ _makeSuggestionBox = function ( prefill, callback, buttonVal ) {
90102 // Create add category prompt
91103 var promptContainer = $( '<div class="mw-addcategory-prompt"/>' );
92104 var promptTextbox = $( '<input type="text" size="45" class="mw-addcategory-input"/>' );
@@ -114,24 +126,38 @@
115127 promptContainer.append( addButton );
116128
117129 return promptContainer;
118 - }
 130+ };
119131
120 - // Create a valid link to the category.
121 - function _catLink ( cat ) {
122 - //SYNCED
 132+ /**
 133+ * Build URL for passed Category
 134+ *
 135+ * @param string category name.
 136+ * @return string Valid URL
 137+ */
 138+ _catLink = function ( cat ) {
123139 return mw.util.wikiGetlink( categoryNamespace + ':' + $.ucFirst( cat ) );
124 - }
 140+ };
125141
126 - function _getCats() {
 142+ /**
 143+ * Parse the DOM $container and build a list of
 144+ * present categories
 145+ *
 146+ * @return array Array of all categories
 147+ */
 148+ _getCats = function () {
127149 return $container.find( categoryLinkSelector ).map( function() { return $.trim( $( this ).text() ); } );
128 - }
 150+ };
129151
130 - function _containsCat( cat ) {
131 - //TODO: SYNC
 152+ /**
 153+ * Check whether a passed category is present in the DOM
 154+ *
 155+ * @return boolean True for exists
 156+ */
 157+ _containsCat = function ( cat ) {
132158 return _getCats().filter( function() { return $.ucFirst(this) == $.ucFirst(cat); } ).length !== 0;
133 - }
 159+ };
134160
135 - function _confirmEdit ( page, fn, actionSummary, doneFn ) {
 161+ _confirmEdit = function ( page, fn, actionSummary, doneFn ) {
136162
137163 // Produce a confirmation dialog
138164 var dialog = $( '<div/>' );
@@ -185,9 +211,9 @@
186212
187213 $( '#catlinks' ).prepend( dialog );
188214 dialog.dialog( dialogOptions );
189 - }
 215+ };
190216
191 - function _doEdit ( page, fn, summary, doneFn ) {
 217+ _doEdit = function ( page, fn, summary, doneFn ) {
192218 // Get an edit token for the page.
193219 var getTokenVars = {
194220 'action':'query',
@@ -198,7 +224,7 @@
199225 'format':'json'
200226 };
201227
202 - $.get( wgScriptPath + '/api.php', getTokenVars,
 228+ $.get( mw.util.wikiScript( 'api' ), getTokenVars,
203229 function( reply ) {
204230 var infos = reply.query.pages;
205231 $.each(
@@ -222,33 +248,48 @@
223249 'format':'json'
224250 };
225251
226 - $.post( wgScriptPath + '/api.php', postEditVars, doneFn, 'json' );
 252+ $.post( mw.util.wikiScript( 'api' ), postEditVars, doneFn, 'json' );
227253 }
228254 );
229255 }
230256 , 'json' );
231 - }
232 -
233 - function _addProgressIndicator ( elem ) {
 257+ };
 258+
 259+ /**
 260+ * Append spinner wheel to element
 261+ * @param DOMObject element.
 262+ */
 263+ _addProgressIndicator = function ( elem ) {
234264 var indicator = $( '<div/>' );
235265
236266 indicator.addClass( 'mw-ajax-loader' );
237267
238268 elem.append( indicator );
239 - }
 269+ };
240270
241 - function _removeProgressIndicator ( elem ) {
 271+ /**
 272+ * Find and remove spinner wheel from inside element
 273+ * @param DOMObject parent element.
 274+ */
 275+ _removeProgressIndicator = function ( elem ) {
242276 elem.find( '.mw-ajax-loader' ).remove();
243 - }
 277+ };
244278
245 - function _makeCaseInsensitiv( string ) {
 279+ /**
 280+ * Makes regex string caseinsensitive.
 281+ * Useful when 'i' flag can't be used.
 282+ * Return stuff like [Ff][Oo][Oo]
 283+ * @param string Regex string.
 284+ * @return string Processed regex string
 285+ */
 286+ _makeCaseInsensitiv = function ( string ) {
246287 var newString = '';
247288 for (var i=0; i < string.length; i++) {
248289 newString += '[' + string[i].toUpperCase() + string[i].toLowerCase() + ']';
249 - };
 290+ }
250291 return newString;
251 - }
252 - function _buildRegex ( category ) {
 292+ };
 293+ _buildRegex = function ( category ) {
253294 // Build a regex that matches legal invocations of that category.
254295 var categoryNSFragment = '';
255296 $.each( namespaceIds, function( name, id ) {
@@ -269,9 +310,9 @@
270311 var categoryRegex = '\\[\\[(' + categoryNSFragment + '):' + titleFragment + '(\\|[^\\]]*)?\\]\\]';
271312
272313 return new RegExp( categoryRegex, 'g' );
273 - }
 314+ };
274315
275 - function _handleEditLink ( e ) {
 316+ _handleEditLink = function ( e ) {
276317 e.preventDefault();
277318 var $this = $( this );
278319 var $link = $this.parent().find( 'a:not(.icon)' );
@@ -286,15 +327,15 @@
287328 _catElements[category].editButton.show();
288329 $( this ).unbind('click').click( _handleDeleteLink );
289330 });
290 - }
 331+ };
291332
292 - function _handleAddLink ( e ) {
 333+ _handleAddLink = function ( e ) {
293334 e.preventDefault();
294335
295336 $container.find( '#mw-normal-catlinks>.mw-addcategory-prompt' ).toggle();
296 - }
 337+ };
297338
298 - function _handleDeleteLink ( e ) {
 339+ _handleDeleteLink = function ( e ) {
299340 e.preventDefault();
300341
301342 var $this = $( this );
@@ -326,15 +367,15 @@
327368 $this.parent().remove();
328369 }
329370 );
330 - }
 371+ };
331372
332 - function _handleCategoryAdd ( e ) {
 373+ _handleCategoryAdd = function ( e ) {
333374 // Grab category text
334375 var category = $( this ).parent().find( '.mw-addcategory-input' ).val();
335376 category = $.ucFirst( category );
336377
337378 if ( _containsCat(category) ) {
338 - // TODO add info alert
 379+ _showError( mw.msg( 'ajax-category-already-present' ) );
339380 return;
340381 }
341382 var appendText = "\n[[" + categoryNamespace + ":" + category + "]]\n";
@@ -348,9 +389,9 @@
349390 _insertCatDOM( category, false );
350391 }
351392 );
352 - }
 393+ };
353394
354 - function _handleCategoryEdit ( e ) {
 395+ _handleCategoryEdit = function ( e ) {
355396 e.preventDefault();
356397
357398 // Grab category text
@@ -407,8 +448,14 @@
408449 $link.show().text( categoryNew ).attr( 'href', _catLink( categoryNew ) );
409450 }
410451 );
411 - }
412 - function _showError ( str ) {
 452+ };
 453+
 454+ /**
 455+ * Open a dismissable error dialog
 456+ *
 457+ * @param string str The error description
 458+ */
 459+ _showError = function ( str ) {
413460 var dialog = $( '<div/>' );
414461 dialog.text( str );
415462
@@ -425,24 +472,40 @@
426473 };
427474
428475 dialog.dialog( dialogOptions );
429 - }
 476+ };
430477
431 - function _createButton ( icon, title, category, text ){
432 - var button = $( '<a>' ).addClass( category || '' )
 478+ /**
 479+ * Manufacture iconed button, with or without text
 480+ *
 481+ * @param string icon The icon class.
 482+ * @param string title Title attribute.
 483+ * @param string className (optional) Additional classes to be added to the button.
 484+ * @param string text (optional) Text of button.
 485+ *
 486+ * @return jQueryObject The button
 487+ */
 488+ _createButton = function ( icon, title, className, text ){
 489+ var $button = $( '<a>' ).addClass( className || '' )
433490 .attr('title', title);
434491
435492 if ( text ) {
436 - var icon = $( '<a>' ).addClass( 'icon ' + icon );
437 - button.addClass( 'icon-parent' ).append( icon ).append( text );
 493+ var $icon = $( '<a>' ).addClass( 'icon ' + icon );
 494+ $button.addClass( 'icon-parent' ).append( $icon ).append( text );
438495 } else {
439 - button.addClass( 'icon ' + icon );
 496+ $button.addClass( 'icon ' + icon );
440497 }
441 - return button;
442 - }
443 - function _createCatButtons ( element ) {
 498+ return $button;
 499+ };
 500+
 501+ /**
 502+ * Append edit and remove buttons to a given category link
 503+ *
 504+ * @param DOMElement element Anchor element, to which the buttons should be appended.
 505+ */
 506+ _createCatButtons = function( element ) {
444507 // Create remove & edit buttons
445508 var deleteButton = _createButton('icon-close', mw.msg( 'ajax-remove-category' ) );
446 - var editButton = _createButton('icon-edit', mw.msg( 'ajax-edit-category' ) );
 509+ var editButton = _createButton('icon-edit', mw.msg( 'ajax-edit-category' ) );
447510
448511 //Not yet used
449512 var saveButton = _createButton('icon-tick', mw.msg( 'ajax-confirm-save' ) ).hide();
@@ -460,8 +523,8 @@
461524 deleteButton: deleteButton,
462525 editButton : editButton
463526 };
464 - }
465 - function _setup() {
 527+ };
 528+ this.setup = function () {
466529 // Could be set by gadgets like HotCat etc.
467530 if ( mw.config.get('disableAJAXCategories') ) {
468531 return;
@@ -494,10 +557,8 @@
495558 });
496559
497560 clElement.append( promptContainer );
498 - }
499 - function _teardown() {
500 -
501 - }
 561+ };
 562+
502563 _tasks = {
503564 list : [],
504565 executed : [],
@@ -509,7 +570,13 @@
510571 //run task
511572 this.executed.push( task );
512573 }
513 - }
514 - $(document).ready( function() {_setup()});
 574+ };
 575+};
 576+// Now make a new version
 577+mw.ajaxCategories = new ajaxCategories();
515578
 579+// Executing only on doc.ready, so that everyone
 580+// gets a chance to set mw.config.set('disableAJAXCategories')
 581+$( document ).ready( mw.ajaxCategories.setup() );
 582+
516583 } )( jQuery, mediaWiki );
\ No newline at end of file

Follow-up revisions

RevisionCommit summaryAuthorDate
r92288ajaxCategories fixes:...krinkle19:25, 15 July 2011

Past revisions this follows-up on

RevisionCommit summaryAuthorDate
r92112Rewrite ajaxCategories for ResourceLoader. Add some missing functionality (ed...diebuche22:36, 13 July 2011

Comments

#Comment by Nikerabbit (talk | contribs)   11:49, 14 July 2011

Shouldn't there be 'e in function _makeCaseInsensitiv.

+'ajax-category-already-present' => 'This page already has the category you specified.',

Can you make this to say "This page already belongs to the category $1".

This looks like a very nice feature.

#Comment by DieBuche (talk | contribs)   11:56, 14 July 2011

Sure. mw.msg() can replace dollar sign placeholders.

#Comment by DieBuche (talk | contribs)   15:01, 14 July 2011

Both done in r92159

#Comment by Krinkle (talk | contribs)   20:54, 3 October 2011

AjaxCategories moved out of core. Marking deferred for now.

Status & tagging log