1 var mediaWikiSearch = function( iObj
) {
2 return this.init( iObj
);
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
];
12 this['parent_' + i
] = baseSearch
[i
];
15 // inherit the cp settings for
17 // returns a rObj by title
18 addByTitle:function( title
, callback
, redirect_count
) {
19 js_log( "AddByTitle::" + title
);
21 if ( !redirect_count
)
23 if ( redirect_count
> 5 ) {
24 js_log( 'Error: addByTitle too many redirects' );
30 'titles':'File:' + title
,
31 'prop':'imageinfo|revisions|categories',
32 'iiprop':'url|mime|size',
33 'iiurlwidth': parseInt( this.rsd
.thumb_width
),
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
);
47 _this
.addByTitle( pt
[1], callback
, redirect_count
++ );
50 js_log( 'Error: addByTitle could not proccess redirect' );
56 // if not a redirect do the callback directly:
57 callback( _this
.addSingleResult( data
) );
61 clearResults:function() {
62 this.resultsObj
= { };
65 // update the resultObj with recently uploaded items by current User:
66 getUserRecentUploads:function( wgUser
, callback
) {
69 'url':this.cp
.api_url
,
72 'list':'recentchanges',
73 'rcnamespace':6, // only files
75 'rclimit':15 // get last 15 uploaded files
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
;
92 // now run the actual query ( too bad we can't use recentchanges as a generator )
98 'prop' : 'imageinfo|revisions|categories',
99 'iiprop' : 'url|mime|size',
100 'iiurlwidth': parseInt( _this
.rsd
.thumb_width
),
103 'url':_this
.cp
.api_url
104 }, function( data
) {
105 _this
.clearResults();
106 _this
.addResults( data
);
112 getSearchResults:function() {
114 this.parent_getSearchResults();
118 js_log( 'f:getSearchResults for:' + $j( '#rsd_q' ).val() );
119 // Do two queries against the Image / File / MVD namespace:
121 // Build the image request object:
124 'generator':'search',
125 'gsrsearch': $j( '#rsd_q' ).val(),
126 'gsrnamespace':6, // (only search the "file" namespace (audio, video, images)
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
),
135 // Set up the number of request:
136 this.completed_req
= 0;
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';
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;
152 // same as below but returns your rObj for convenience
153 addSingleResult:function( data
) {
154 return this.addResults( data
, true );
156 addResults:function( data
, returnFirst
) {
157 js_log( "f:addResults" );
160 if ( typeof data
['query-continue'] != 'undefined' ) {
161 if ( typeof data
['query-continue'].search
!= 'undefined' )
162 this.more_results
= true;
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
];
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' ) {
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
181 // Skip if its an empty or missing imageinfo:
182 if ( !page
.imageinfo
)
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:
200 'categories':page
.categories
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
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];
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];
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';
240 // Add to the resultObj
241 this.resultsObj
[page_id
] = rObj
;
243 // If returnFirst flag:
245 return this.resultsObj
[page_id
];
249 // for(var i in this.resultsObj[page_id]){
250 // js_log('added: '+ i +' '+ this.resultsObj[page_id][i]);
254 js_log( 'no results:' + data
);
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
) {
265 getImageObj:function( rObj
, size
, callback
) {
266 if ( rObj
.mime
== 'application/ogg' )
267 return callback( { 'url':rObj
.src
, 'poster' : rObj
.url
} );
269 // This could be depreciated if thumb.php support is standard
273 'titles':rObj
.titleKey
,
275 'iiprop':'url|size|mime'
279 reqObj
['iiurlwidth'] = size
.width
;
280 js_log( 'going to do req: ' + this.cp
.api_url
+ ' ' + reqObj
);
283 'url' : this.cp
.api_url
284 }, function( data
) {
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
;
297 imObj
['url'] = iminfo
.thumburl
;
298 imObj
['width'] = iminfo
.thumbwidth
;
299 imObj
['height'] = iminfo
.thumbheight
;
302 js_log( 'getImageObj: get: ' + size
.width
+ ' got url:' + imObj
.url
);
306 // the insert image function
307 insertImage:function( cEdit
) {
309 var cEdit
= _this
.cEdit
;
311 getInlineDescWiki:function( rObj
) {
312 var desc
= this.parent_getInlineDescWiki( rObj
);
314 // Strip categories for inline Desc: (should strip license tags too but not as easy)
315 desc
= desc
.replace( /\[\[Category\:[^\]]*\]\]/gi, '' );
317 // Just grab the description tag for inline desc:
318 var descMatch
= new RegExp( /Description=(\{\{en\|)?([^|]*|)/ );
319 var dparts
= desc
.match( descMatch
);
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
;
326 // Hackish attempt to strip templates
327 desc
= desc
.replace( /\{\{[^\}]*\}\}/gi, '' );
328 // strip any nexted template closures
329 desc
= desc
.replace( /\}\}/gi, '' );
331 desc
= desc
.replace( /\=\=[^\=]*\=\=/gi, '' );
333 // else return the title since we could not find the desc:
334 js_log( 'Error: No Description Tag, Using::' + desc
);
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" +