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
= {
17 handleAddLink : function(e
) {
20 // Make sure the suggestion plugin is loaded. Load everything else while we're at it
21 mvJsLoader
.doLoad( ['$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();
38 fetchSuggestions : function( query
) {
40 var request
= $j
.ajax( {
41 url
: wgScriptPath
+ '/api.php',
46 'apprefix': $j(this).val(),
50 success: function( data
) {
51 // Process data.query.allpages into an array of titles
52 var pages
= data
.query
.allpages
;
55 $j
.each(pages
, function(i
, page
) {
56 var title
= page
.title
.split( ':', 2 )[1];
60 $j(that
).suggestions( 'suggestions', titleArr
);
64 ajaxCategories
.request
= request
;
67 reloadCategoryList : function( response
) {
68 var holder
= $j('<div/>');
70 holder
.load( window
.location
.href
+' .catlinks', function() {
71 $j('.catlinks').replaceWith( holder
.find('.catlinks') );
72 ajaxCategories
.setupAJAXCategories();
73 ajaxCategories
.removeProgressIndicator( $j('.catlinks') );
77 confirmEdit : function( page
, fn
, actionSummary
, doneFn
) {
79 mvJsLoader
.doLoad( ['$j.ui', '$j.ui.dialog', '$j.fn.suggestions'], function() {
80 // Produce a confirmation dialog
82 var dialog
= $j('<div/>');
84 dialog
.addClass('mw-ajax-confirm-dialog');
85 dialog
.attr( 'title', gM('ajax-confirm-title') );
88 var confirmIntro
= $j('<p/>');
89 confirmIntro
.text( gM('ajax-confirm-prompt') );
90 dialog
.append(confirmIntro
);
92 // Summary of the action to be taken
93 var summaryHolder
= $j('<p/>');
94 var summaryLabel
= $j('<strong/>');
95 summaryLabel
.text(gM('ajax-confirm-actionsummary')+" " );
96 summaryHolder
.text( actionSummary
);
97 summaryHolder
.prepend( summaryLabel
);
98 dialog
.append(summaryHolder
);
101 var reasonBox
= $j('<input type="text" size="45" />');
102 reasonBox
.addClass('mw-ajax-confirm-reason');
103 dialog
.append(reasonBox
);
106 var submitButton
= $j('<input type="button"/>');
107 submitButton
.val( gM( 'ajax-confirm-save' ) );
109 var submitFunction = function() {
110 ajaxCategories
.addProgressIndicator( dialog
);
111 ajaxCategories
.doEdit( page
, fn
, reasonBox
.val(),
114 dialog
.dialog('close');
115 ajaxCategories
.removeProgressIndicator( dialog
);
121 buttons
[gM('ajax-confirm-save')] = submitFunction
;
122 var dialogOptions
= {
128 $j('#catlinks').prepend(dialog
);
129 dialog
.dialog( dialogOptions
);
133 doEdit : function( page
, fn
, summary
, doneFn
) {
134 // Get an edit token for the page.
137 'prop':'info|revisions',
140 'rvprop':'content|timestamp',
143 $j
.get(wgScriptPath
+'/api.php', getTokenVars
,
145 var infos
= reply
.query
.pages
;
146 $j
.each(infos
, function(pageid
, data
) {
147 var token
= data
.edittoken
;
148 var timestamp
= data
.revisions
[0].timestamp
;
149 var oldText
= data
.revisions
[0]['*'];
151 var newText
= fn(oldText
);
153 if (newText
=== false) return;
161 'basetimestamp':timestamp
,
165 $j
.post( wgScriptPath
+'/api.php', postEditVars
, doneFn
, 'json' );
171 addProgressIndicator : function( elem
) {
172 var indicator
= $j('<div/>');
174 indicator
.addClass('mw-ajax-loader');
176 elem
.append( indicator
);
179 removeProgressIndicator : function( elem
) {
180 elem
.find('.mw-ajax-loader').remove();
183 handleCategoryAdd : function(e
) {
184 // Grab category text
185 var category
= $j('#mw-addcategory-input').val();
186 var appendText
= "\n[["+wgFormattedNamespaces
[14]+":"+category
+"]]\n";
187 var summary
= gM('ajax-add-category-summary', category
);
189 ajaxCategories
.confirmEdit( wgPageName
, function(oldText
) { return oldText
+appendText
},
190 summary
, ajaxCategories
.reloadCategoryList
);
193 handleDeleteLink : function(e
) {
196 var category
= $j(this).parent().find('a').text();
198 // Build a regex that matches legal invocations of that category.
200 // In theory I should escape the aliases, but there's no JS function for it
201 // Shouldn't have any real impact, can't be exploited or anything, so we'll
203 var categoryNSFragment
= '';
204 $j
.each(wgNamespaceIds
, function( name
, id
) {
206 // Allow the first character to be any case
207 var firstChar
= name
.charAt(0);
208 firstChar
= '['+firstChar
.toUpperCase()+firstChar
.toLowerCase()+']'
209 categoryNSFragment
+= '|'+firstChar
+name
.substr(1);
212 categoryNSFragment
= categoryNSFragment
.substr(1) // Remove leading |
216 var titleFragment
= category
;
218 firstChar
= category
.charAt(0);
219 firstChar
= '['+firstChar
.toUpperCase()+firstChar
.toLowerCase()+']';
220 titleFragment
= firstChar
+category
.substr(1);
221 var categoryRegex
= '\\[\\['+categoryNSFragment
+':'+titleFragment
+'(\\|[^\\]]*)?\\]\\]';
222 categoryRegex
= new RegExp( categoryRegex
, 'g' );
224 var summary
= gM('ajax-remove-category-summary', category
);
226 ajaxCategories
.confirmEdit( wgPageName
,
228 var newText
= oldText
.replace(categoryRegex
, '');
230 if (newText
== oldText
) {
231 var error
= gM('ajax-remove-category-error');
232 ajaxCategories
.showError( error
);
233 ajaxCategories
.removeProgressIndicator( $j('.mw-ajax-confirm-dialog') );
234 $j('.mw-ajax-confirm-dialog').dialog('close');
239 }, summary
, ajaxCategories
.reloadCategoryList
);
242 showError : function( str
) {
243 var dialog
= $j('<div/>');
246 $j('#bodyContent').append(dialog
);
249 buttons
[gM('ajax-error-dismiss')] = function(e
) { dialog
.dialog('close'); };
250 var dialogOptions
= {
253 'title' : gM('ajax-error-title'),
256 dialog
.dialog(dialogOptions
);
259 setupAJAXCategories : function() {
260 // Only do it for articles.
261 if ( !wgIsArticle
) return;
263 var clElement
= $j('.catlinks');
265 // Unhide hidden category holders.
266 clElement
.removeClass( 'catlinks-allhidden' );
268 var addLink
= $j('<a/>');
269 addLink
.addClass( 'mw-ajax-addcategory' );
271 // Create [Add Category] link
272 addLink
.text( gM( 'ajax-add-category' ) );
273 addLink
.attr('href', '#');
274 addLink
.click( ajaxCategories
.handleAddLink
);
275 clElement
.append(addLink
);
277 // Create add category prompt
278 var promptContainer
= $j('<div id="mw-addcategory-prompt"/>');
279 var promptTextbox
= $j('<input type="text" size="45" id="mw-addcategory-input"/>');
280 var addButton
= $j('<input type="button" id="mw-addcategory-button"/>' );
281 addButton
.val( gM('ajax-add-category-submit') );
283 promptTextbox
.keypress( ajaxCategories
.handleCategoryInput
);
284 addButton
.click( ajaxCategories
.handleCategoryAdd
);
286 promptContainer
.append(promptTextbox
);
287 promptContainer
.append(addButton
);
288 promptContainer
.hide();
290 // Create delete link for each category.
291 $j('.catlinks div span a').each( function(e
) {
292 // Create a remove link
293 var deleteLink
= $j('<a class="mw-remove-category" href="#"/>');
295 deleteLink
.click(ajaxCategories
.handleDeleteLink
);
297 $j(this).after(deleteLink
);
300 clElement
.append(promptContainer
);
305 js2AddOnloadHook( ajaxCategories
.setupAJAXCategories
);