Follow-up r57470: Add show/hide links for users that can view deleted revisions but...
[mediawiki.git] / js2 / ajaxcategories.js
blobb37cd62842facce86812143a9c48756e78af7054
1 loadGM( {
2         "ajax-add-category" : "[Add Category]",
3         "ajax-add-category-submit" : "[Add]",
4         "ajax-confirm-prompt" : "[Confirmation Text]",
5         "ajax-confirm-title" : "[Confirmation Title]",
6         "ajax-confirm-save" : "[Save]",
7         "ajax-add-category-summary" : "[Add category $1]",
8         "ajax-remove-category-summary" : "[Remove category $2]",
9         "ajax-confirm-actionsummary" : "[Summary]",
10         "ajax-error-title" : "Error",
11         "ajax-error-dismiss" : "OK",
12         "ajax-remove-category-error" : "[RemoveErr]"
13 } );
15 var ajaxCategories = {
16         handleAddLink : function(e) {
17                 e.preventDefault();
19                 // Make sure the suggestion plugin is loaded. Load everything else while we're at it
20                 mvJsLoader.doLoad(
21                         ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'],
22                         function() {
23                                 $j('#mw-addcategory-prompt').toggle();
25                                 $j('#mw-addcategory-input').suggestions( {
26                                         'fetch':ajaxCategories.fetchSuggestions,
27                                         'cancel': function() {
28                                                 var req = ajaxCategories.request;
29                                                 if (req.abort)
30                                                         req.abort();
31                                         }
32                                 } );
34                                 $j('#mw-addcategory-input').suggestions();
35                         }
36                 );
37         },
39         fetchSuggestions : function( query ) {
40                 var that = this;
41                 var request = $j.ajax( {
42                         url: wgScriptPath + '/api.php',
43                         data: {
44                                 'action': 'query',
45                                 'list': 'allpages',
46                                 'apnamespace': 14,
47                                 'apprefix': $j(this).val(),
48                                 'format': 'json'
49                         },
50                         dataType: 'json',
51                         success: function( data ) {
52                                 // Process data.query.allpages into an array of titles
53                                 var pages = data.query.allpages;
54                                 var titleArr = [];
56                                 $j.each(pages, function(i, page) {
57                                         var title = page.title.split( ':', 2 )[1];
58                                         titleArr.push(title);
59                                 } );
61                                 $j(that).suggestions( 'suggestions', titleArr );
62                         }
63                 });
65                 ajaxCategories.request = request;
66         },
68         reloadCategoryList : function( response ) {
69                 var holder = $j('<div/>');
71                 holder.load(
72                         window.location.href+' .catlinks',
73                         function() {
74                                 $j('.catlinks').replaceWith( holder.find('.catlinks') );
75                                 ajaxCategories.setupAJAXCategories();
76                                 ajaxCategories.removeProgressIndicator( $j('.catlinks') );
77                         }
78                 );
79         },
81         confirmEdit : function( page, fn, actionSummary, doneFn ) {
82                 // Load jQuery UI
83                 mvJsLoader.doLoad(
84                         ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'],
85                         function() {
86                                 // Produce a confirmation dialog
88                                 var dialog = $j('<div/>');
90                                 dialog.addClass('mw-ajax-confirm-dialog');
91                                 dialog.attr( 'title', gM('ajax-confirm-title') );
93                                 // Intro text.
94                                 var confirmIntro = $j('<p/>');
95                                 confirmIntro.text( gM('ajax-confirm-prompt') );
96                                 dialog.append(confirmIntro);
98                                 // Summary of the action to be taken
99                                 var summaryHolder = $j('<p/>');
100                                 var summaryLabel = $j('<strong/>');
101                                 summaryLabel.text(gM('ajax-confirm-actionsummary')+" " );
102                                 summaryHolder.text( actionSummary );
103                                 summaryHolder.prepend( summaryLabel );
104                                 dialog.append(summaryHolder);
106                                 // Reason textbox.
107                                 var reasonBox = $j('<input type="text" size="45" />');
108                                 reasonBox.addClass('mw-ajax-confirm-reason');
109                                 dialog.append(reasonBox);
111                                 // Submit button
112                                 var submitButton = $j('<input type="button"/>');
113                                 submitButton.val( gM( 'ajax-confirm-save' ) );
115                                 var submitFunction = function() {
116                                         ajaxCategories.addProgressIndicator( dialog );
117                                         ajaxCategories.doEdit(
118                                                 page,
119                                                 fn,
120                                                 reasonBox.val(),
121                                                 function() {
122                                                         doneFn();
123                                                         dialog.dialog('close');
124                                                         ajaxCategories.removeProgressIndicator( dialog );
125                                                 }
126                                         );
127                                 };
129                                 var buttons = {};
130                                 buttons[gM('ajax-confirm-save')] = submitFunction;
131                                 var dialogOptions = {
132                                         'AutoOpen' : true,
133                                         'buttons' : buttons,
134                                         'width' : 450
135                                 };
137                                 $j('#catlinks').prepend(dialog);
138                                 dialog.dialog( dialogOptions );
139                         }
140                 );
141         },
143         doEdit : function( page, fn, summary, doneFn ) {
144                 // Get an edit token for the page.
145                 var getTokenVars = {
146                         'action':'query',
147                         'prop':'info|revisions',
148                         'intoken':'edit',
149                         'titles':page,
150                         'rvprop':'content|timestamp',
151                         'format':'json'
152                 };
154                 $j.get(wgScriptPath+'/api.php', getTokenVars,
155                         function( reply ) {
156                                 var infos = reply.query.pages;
157                                 $j.each(
158                                         infos,
159                                         function(pageid, data) {
160                                                 var token = data.edittoken;
161                                                 var timestamp = data.revisions[0].timestamp;
162                                                 var oldText = data.revisions[0]['*'];
164                                                 var newText = fn(oldText);
166                                                 if (newText === false) return;
168                                                 var postEditVars = {
169                                                         'action':'edit',
170                                                         'title':page,
171                                                         'text':newText,
172                                                         'summary':summary,
173                                                         'token':token,
174                                                         'basetimestamp':timestamp,
175                                                         'format':'json'
176                                                 };
178                                                 $j.post( wgScriptPath+'/api.php', postEditVars, doneFn, 'json' );
179                                         }
180                                 );
181                         }
182                 , 'json' );
183         },
185         addProgressIndicator : function( elem ) {
186                 var indicator = $j('<div/>');
188                 indicator.addClass('mw-ajax-loader');
190                 elem.append( indicator );
191         },
193         removeProgressIndicator : function( elem ) {
194                 elem.find('.mw-ajax-loader').remove();
195         },
197         handleCategoryAdd : function(e) {
198                 // Grab category text
199                 var category = $j('#mw-addcategory-input').val();
200                 var appendText = "\n[["+wgFormattedNamespaces[14]+":"+category+"]]\n";
201                 var summary = gM('ajax-add-category-summary', category);
203                 ajaxCategories.confirmEdit(
204                         wgPageName,
205                         function(oldText) { return oldText+appendText },
206                         summary,
207                         ajaxCategories.reloadCategoryList
208                 );
209         },
211         handleDeleteLink : function(e) {
212                 e.preventDefault();
214                 var category = $j(this).parent().find('a').text();
216                 // Build a regex that matches legal invocations of that category.
218                 // In theory I should escape the aliases, but there's no JS function for it
219                 //  Shouldn't have any real impact, can't be exploited or anything, so we'll
220                 //  leave it for now.
221                 var categoryNSFragment = '';
222                 $j.each(wgNamespaceIds, function( name, id ) {
223                         if (id == 14) {
224                                 // Allow the first character to be any case
225                                 var firstChar = name.charAt(0);
226                                 firstChar = '['+firstChar.toUpperCase()+firstChar.toLowerCase()+']';
227                                 categoryNSFragment += '|'+firstChar+name.substr(1);
228                         }
229                 } );
230                 categoryNSFragment = categoryNSFragment.substr(1); // Remove leading |
232                 // Build the regex
233                 var titleFragment = category;
235                 firstChar = category.charAt(0);
236                 firstChar = '['+firstChar.toUpperCase()+firstChar.toLowerCase()+']';
237                 titleFragment = firstChar+category.substr(1);
238                 var categoryRegex = '\\[\\['+categoryNSFragment+':'+titleFragment+'(\\|[^\\]]*)?\\]\\]';
239                 categoryRegex = new RegExp( categoryRegex, 'g' );
241                 var summary = gM('ajax-remove-category-summary', category);
243                 ajaxCategories.confirmEdit(
244                         wgPageName,
245                         function(oldText) {
246                                 var newText = oldText.replace(categoryRegex, '');
248                                 if (newText == oldText) {
249                                         var error = gM('ajax-remove-category-error');
250                                         ajaxCategories.showError( error );
251                                         ajaxCategories.removeProgressIndicator( $j('.mw-ajax-confirm-dialog') );
252                                         $j('.mw-ajax-confirm-dialog').dialog('close');
253                                         return false;
254                                 }
256                                 return newText;
257                         },
258                         summary, ajaxCategories.reloadCategoryList
259                 );
260         },
262         showError : function( str ) {
263                 var dialog = $j('<div/>');
264                 dialog.text(str);
266                 $j('#bodyContent').append(dialog);
268                 var buttons = {};
269                 buttons[gM('ajax-error-dismiss')] = function(e) {
270                         dialog.dialog('close');
271                 };
272                 var dialogOptions = {
273                         'buttons' : buttons,
274                         'AutoOpen' : true,
275                         'title' : gM('ajax-error-title')
276                 };
278                 dialog.dialog(dialogOptions);
279         },
281         setupAJAXCategories : function() {
282                 // Only do it for articles.
283                 if ( !wgIsArticle ) return;
285                 var clElement = $j('.catlinks');
287                 // Unhide hidden category holders.
288                 clElement.removeClass( 'catlinks-allhidden' );
290                 var addLink = $j('<a/>');
291                 addLink.addClass( 'mw-ajax-addcategory' );
293                 // Create [Add Category] link
294                 addLink.text( gM( 'ajax-add-category' ) );
295                 addLink.attr('href', '#');
296                 addLink.click( ajaxCategories.handleAddLink );
297                 clElement.append(addLink);
299                 // Create add category prompt
300                 var promptContainer = $j('<div id="mw-addcategory-prompt"/>');
301                 var promptTextbox = $j('<input type="text" size="45" id="mw-addcategory-input"/>');
302                 var addButton = $j('<input type="button" id="mw-addcategory-button"/>' );
303                 addButton.val( gM('ajax-add-category-submit') );
305                 promptTextbox.keypress( ajaxCategories.handleCategoryInput );
306                 addButton.click( ajaxCategories.handleCategoryAdd );
308                 promptContainer.append(promptTextbox);
309                 promptContainer.append(addButton);
310                 promptContainer.hide();
312                 // Create delete link for each category.
313                 $j('.catlinks div span a').each( function(e) {
314                         // Create a remove link
315                         var deleteLink = $j('<a class="mw-remove-category" href="#"/>');
317                         deleteLink.click(ajaxCategories.handleDeleteLink);
319                         $j(this).after(deleteLink);
320                 } );
322                 clElement.append(promptContainer);
323         }
326 js2AddOnloadHook( ajaxCategories.setupAJAXCategories );