Commit RELEASE-NOTES line for the wgCategories js variable I added some time ago.
[lhc/web/wiklou.git] / js2 / mwEmbed / libAddMedia / searchLibs / mediaWikiSearch.js
1 var mediaWikiSearch = function( iObj ) {
2 return this.init( iObj );
3 };
4 mediaWikiSearch.prototype = {
5 init:function( iObj ) {
6 // init base class and inherit:
7 var baseSearch = new baseRemoteSearch( iObj );
8 for ( var i in baseSearch ) {
9 if ( typeof this[i] == 'undefined' ) {
10 this[i] = baseSearch[i];
11 } else {
12 this['parent_' + i] = baseSearch[i];
13 }
14 }
15 // inherit the cp settings for
16 },
17 // returns a rObj by title
18 addByTitle:function( title , callback, redirect_count ) {
19 js_log( "AddByTitle::" + title );
20 var _this = this;
21 if ( !redirect_count )
22 redirect_count = 0;
23 if ( redirect_count > 5 ) {
24 js_log( 'Error: addByTitle too many redirects' );
25 callback( false );
26 return false;
27 }
28 var reqObj = {
29 'action':'query',
30 'titles':'File:' + title,
31 'prop':'imageinfo|revisions|categories',
32 'iiprop':'url|mime|size',
33 'iiurlwidth': parseInt( this.rsd.thumb_width ),
34 'rvprop':'content'
35 }
36 do_api_req( {
37 'data':reqObj,
38 'url':this.cp.api_url
39 }, function( data ) {
40 // check for redirect
41 for ( var i in data.query.pages ) {
42 var page = data.query.pages[i];
43 if ( page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) {
44 var re = new RegExp( /[^\[]*\[\[([^\]]*)/ );
45 var pt = page.revisions[0]['*'].match( re );
46 if ( pt[1] ) {
47 _this.addByTitle( pt[1], callback, redirect_count++ );
48 return ;
49 } else {
50 js_log( 'Error: addByTitle could not proccess redirect' );
51 callback( false );
52 return false;
53 }
54 }
55 }
56 // if not a redirect do the callback directly:
57 callback( _this.addSingleResult( data ) );
58 }
59 );
60 },
61 clearResults:function() {
62 this.resultsObj = { };
63 this.last_query = '';
64 },
65 // update the resultObj with recently uploaded items by current User:
66 getUserRecentUploads:function( wgUser, callback ) {
67 var _this = this;
68 do_api_req( {
69 'url':this.cp.api_url,
70 'data': {
71 'action':'query',
72 'list':'recentchanges',
73 'rcnamespace':6, // only files
74 'rcuser': wgUser,
75 'rclimit':15 // get last 15 uploaded files
76 }
77 }, function( data ) {
78 var titleSet = { };
79 var titleStr = ''
80 var pound = '';
81 // loop over the data and group by title
82 if ( data.query && data.query.recentchanges ) {
83 for ( var i in data.query.recentchanges ) {
84 var rc = data.query.recentchanges[i];
85 if ( !titleSet[ rc.title ] ) {
86 titleSet[ rc.title ] = true;
87 titleStr += pound + rc.title;
88 pound = '|';
89 }
90 }
91 }
92 // now run the actual query ( too bad we can't use recentchanges as a generator )
93 // bug 20563
94 do_api_req( {
95 'data' : {
96 'action' : 'query',
97 'titles' : titleStr,
98 'prop' : 'imageinfo|revisions|categories',
99 'iiprop' : 'url|mime|size',
100 'iiurlwidth': parseInt( _this.rsd.thumb_width ),
101 'rvprop':'content'
102 },
103 'url':_this.cp.api_url
104 }, function( data ) {
105 _this.clearResults();
106 _this.addResults( data );
107 if ( callback )
108 callback();
109 } );
110 } );
111 },
112 getSearchResults:function() {
113 // Call parent:
114 this.parent_getSearchResults();
115 // Set local ref:
116 var _this = this;
117
118 js_log( 'f:getSearchResults for:' + $j( '#rsd_q' ).val() );
119 // Do two queries against the Image / File / MVD namespace:
120
121 // Build the image request object:
122 var reqObj = {
123 'action':'query',
124 'generator':'search',
125 'gsrsearch': $j( '#rsd_q' ).val(),
126 'gsrnamespace':6, // (only search the "file" namespace (audio, video, images)
127 'gsrwhat':'title',
128 'gsrlimit': this.cp.limit,
129 'gsroffset': this.cp.offset,
130 'prop':'imageinfo|revisions|categories',
131 'iiprop':'url|mime|size',
132 'iiurlwidth': parseInt( this.rsd.thumb_width ),
133 'rvprop':'content'
134 };
135 // Set up the number of request:
136 this.completed_req = 0;
137 this.num_req = 1;
138 // Setup the number of requests result flag:
139 // Also do a request for page titles (would be nice if api could query both at the same time)
140 reqObj['gsrwhat'] = 'text';
141 do_api_req( {
142 'data':reqObj,
143 'url':this.cp.api_url
144 }, function( data ) {
145 js_log( 'mediaWikiSearch: got data response' );
146 // parse the return data
147 _this.addResults( data );
148 // _this.checkRequestDone(); //only need if we do two queries one for title one for text
149 _this.loading = false;
150 } );
151 },
152 // same as below but returns your rObj for convenience
153 addSingleResult:function( data ) {
154 return this.addResults( data, true );
155 },
156 addResults:function( data, returnFirst ) {
157 js_log( "f:addResults" );
158 var _this = this
159 // check if we have
160 if ( typeof data['query-continue'] != 'undefined' ) {
161 if ( typeof data['query-continue'].search != 'undefined' )
162 this.more_results = true;
163 }
164 // Make sure we have pages to idorate:
165 if ( data.query && data.query.pages ) {
166 for ( var page_id in data.query.pages ) {
167 var page = data.query.pages[ page_id ];
168
169 // Make sure the reop is shared (don't show for now it confusing things)
170 // @@todo support remote repository better
171 if ( page.imagerepository == 'shared' ) {
172 continue;
173 }
174
175 // Make sure the page is not a redirect
176 if ( page.revisions && page.revisions[0] &&
177 page.revisions[0]['*'] && page.revisions[0]['*'].indexOf( '#REDIRECT' ) === 0 ) {
178 // skip page is redirect
179 continue;
180 }
181 // Skip if its an empty or missing imageinfo:
182 if ( !page.imageinfo )
183 continue;
184 var rObj = {
185 'id' : page_id,
186 'titleKey' : page.title,
187 'link' : page.imageinfo[0].descriptionurl,
188 'title' : page.title.replace(/File:.jpg|.png|.svg|.ogg|.ogv|.oga/ig, ''),
189 'poster' : page.imageinfo[0].thumburl,
190 'thumbwidth' : page.imageinfo[0].thumbwidth,
191 'thumbheight': page.imageinfo[0].thumbheight,
192 'orgwidth' : page.imageinfo[0].width,
193 'orgheight' : page.imageinfo[0].height,
194 'mime' : page.imageinfo[0].mime,
195 'src' : page.imageinfo[0].url,
196 'desc' : page.revisions[0]['*'],
197 // add pointer to parent search obj:
198 'pSobj' :_this,
199 'meta': {
200 'categories':page.categories
201 }
202 };
203 /*
204 //to use once we get the wiki-text parser in shape
205 var pObj = mw.parser.pNew( rObj.desc );
206 //structured data on commons is based on the "information" template:
207 var tmplInfo = pObj.templates( 'information' );
208 rObj.desc = tmplInfo.description
209 */
210
211 // Attempt to parse out the description current user desc from the commons template:
212 // @@todo these could be combined to a single regEx
213 // or better improve the wiki-text parsing and use above
214 var desc = rObj.desc.match( /\|\s*description\s*=\s*(([^\n]*\n)*)\|\s*source=/i );
215 if ( desc && desc[1] ) {
216 rObj.desc = $j.trim( desc[1] );
217 // attempt to get the user language if set:
218 if ( typeof wgUserLanguage != 'undefined' && wgUserLanguage ) {
219 // for some reason the RegExp object is not happy:
220 var reg = new RegExp( '\{\{\s*' + wgUserLanguage + '([^=]*)=([^\}]*)\}\}', 'gim' );
221 var langMatch = reg.exec( rObj.desc );
222 if ( langMatch && langMatch[2] ) {
223 rObj.desc = langMatch[2];
224 } else {
225 // try simple lang template form:
226 var reg = new RegExp( '\{\{\s*' + wgUserLanguage + '\\|([^\}]*)\}\}', 'gim' );
227 var langMatch = reg.exec( rObj.desc );
228 if ( langMatch && langMatch[1] ) {
229 rObj.desc = langMatch[1];
230 }
231 }
232 }
233 }
234
235 // Likely a audio clip if no poster and type application/ogg
236 // @@todo we should return audio/ogg for the mime type or some other way to specify its "audio"
237 if ( ! rObj.poster && rObj.mime == 'application/ogg' ) {
238 rObj.mime = 'audio/ogg';
239 }
240 // Add to the resultObj
241 this.resultsObj[page_id] = rObj;
242
243 // If returnFirst flag:
244 if ( returnFirst )
245 return this.resultsObj[page_id];
246
247
248 this.num_results++;
249 // for(var i in this.resultsObj[page_id]){
250 // js_log('added: '+ i +' '+ this.resultsObj[page_id][i]);
251 // }
252 }
253 } else {
254 js_log( 'no results:' + data );
255 }
256 },
257 // Check request done used for when we have multiple requests to check before formating results.
258 checkRequestDone:function() {
259 // Display output if done:
260 this.completed_req++;
261 if ( this.completed_req == this.num_req ) {
262 this.loading = 0;
263 }
264 },
265 getImageObj:function( rObj, size, callback ) {
266 if ( rObj.mime == 'application/ogg' )
267 return callback( { 'url':rObj.src, 'poster' : rObj.url } );
268
269 // This could be depreciated if thumb.php support is standard
270 var reqObj = {
271 'action':'query',
272 'format':'json',
273 'titles':rObj.titleKey,
274 'prop':'imageinfo',
275 'iiprop':'url|size|mime'
276 }
277 // Set the width:
278 if ( size.width )
279 reqObj['iiurlwidth'] = size.width;
280 js_log( 'going to do req: ' + this.cp.api_url + ' ' + reqObj );
281 do_api_req( {
282 'data':reqObj,
283 'url' : this.cp.api_url
284 }, function( data ) {
285 var imObj = { };
286 for ( var page_id in data.query.pages ) {
287 var iminfo = data.query.pages[ page_id ].imageinfo[0];
288 // store the orginal width:
289 imObj['org_width'] = iminfo.width;
290 // check if thumb size > than image size and is jpeg or png (it will not scale well above its max res)
291 if ( ( iminfo.mime == 'image/jpeg' || iminfo == 'image/png' ) &&
292 iminfo.thumbwidth > iminfo.width ) {
293 imObj['url'] = iminfo.url;
294 imObj['width'] = iminfo.width;
295 imObj['height'] = iminfo.height;
296 } else {
297 imObj['url'] = iminfo.thumburl;
298 imObj['width'] = iminfo.thumbwidth;
299 imObj['height'] = iminfo.thumbheight;
300 }
301 }
302 js_log( 'getImageObj: get: ' + size.width + ' got url:' + imObj.url );
303 callback( imObj );
304 } );
305 },
306 // the insert image function
307 insertImage:function( cEdit ) {
308 if ( !cEdit )
309 var cEdit = _this.cEdit;
310 },
311 getInlineDescWiki:function( rObj ) {
312 var desc = this.parent_getInlineDescWiki( rObj );
313
314 // Strip categories for inline Desc: (should strip license tags too but not as easy)
315 desc = desc.replace( /\[\[Category\:[^\]]*\]\]/gi, '' );
316
317 // Just grab the description tag for inline desc:
318 var descMatch = new RegExp( /Description=(\{\{en\|)?([^|]*|)/ );
319 var dparts = desc.match( descMatch );
320
321 if ( dparts && dparts.length > 1 ) {
322 desc = ( dparts.length == 2 ) ? dparts[1] : dparts[2].replace( '}}', '' );
323 desc = ( desc.substr( 0, 2 ) == '1=' ) ? desc.substr( 2 ): desc;
324 return desc;
325 }
326 // Hackish attempt to strip templates
327 desc = desc.replace( /\{\{[^\}]*\}\}/gi, '' );
328 // strip any nexted template closures
329 desc = desc.replace( /\}\}/gi, '' );
330 // strip titles
331 desc = desc.replace( /\=\=[^\=]*\=\=/gi, '' );
332
333 // else return the title since we could not find the desc:
334 js_log( 'Error: No Description Tag, Using::' + desc );
335 return desc;
336 },
337 // Returns the inline wikitext for insertion (template based crops for now)
338 getEmbedWikiCode: function( rObj ) {
339 // Set default layout to right justified
340 var layout = ( rObj.layout ) ? rObj.layout:"right"
341 // if crop is null do base output:
342 if ( rObj.crop == null )
343 return this.parent_getEmbedWikiCode( rObj );
344 // Using the preview crop template: http://en.wikipedia.org/wiki/Template:Preview_Crop
345 // @@todo should be replaced with server side cropping
346 return '{{Preview Crop ' + "\n" +
347 '|Image = ' + rObj.target_resource_title + "\n" +
348 '|bSize = ' + rObj.width + "\n" +
349 '|cWidth = ' + rObj.crop.w + "\n" +
350 '|cHeight = ' + rObj.crop.h + "\n" +
351 '|oTop = ' + rObj.crop.y + "\n" +
352 '|oLeft = ' + rObj.crop.x + "\n" +
353 '|Location =' + layout + "\n" +
354 '|Description =' + rObj.inlineDesc + "\n" +
355 '}}';
356 }
357 }