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) { dialog.dialog('close'); };
270 var dialogOptions = {
273 'title' : gM('ajax-error-title'),
276 dialog.dialog(dialogOptions);
279 setupAJAXCategories : function() {
280 // Only do it for articles.
281 if ( !wgIsArticle ) return;
283 var clElement = $j('.catlinks');
285 // Unhide hidden category holders.
286 clElement.removeClass( 'catlinks-allhidden' );
288 var addLink = $j('<a/>');
289 addLink.addClass( 'mw-ajax-addcategory' );
291 // Create [Add Category] link
292 addLink.text( gM( 'ajax-add-category' ) );
293 addLink.attr('href', '#');
294 addLink.click( ajaxCategories.handleAddLink );
295 clElement.append(addLink);
297 // Create add category prompt
298 var promptContainer = $j('<div id="mw-addcategory-prompt"/>');
299 var promptTextbox = $j('<input type="text" size="45" id="mw-addcategory-input"/>');
300 var addButton = $j('<input type="button" id="mw-addcategory-button"/>' );
301 addButton.val( gM('ajax-add-category-submit') );
303 promptTextbox.keypress( ajaxCategories.handleCategoryInput );
304 addButton.click( ajaxCategories.handleCategoryAdd );
306 promptContainer.append(promptTextbox);
307 promptContainer.append(addButton);
308 promptContainer.hide();
310 // Create delete link for each category.
311 $j('.catlinks div span a').each( function(e) {
312 // Create a remove link
313 var deleteLink = $j('<a class="mw-remove-category" href="#"/>');
315 deleteLink.click(ajaxCategories.handleDeleteLink);
317 $j(this).after(deleteLink);
320 clElement.append(promptContainer);
324 js2AddOnloadHook( ajaxCategories.setupAJAXCategories );