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]"
15 var ajaxCategories = {
16 handleAddLink : function(e) {
19 // Make sure the suggestion plugin is loaded. Load everything else while we're at it
21 ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'],
23 $j('#mw-addcategory-prompt').toggle();
25 $j('#mw-addcategory-input').suggestions( {
26 'fetch':ajaxCategories.fetchSuggestions,
27 'cancel': function() {
28 var req = ajaxCategories.request;
34 $j('#mw-addcategory-input').suggestions();
39 fetchSuggestions : function( query ) {
41 var request = $j.ajax( {
42 url: wgScriptPath + '/api.php',
47 'apprefix': $j(this).val(),
51 success: function( data ) {
52 // Process data.query.allpages into an array of titles
53 var pages = data.query.allpages;
56 $j.each(pages, function(i, page) {
57 var title = page.title.split( ':', 2 )[1];
61 $j(that).suggestions( 'suggestions', titleArr );
65 ajaxCategories.request = request;
68 reloadCategoryList : function( response ) {
69 var holder = $j('<div/>');
72 window.location.href+' .catlinks',
74 $j('.catlinks').replaceWith( holder.find('.catlinks') );
75 ajaxCategories.setupAJAXCategories();
76 ajaxCategories.removeProgressIndicator( $j('.catlinks') );
81 confirmEdit : function( page, fn, actionSummary, doneFn ) {
84 ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'],
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') );
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);
107 var reasonBox = $j('<input type="text" size="45" />');
108 reasonBox.addClass('mw-ajax-confirm-reason');
109 dialog.append(reasonBox);
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(
123 dialog.dialog('close');
124 ajaxCategories.removeProgressIndicator( dialog );
130 buttons[gM('ajax-confirm-save')] = submitFunction;
131 var dialogOptions = {
137 $j('#catlinks').prepend(dialog);
138 dialog.dialog( dialogOptions );
143 doEdit : function( page, fn, summary, doneFn ) {
144 // Get an edit token for the page.
147 'prop':'info|revisions',
150 'rvprop':'content|timestamp',
154 $j.get(wgScriptPath+'/api.php', getTokenVars,
156 var infos = reply.query.pages;
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;
174 'basetimestamp':timestamp,
178 $j.post( wgScriptPath+'/api.php', postEditVars, doneFn, 'json' );
185 addProgressIndicator : function( elem ) {
186 var indicator = $j('<div/>');
188 indicator.addClass('mw-ajax-loader');
190 elem.append( indicator );
193 removeProgressIndicator : function( elem ) {
194 elem.find('.mw-ajax-loader').remove();
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(
205 function(oldText) { return oldText+appendText },
207 ajaxCategories.reloadCategoryList
211 handleDeleteLink : function(e) {
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
221 var categoryNSFragment = '';
222 $j.each(wgNamespaceIds, function( name, id ) {
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);
230 categoryNSFragment = categoryNSFragment.substr(1); // Remove leading |
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(
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');
258 summary, ajaxCategories.reloadCategoryList
262 showError : function( str ) {
263 var dialog = $j('<div/>');
266 $j('#bodyContent').append(dialog);
269 buttons[gM('ajax-error-dismiss')] = function(e) {
270 dialog.dialog('close');
272 var dialogOptions = {
275 'title' : gM('ajax-error-title')
278 dialog.dialog(dialogOptions);
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);
322 clElement.append(promptContainer);
326 js2AddOnloadHook( ajaxCategories.setupAJAXCategories );