Index: trunk/extensions/UploadWizard/UploadWizardHooks.php |
— | — | @@ -40,12 +40,6 @@ |
41 | 41 | 'resources/jquery/jquery.removeCtrl.js', |
42 | 42 | 'resources/jquery/jquery.pubsub.js', |
43 | 43 | |
44 | | - // mediawiki-specific interface helper (relies on mediawiki globals) |
45 | | - 'resources/jquery/jquery.mwCoolCats.js', |
46 | | - |
47 | | - // wikimedia-comons specific title checker |
48 | | - 'resources/jquery/jquery.validate.wmCommonsBlacklist.js', |
49 | | - |
50 | 44 | // common utilities |
51 | 45 | 'resources/mw.fileApi.js', |
52 | 46 | 'resources/mw.units.js', |
— | — | @@ -56,10 +50,17 @@ |
57 | 51 | 'resources/mw.Uri.js', |
58 | 52 | 'resources/mw.Api.js', |
59 | 53 | 'resources/mw.Api.edit.js', |
| 54 | + 'resources/mw.Api.category.js', |
60 | 55 | 'resources/mw.Title.js', |
61 | 56 | 'resources/mw.Feedback.js', |
62 | 57 | 'resources/mw.ConfirmCloseWindow.js', |
63 | 58 | |
| 59 | + // mediawiki-specific interface helper (relies on mediawiki globals) |
| 60 | + 'resources/jquery/jquery.mwCoolCats.js', |
| 61 | + |
| 62 | + // wikimedia-comons specific title checker |
| 63 | + 'resources/jquery/jquery.validate.wmCommonsBlacklist.js', |
| 64 | + |
64 | 65 | // language menus |
65 | 66 | 'resources/mw.LanguageUpWiz.js', |
66 | 67 | |
— | — | @@ -342,7 +343,11 @@ |
343 | 344 | 'size-gigabytes', |
344 | 345 | 'size-megabytes', |
345 | 346 | 'size-kilobytes', |
346 | | - 'size-bytes' |
| 347 | + 'size-bytes', |
| 348 | + 'mw-coolcats-confirm-new-title', |
| 349 | + 'mw-coolcats-confirm-new', |
| 350 | + 'mw-coolcats-confirm-new-ok', |
| 351 | + 'mw-coolcats-confirm-new-cancel' |
347 | 352 | ), |
348 | 353 | 'group' => 'ext.uploadWizard' |
349 | 354 | ), |
Index: trunk/extensions/UploadWizard/UploadWizard.i18n.php |
— | — | @@ -300,6 +300,13 @@ |
301 | 301 | 'mwe-upwiz-campaign-enabled' => 'Campaign enabled', |
302 | 302 | 'mwe-upwiz-campaign-conf-skipTutorial' => 'Skip the licensing tutorial', |
303 | 303 | 'mwe-upwiz-campaign-conf-autoCategories' => 'Categories to add the images to automatically', |
| 304 | + |
| 305 | + // Coolcats |
| 306 | + 'mw-coolcats-confirm-new-title' => 'Confirm New category', |
| 307 | + 'mw-coolcats-confirm-new' => 'It looks like you are trying to add a new category, "$1". Be aware:<ul><li>Categories should usually be in English.</li><li>Most new categories should be a subcategory of an existing category.</li></ul>Generally, only experts should add a category.', |
| 308 | + 'mw-coolcats-confirm-new-ok' => 'Add this category anyway', |
| 309 | + 'mw-coolcats-confirm-new-cancel' => 'Never mind' |
| 310 | + |
304 | 311 | ); |
305 | 312 | |
306 | 313 | /** Message documentation (Message documentation) |
Index: trunk/extensions/UploadWizard/resources/jquery/jquery.mwCoolCats.js |
— | — | @@ -1,10 +1,138 @@ |
2 | 2 | /** |
3 | 3 | * Simple predictive typing category adder for Mediawiki. |
4 | | - * Relies on globals: wgScriptPath, wgNamespaceIds, wgFormattedNamespaces |
| 4 | + * Relies on mw.Title, mw.api.category, $.fn.removeCtrl |
5 | 5 | * Add to the page and then use getWikiText() to get wiki text representing the categories. |
6 | 6 | */ |
7 | 7 | ( function ( $j ) { $j.fn.mwCoolCats = function( options ) { |
8 | 8 | |
| 9 | + /** |
| 10 | + * Get content from our text field, and attempt to insert it as a category. |
| 11 | + * May require confirmation from user if they appear to be adding a new category. |
| 12 | + */ |
| 13 | + function _processInput() { |
| 14 | + var $input = $container.find( 'input' ); |
| 15 | + var text = _stripText( $input.val() ); |
| 16 | + if ( text === '' ) { |
| 17 | + return; |
| 18 | + } |
| 19 | + |
| 20 | + var title = new mw.Title( text, 'category' ); |
| 21 | + |
| 22 | + var insertIt = function() { |
| 23 | + _insertCat( title ); |
| 24 | + $input.val(""); |
| 25 | + }; |
| 26 | + |
| 27 | + var confirmIt = function() { |
| 28 | + var buttons = [ |
| 29 | + { |
| 30 | + text: gM( 'mw-coolcats-confirm-new-cancel' ), |
| 31 | + click: function() { |
| 32 | + $( this ).dialog( "close" ); |
| 33 | + } |
| 34 | + }, |
| 35 | + { |
| 36 | + text: gM( 'mw-coolcats-confirm-new-ok' ), |
| 37 | + click: function() { |
| 38 | + insertIt(); |
| 39 | + $( this ).dialog( "close" ); |
| 40 | + } |
| 41 | + } |
| 42 | + ]; |
| 43 | + $j( '<div></div>' ) |
| 44 | + .msg( 'mw-coolcats-confirm-new', title.getMainText() ) |
| 45 | + .dialog( { |
| 46 | + width: 500, |
| 47 | + zIndex: 200000, |
| 48 | + autoOpen: true, |
| 49 | + title: gM( 'mw-coolcats-confirm-new-title' ), |
| 50 | + modal: true, |
| 51 | + buttons: buttons |
| 52 | + } ); |
| 53 | + }; |
| 54 | + |
| 55 | + if( seenTitleText[ title.getMainText() ] ) { |
| 56 | + insertIt(); |
| 57 | + } else { |
| 58 | + settings.api.isCategory( title, function( isCategory ) { |
| 59 | + if ( isCategory ) { |
| 60 | + insertIt(); |
| 61 | + } else { |
| 62 | + confirmIt(); |
| 63 | + } |
| 64 | + } ); |
| 65 | + } |
| 66 | + |
| 67 | + } |
| 68 | + |
| 69 | + /** |
| 70 | + * Add a new category to the page |
| 71 | + * @param {mw.Title} title of category -- should already be in category namespace |
| 72 | + * @param {boolean} whether this category is visible to the user |
| 73 | + */ |
| 74 | + function _insertCat( title, isHidden ) { |
| 75 | + if ( _containsCat( title ) ) { |
| 76 | + return; |
| 77 | + } |
| 78 | + var $li = $j( '<li/>' ).addClass( 'cat' ); |
| 79 | + var $anchor = $j( '<a/>' ).addClass( 'cat' ).append( title.getMainText() ); |
| 80 | + $li.append( $anchor ); |
| 81 | + $li.data( 'title', title ); |
| 82 | + if ( isHidden ) { |
| 83 | + $li.hide(); |
| 84 | + } else { |
| 85 | + $anchor.attr( { target: "_blank", href: title.getUrl() } ); |
| 86 | + $li.append( $j.fn.removeCtrl( null, 'mwe-upwiz-category-remove', function() { $li.remove(); } ) ); |
| 87 | + } |
| 88 | + $container.find( 'ul' ).append( $li ); |
| 89 | + } |
| 90 | + |
| 91 | + /** |
| 92 | + * Get all the HTML elements representing categories on the page |
| 93 | + * @return {Array of mw.Title} |
| 94 | + */ |
| 95 | + function _getCats() { |
| 96 | + return $container.find('ul li.cat').map( function() { return $j( this ).data( 'title' ); } ); |
| 97 | + } |
| 98 | + |
| 99 | + /** |
| 100 | + * Check if we already have this category on the page |
| 101 | + * @param {mw.Title} |
| 102 | + * @return boolean, true if already on the page |
| 103 | + */ |
| 104 | + function _containsCat( title ) { |
| 105 | + var s = title.toString(); |
| 106 | + return _getCats().filter( function() { return this.toString() == s; } ).length !== 0; |
| 107 | + } |
| 108 | + |
| 109 | + /** |
| 110 | + * Normalize text |
| 111 | + * @param {String} |
| 112 | + * @return string stripped of some characters, trimmed |
| 113 | + */ |
| 114 | + function _stripText( s ) { |
| 115 | + return $j.trim( s.replace( /[\x00-\x1f\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f]+/g, '' ) ); |
| 116 | + } |
| 117 | + |
| 118 | + /** |
| 119 | + * Fetch and display suggestions for categories, based on what the user has already typed |
| 120 | + * into the text field |
| 121 | + */ |
| 122 | + function _fetchSuggestions() { |
| 123 | + var _input = this; |
| 124 | + // ignore bad characters, they will be stripped out |
| 125 | + var prefix = _stripText( $j( this ).val() ); |
| 126 | + |
| 127 | + var ok = function( catList ) { |
| 128 | + $j( _input ).suggestions( 'suggestions', catList ); |
| 129 | + $j.each( catList, function( i, category ) { |
| 130 | + seenTitleText[category] = 1; |
| 131 | + } ); |
| 132 | + }; |
| 133 | + |
| 134 | + $j( _input ).data( 'request', settings.api.getCategoriesByPrefix( prefix, ok ) ); |
| 135 | + } |
| 136 | + |
9 | 137 | var defaults = { |
10 | 138 | buttontext: 'Add', |
11 | 139 | hiddenCats: [], |
— | — | @@ -12,13 +140,21 @@ |
13 | 141 | }; |
14 | 142 | |
15 | 143 | var settings = $j.extend( {}, defaults, options ); |
| 144 | + if ( !settings.api ) { |
| 145 | + throw new Error( "jQuery.mwCoolCats needs an 'api' argument" ); |
| 146 | + } |
16 | 147 | |
17 | | - // usually Category:Foo |
18 | | - var categoryNamespace = wgFormattedNamespaces[wgNamespaceIds['category']]; |
| 148 | + // a cache of suggestions we've seen, to check if the category they finally enter is already on the wiki or not. |
| 149 | + var seenTitleText = {}; |
19 | 150 | |
20 | 151 | var $container; |
| 152 | + |
| 153 | + /** |
| 154 | + * Initialize the text field(s) the widget was given to be category pickers. |
| 155 | + */ |
21 | 156 | return this.each( function() { |
22 | 157 | var _this = $j( this ); |
| 158 | + |
23 | 159 | _this.addClass( 'categoryInput' ); |
24 | 160 | |
25 | 161 | _this.suggestions( { |
— | — | @@ -60,94 +196,23 @@ |
61 | 197 | }); |
62 | 198 | |
63 | 199 | this.getWikiText = function() { |
64 | | - return _getCats().map( function() { return '[[' + categoryNamespace + ':' + this + ']]'; } ) |
65 | | - .toArray() |
66 | | - .join( "\n" ); |
| 200 | + debugger; |
| 201 | + var wikiText = '{{subst:unc}}'; |
| 202 | + var $cats = _getCats(); |
| 203 | + if ( $cats.length ) { |
| 204 | + wikiText = $cats.map( function() { return '[[' + this.toString() + ']]'; } ) |
| 205 | + .toArray() |
| 206 | + .join( "\n" ); |
| 207 | + } |
| 208 | + return wikiText; |
67 | 209 | }; |
68 | 210 | |
69 | 211 | // initialize with some categories, if so configured |
70 | | - $j.each( settings.cats, function( i, cat ) { _insertCat( cat ); } ); |
71 | | - $j.each( settings.hiddenCats, function( i, cat ) { _insertCat( cat, true ); } ); |
| 212 | + $j.each( settings.cats, function( i, cat ) { _insertCat( new mw.Title( cat, 'category' ) ); } ); |
| 213 | + $j.each( settings.hiddenCats, function( i, cat ) { _insertCat( new mw.Title( cat, 'category' ), true ); } ); |
72 | 214 | |
73 | 215 | _processInput(); |
74 | 216 | } ); |
75 | | - |
76 | | - function _processInput() { |
77 | | - var $input = $container.find( 'input' ); |
78 | | - _insertCat( $j.trim( $input.val() ) ); |
79 | | - $input.val(""); |
80 | | - } |
81 | 217 | |
82 | | - function _insertCat( cat, isHidden ) { |
83 | | - // strip out bad characters |
84 | | - cat = cat.replace( /[\x00-\x1f\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f]+/g, '' ); |
85 | | - if ( mw.isEmpty( cat ) || _containsCat( cat ) ) { |
86 | | - return; |
87 | | - } |
88 | | - var $li = $j( '<li/>' ).addClass( 'cat' ); |
89 | | - var $anchor = $j( '<a/>' ).addClass( 'cat' ).append( cat ); |
90 | | - $li.append( $anchor ); |
91 | | - if ( isHidden ) { |
92 | | - $li.hide(); |
93 | | - } else { |
94 | | - $anchor.attr( { target: "_blank", href: _catLink( cat ) } ); |
95 | | - $li.append( $j.fn.removeCtrl( null, 'mwe-upwiz-category-remove', function() { $li.remove(); } ) ); |
96 | | - } |
97 | | - $container.find( 'ul' ).append( $li ); |
98 | | - } |
99 | 218 | |
100 | | - function _catLink( cat ) { |
101 | | - var catLink = |
102 | | - encodeURIComponent( categoryNamespace ) |
103 | | - + ':' |
104 | | - + encodeURIComponent( mw.ucfirst( cat.replace(/ /g, '_' ) ) ); |
105 | | - |
106 | | - // wgServer typically like 'http://commons.prototype.wikimedia.org' |
107 | | - // wgArticlePath typically like '/wiki/$1' |
108 | | - if ( ! ( mw.isEmpty( wgServer ) && mw.isEmpty( wgArticlePath ) ) ) { |
109 | | - catLink = wgServer + wgArticlePath.replace( /\$1/, catLink ); |
110 | | - } |
111 | | - |
112 | | - return catLink; |
113 | | - } |
114 | | - |
115 | | - function _getCats() { |
116 | | - return $container.find('ul li a.cat').map( function() { return $j.trim( $j( this ).text() ); } ); |
117 | | - } |
118 | | - |
119 | | - function _containsCat( cat ) { |
120 | | - return _getCats().filter( function() { return this == cat; } ).length !== 0; |
121 | | - } |
122 | | - |
123 | | - function _fetchSuggestions( query ) { |
124 | | - var _this = this; |
125 | | - // ignore bad characters, they will be stripped out |
126 | | - var catName = $j( this ).val().replace( /[\x00-\x1f\x3c\x3e\x5b\x5d\x7b\x7c\x7d\x7f]+/g, '' ); |
127 | | - var request = $j.ajax( { |
128 | | - url: wgScriptPath + '/api.php', |
129 | | - data: { |
130 | | - 'action': 'query', |
131 | | - 'list': 'allpages', |
132 | | - 'apnamespace': wgNamespaceIds['category'], |
133 | | - 'apprefix': catName, |
134 | | - 'format': 'json' |
135 | | - }, |
136 | | - dataType: 'json', |
137 | | - success: function( data ) { |
138 | | - // Process data.query.allpages into an array of titles |
139 | | - var pages = data.query.allpages; |
140 | | - var titleArr = []; |
141 | | - |
142 | | - $j.each( pages, function( i, page ) { |
143 | | - var title = page.title.split( ':', 2 )[1]; |
144 | | - titleArr.push( title ); |
145 | | - } ); |
146 | | - |
147 | | - $j( _this ).suggestions( 'suggestions', titleArr ); |
148 | | - } |
149 | | - } ); |
150 | | - |
151 | | - $j( _this ).data( 'request', request ); |
152 | | - } |
153 | | - |
154 | 219 | }; } )( jQuery ); |
Index: trunk/extensions/UploadWizard/resources/mw.UploadWizardDetails.js |
— | — | @@ -158,6 +158,7 @@ |
159 | 159 | |
160 | 160 | $j( moreDetailsDiv ).append( |
161 | 161 | // location goes here |
| 162 | + $categoriesDiv, |
162 | 163 | otherInformationDiv |
163 | 164 | ); |
164 | 165 | |
— | — | @@ -170,7 +171,6 @@ |
171 | 172 | descriptionAdderDiv, |
172 | 173 | _this.copyrightInfoFieldset, |
173 | 174 | dateInputDiv, |
174 | | - $categoriesDiv, |
175 | 175 | moreDetailsCtrlDiv, |
176 | 176 | moreDetailsDiv |
177 | 177 | ); |
— | — | @@ -273,6 +273,7 @@ |
274 | 274 | $categoriesDiv.find( '.mwe-upwiz-details-input' ) |
275 | 275 | .find( 'input' ) |
276 | 276 | .mwCoolCats( { |
| 277 | + api: _this.upload.api, |
277 | 278 | hiddenCats: hiddenCats, |
278 | 279 | buttontext: gM( 'mwe-upwiz-categories-add' ) |
279 | 280 | } ); |