Bug 20489 Configure illegal file characters https://bugzilla.wikimedia.org/show_bug...
[mediawiki.git] / js2 / mwEmbed / libAddMedia / remoteSearchDriver.js
blob2fcfba1fb1afc7ff193b66e37823f3c7a607a3fd
1 /*
2  * a library for doing remote media searches
3  *
4  * initial targeted archives are:
5         the local wiki
6         wikimedia commons
7         metavid
8         and archive.org
9  */
11 loadGM({
12         "mwe-add_media_wizard" : "Add media wizard",
13         "mwe-media_search" : "Media search",
14         "rsd_box_layout" : "Box layout",
15         "rsd_list_layout" : "List layout",
16         "rsd_results_desc" : "Results",
17         "rsd_results_next" : "next",
18         "rsd_results_prev" : "previous",
19         "rsd_no_results" : "No search results for <b>$1<\/b>",
20         "mwe-upload_tab" : "Upload",
21         "rsd_layout" : "Layout:",
22         "rsd_resource_edit" : "Edit resource: $1",
23         "mwe-resource_description_page" : "Resource description page",
24         "rsd_local_resource_title" : "Local resource title",
25         "rsd_do_insert" : "Do insert",
26         "mwe-cc_title" : "Creative Commons",
27         "mwe-cc_by_title" : "Attribution",
28         "mwe-cc_nc_title" : "Noncommercial",
29         "mwe-cc_nd_title" : "No Derivative Works",
30         "mwe-cc_sa_title" : "Share Alike",
31         "mwe-cc_pd_title" : "Public Domain",
32         "mwe-unknown_license" : "Unknown license",
33         "mwe-no_import_by_url" : "This user or wiki <b>can not<\/b> import assets from remote URLs.<\/p><p>Do you need to login?<\/p><p>If permissions are set, you may have to enable $wgAllowCopyUploads (<a href=\"http:\/\/www.mediawiki.org\/wiki\/Manual:$wgAllowCopyUploads\">more information<\/a>).<\/p>",
34         "mwe-results_from" : "Results from <a href=\"$1\" target=\"_new\" >$2<\/a>",
35         "mwe-missing_desc_see_source" : "This asset is missing a description. Please see the [$1 orginal source] and help describe it.",
36         "rsd_config_error" : "Add media wizard configuration error: $1",
37         "mwe-your_recent_uploads" : "Your recent uploads",
38         "mwe-upload_a_file" : "Upload a new file",
39         "mwe-resource_page_desc" : "Resource page description:",
40         "mwe-edit_resource_desc" : "Edit wiki text resource description:",
41         "mwe-local_resource_title" : "Local resource title:",
42         "mwe-watch_this_page" : "Watch this page",
43         "mwe-do_import_resource" : "Import resource",
44         "mwe-update_preview" : "Update preview",
45         "mwe-cancel_import" : "Cancel import",
46         "mwe-importing_asset" : "Importing asset",
47         "mwe-preview_insert_resource" : "Preview insert of resource: $1"
48 });
50 var default_remote_search_options = {
51         'profile':'mediawiki_edit',
52         'target_container':null, //the div that will hold the search interface
53         //if using a modeal dialog (instead of target_container) how close to the edge of the window should we go:
54         'modal_edge_padding':'20px',
56         'target_invocation': null, //the button or link that will invoke the search interface
58         'default_provider_id':'all', //all or one of the content_providers ids
60         'caret_pos':null,
61         'local_wiki_api_url':null,
63         //can be 'api', 'form', 'autodetect', 'remote_link'
64         'import_url_mode': 'autodetect',
66         'target_title':null,
68         'target_textbox':null,
69         'target_render_area': null, //where output render should go:
70         'instance_name': null, //a globally accessible callback instance name
71         'default_query':null, //default search query
72         //specific to sequence profile
73         'p_seq':null,
74         'cFileNS':'File', //what is the cannonical namespace for images
75                                           //@@todo (should get that from the api or inpage vars)
77         'enable_upload_tab':true, // if we want to enable an uploads tab:
78         'upload_api_target'        : 'http://localhost/wiki_trunk/api.php' // can be local or the url of the upload api.
81 if(typeof wgServer == 'undefined')
82         wgServer = '';
83 if(typeof wgScriptPath == 'undefined')
84         wgScriptPath = '';
85 if(typeof stylepath == 'undefined')
86         stylepath = '';
89  *      base remoteSearch Driver interface
90  */
91 var remoteSearchDriver = function(iObj){
92         return this.init( iObj );
94 remoteSearchDriver.prototype = {
95         results_cleared:false,
96         //here we define the set of possible media content providers:
97         main_search_options:{
98                 'selprovider':{
99                         'title': 'Select Providers'
100                 },
101                 'advanced_search':{
102                         'title': 'Advanced Options'
103                 }
104         },
105         /*
106          * sets the default display item:
107          * can be any content_providers key or 'all'
108          */
109         disp_item : 'wiki_commons',
110         /** the default content providers list.
111          *
112          * (should be note that special tabs like "upload" and "combined" don't go into the content proviers list:
113          * @note do not use double underscore in content providers names (used for id lookup)
114          *
115          * @@todo we will want to load more per user-preference and per category lookup
116          */
117         content_providers:{
118                 /*content_providers documentation:
119                  *  @@todo we should move the bulk of the configuration to each file
120                  *
122                         @enabled: whether the search provider can be selected
123                         @checked: whether the search provider will show up as seleatable tab (todo: user prefrence)
124                         @d:        default: if the current cp should be displayed (only one should be the default)
125                         @title:   the title of the search provider
126                         @desc:     can use html... todo: need to localize
127                         @api_url: the url to query against given the library type:
128                         @lib:      the search library to use corresponding to the
129                                                 search object ie: 'mediaWiki' = new mediaWikiSearchSearch()
130                         @tab_img: the tab image (if set to false use title text)
131                                                 if === "ture" use standard location skin/images/{cp_id}_tab.png
132                                                 if === string use as url for image
134                         @linkback_icon default is: /wiki/skins/common/images/magnify-clip.png
136                         //domain insert: two modes: simple config or domain list:
137                         @local : if the content provider assets need to be imported or not.
138                         @local_domains : sets of domains for which the content is local
139                         //@@todo should query wgForeignFileRepos setting maybe interwikimap from the api
140                  */
141                 'this_wiki':{
142                         'enabled': 1,
143                         'checked': 1,
144                         'title'  : 'This Wiki',
145                         'desc'   : '(should be updated with the proper text) maybe import from some config value',
146                         'api_url':  ( wgServer && wgScriptPath )? wgServer + wgScriptPath+ '/api.php': null,
147                         'lib'    : 'mediaWiki',
148                         'local'  : true,
149                         'tab_img': false
150                 },
151                 'wiki_commons':{
152                         'enabled': 1,
153                         'checked': 1,
154                         'title'  :'Wikimedia Commons',
155                         'desc'   : 'Wikimedia Commons is a media file repository making available public domain '+
156                                          'and freely-licensed educational media content (images, sound and video clips) to all.',
157                         'homepage': 'http://commons.wikimedia.org/wiki/Main_Page',
158                         'api_url':'http://commons.wikimedia.org/w/api.php',
159                         'lib'   :'mediaWiki',
160                         'resource_prefix': 'WC_', //prefix on imported resources (not applicable if the repository is local)
162                         //list all the domains where commons is local?
163                         // probably should set this some other way by doing an api query
164                         // or by seeding this config when calling the remote search?
165                         'local_domains': ['wikimedia','wikipedia','wikibooks'],
166                         //specific to wiki commons config:
167                         'search_title':false, //disable title search
168                         //set up default range limit
169                         'offset'                        : 0,
170                         'limit'                         : 30,
171                         'tab_img':true
172                 },
173                 'archive_org':{
174                         'enabled':1,
175                         'checked':1,
176                         'title' : 'Archive.org',
177                         'desc'  : 'The Internet Archive, a digital library of cultural artifacts',
178                         'homepage':'http://www.archive.org/about/about.php',
180                         'api_url':'http://homeserver7.us.archive.org:8983/solr/select',
181                         'lib'   : 'archiveOrg',
182                         'local' : false,
183                         'resource_prefix': 'AO_',
184                         'tab_img':true
185                 },
186                 'metavid':{
187                         'enabled':1,
188                         'checked':1,
189                         'title' :'Metavid.org',
190                         'homepage':'http://metavid.org',
191                         'desc'  : 'Metavid hosts thousands of hours of US house and senate floor proceedings',
192                         'api_url':'http://metavid.org/w/index.php?title=Special:MvExportSearch',
193                         'lib'   : 'metavid',
194                         'local' :false,                 //if local set to true we can use local
195                         'resource_prefix': 'MV_', //what prefix to use on imported resources
197                         'local_domains': ['metavid'], // if the domain name contains metavid
198                                                                            // no need to import metavid content to metavid sites
200                         'stream_import_key': 'mv_ogg_low_quality', // which stream to import, could be mv_ogg_high_quality
201                                                                                                           //or flash stream, see ROE xml for keys
203                         'remote_embed_ext': false, //if running the remoteEmbed extension no need to copy local
204                                                                            //syntax will be [remoteEmbed:roe_url link title]
205                         'tab_img':true
206                 }
207         },
208         //define the licenses
209         // ... this will get complicated quick...
210         // (just look at complexity for creative commons without exessive "duplicate data")
211         // ie cc_by could be "by/3.0/us/" or "by/2.1/jp/" to infinitum...
212         // some complexity should be negated by license equivalances.
214         // but we will have to abstract into another class let content providers provide license urls
215         // and we have to clone the license object and allow local overrides
217         licenses:{
218                 //for now only support creative commons type licenses
219                 //used page: http://creativecommons.org/licenses/
220                 'cc':{
221                         'base_img_url':'http://upload.wikimedia.org/wikipedia/commons/thumb/',
222                         'base_license_url': 'http://creativecommons.org/licenses/',
223                         'licenses':{
224                                 'by': 'by/3.0/',
225                                 'by-sa': 'by-sa/3.0/',
226                                 'by-nc-nd': 'by-nc-nd/3.0/',
227                                 'by-nc': 'by-nc/3.0/',
228                                 'by-nd': 'by-nd/3.0/',
229                                 'by-nc-sa': 'by-nc-sa/3.0/',
230                                 'by-sa': 'by-nc/3.0',
231                                 'pd': 'publicdomain/'
232                         },
233                         'license_img':{
234                                 'by':{
235                                         'im':'1/11/Cc-by_new_white.svg/20px-Cc-by_new_white.svg.png'
236                                 },
237                                 'nc':{
238                                         'im':'2/2f/Cc-nc_white.svg/20px-Cc-nc_white.svg.png'
239                                 },
240                                 'nd':{
241                                         'im':'b/b3/Cc-nd_white.svg/20px-Cc-nd_white.svg.png'
242                                 },
243                                 'sa':{
244                                         'im':'d/df/Cc-sa_white.svg/20px-Cc-sa_white.svg.png'
245                                 },
246                                 'pd':{
247                                         'im':'5/51/Cc-pd-new_white.svg/20px-Cc-pd-new_white.svg.png'
248                                 }
249                         }
250                 }
251         },
252         /*
253          * getlicenseImgSet
254          * @param license_key  the license key (ie "by-sa" or "by-nc-sa" etc)
255          */
256         getlicenseImgSet: function( licenseObj ){
257                 //js_log('output images: '+ imgs);
258                 return '<div class="rsd_license" title="'+ licenseObj.title + '" >' +
259                                         '<a target="_new" href="'+ licenseObj.lurl +'" ' +
260                                         'title="' + licenseObj.title + '">'+
261                                                         licenseObj.img_html +
262                                         '</a>'+
263                                   '</div>';
264         },
265         /*
266          * getLicenceKeyFromKey
267          * @param license_key the key of the license (must be defined in: this.licenses.cc.licenses)
268          */
269         getLicenceFromKey:function( license_key , force_url){
270                 if( typeof( this.licenses.cc.licenses[ license_key ]) == 'undefined')
271                         return js_error('could not find:' + license_key);
272                 //set the current license pointer:
273                 var cl = this.licenses.cc;
274                 var title = gM('mwe-cc_title');
275                 var imgs = '';
276                 var license_set = license_key.split('-');
277                 for(var i=0;i < license_set.length; i++){
278                         lkey =   license_set[i];
279                         title += ' ' + gM( 'mwe-cc_' + lkey + '_title');
280                         imgs +='<img class="license_desc" width="20" src="' + cl.base_img_url +
281                                 cl.license_img[ lkey ].im + '">';
282                 }
283                 var url = (force_url) ? force_url : cl.base_license_url + cl.licenses[ license_key ];
284                 return {
285                         'title'         : title,
286                         'img_html'      : imgs,
287                         'key'            : license_key,
288                         'lurl'           : url
289                 };
290         },
291         /*
292          * getLicenceKeyFromUrl
293          * @param licence_url the url of the license
294          */
295         getLicenceFromUrl: function( license_url ){
296                 //js_log("getLicenceFromUrl::" + license_url);
297                 //first do a direct lookup check:
298                 for(var i in this.licenses.cc.licenses){
299                         var lkey = this.licenses.cc.licenses[i].split('/')[0];
300                         //guess by url trim
301                         if( parseUri(license_url).path.indexOf('/'+ lkey +'/') != -1){
302                                 return this.getLicenceFromKey( i , license_url);
303                         }
304                 }
305                 //could not find it return mwe-unknown_license
306                 return {
307                         'title'         : gM('mwe-unknown_license'),
308                         'img_html'      : '<span>' + gM('mwe-unknown_license') + '</span>',
309                         'lurl'          : license_url
310                 };
311         },
312         //some default layout values:
313         thumb_width              : 80,
314         image_edit_width        : 400,
315         video_edit_width        : 400,
316         insert_text_pos         : 0,      //insert at the start (will be overwritten by the user cursor pos)
317         result_display_mode : 'box', //box or list
319         cUpLoader                       : null,
320         cEdit                           : null,
321         dmodalCss                       : {},
323         init: function( iObj ){
324                 var _this = this;
325                 js_log('remoteSearchDriver:init');
326                 for( var i in default_remote_search_options ) {
327                         if( iObj[i]){
328                                 this[ i ] = iObj[i];
329                         }else{
330                                 this[ i ] = default_remote_search_options[i];
331                         }
332                 }
333                 //update the base text:
334                 if(_this.target_textbox)
335                    _this.getTexboxSelection();
337                 //set up the content provider config:
338                 if( this.cpconfig ){
339                         for(var cpc in cpconfig){
340                                 for(var cinx in this.cpconfig[cpc]){
341                                         if( this.content_providers[cpc] )
342                                                 this.content_providers[ cpc ][ cinx ] = this.cpconfig[cpc][ cinx];
343                                 }
344                         }
345                 }
347                 //make sure the selected cp has an api to query against (if its a content_provider
348                 if( this.content_providers[ this.disp_item ] &&
349                         !this.content_providers[ this.disp_item ].api_url  ){
350                         for(var inx in this.content_providers){
351                                 if( this.content_providers[ inx ].api_url ){
352                                         this.disp_item = inx;
353                                         break;
354                                 }
355                         }
356                 }
359                 //set up the default model config:
360                 this.dmodalCss = {
361                         'width':'auto',
362                         'height':'auto',
363                         'top'   : this.modal_edge_padding,
364                         'left'  : this.modal_edge_padding,
365                         'right' : this.modal_edge_padding,
366                         'bottom': this.modal_edge_padding
367                 }
370                 //set up the target invocation:
371                 if( $j(this.target_invocation).length==0 ){
372                         js_log("RemoteSearchDriver:: no target invocation provided (will have to run your own doInitDisplay() )");
373                 }else{
374                         if(this.target_invocation){
375                                 $j(this.target_invocation).css('cursor','pointer').attr('title', gM('mwe-add_media_wizard')).click(function(){
376                                         _this.doInitDisplay();
377                                 });
378                         }
379                 }
380         },
381         doInitDisplay:function(){
382                 var _this = this;
383                 //setup the parent container:
384                 this.init_modal();
385                 //fill in the html:
386                 this.init_interface_html();
387                 //bind actions:
388                 this.add_interface_bindings();
390                 //update the target bining to just unhide the dialog:
391                 $j(this.target_invocation).unbind().click(function(){
392                           js_log("re-open");
393                           //update the base text:
394                           if( _this.target_textbox )
395                                         _this.getTexboxSelection();
396                           //$j(_this.target_container).dialog("open");
397                           $j(_this.target_container).parents('.ui-dialog').fadeIn('slow');
398                  });
399         },
400         //gets the in and out points for insert position or grabs the selected text for search
401         getTexboxSelection:function(){
402                 //update the caretPos
403                 this.getCaretPos();
405                 //if we have highlighted text use that as the query: (would be fun to add context menu once we have rich editor in-place)
406                 if( this.caret_pos.selection )
407                         this.default_query = this.caret_pos.selection
409         },
410         getCaretPos:function(){
411                 this.caret_pos={};
412                 var txtarea = $j(this.target_textbox).get(0);
413                 var getTextCusorStartPos = function (o){
414                         if (o.createTextRange) {
415                                         var r = document.selection.createRange().duplicate()
416                                         r.moveEnd('character', o.value.length)
417                                         if (r.text == '') return o.value.length
418                                         return o.value.lastIndexOf(r.text)
419                                 } else return o.selectionStart
420                 }
421                 var getTextCusorEndPos = function (o){
422                         if (o.createTextRange) {
423                                 var r = document.selection.createRange().duplicate();
424                                 r.moveStart('character', -o.value.length);
425                                 return r.text.length;
426                         } else{
427                                 return o.selectionEnd
428                         }
429                 }
430                 this.caret_pos.s = getTextCusorStartPos( txtarea );
431                 this.caret_pos.e = getTextCusorEndPos( txtarea );
432                 this.caret_pos.text = txtarea.value;
433                 if(this.caret_pos.s && this.caret_pos.e &&
434                                 (this.caret_pos.s != this.caret_pos.e))
435                         this.caret_pos.selection = this.caret_pos.text.substring(this.caret_pos.s, this.caret_pos.e).replace(/ /g, '\xa0') || '\xa0';
437                 js_log('got caret_pos:' + this.caret_pos.s);
438                 //restore text value: (creating textRanges sometimes screws with the text content)
439                 $j(this.target_textbox).val(this.caret_pos.text);
440         },
441         init_modal:function(){
442                 js_log("init_modal");
443                 var _this = this;
444                 //add the parent target_container if not provided or missing
445                 if(!_this.target_container || $j(_this.target_container).length==0){
446                         $j('body').append('<div id="rsd_modal_target" style="position:absolute;top:30px;left:0px;bottom:33px;right:0px;" title="' + gM('mwe-add_media_wizard') + '" ></div>');
447                         _this.target_container = '#rsd_modal_target';
448                         //js_log('appended: #rsd_modal_target' + $j(_this.target_container).attr('id'));
449                         //js_log('added target id:' + $j(_this.target_container).attr('id'));
450                         //get layout
451                         //layout = _this.getMaxModalLayout();
452                         $j(_this.target_container).dialog({
453                                 bgiframe: true,
454                                 autoOpen: true,
455                                 modal: true,
456                                 buttons: {
457                                         '_': function() {
458                                                 //just a place-holder
459                                         }
460                                 },
461                                 close: function() {
462                                         js_log('closed modal');
463                                         $j(this).parents('.ui-dialog').fadeOut('slow');
464                                 }
465                         }).parent('.ui-dialog').css( _this.dmodalCss )
466                         //@@bind on resize to disable css dialog to update dmodelCss
467                         .bind('resizestart', function(event, ui) {
468                                  _this.dmodalCss = {};
469                                  $j(this).css({});
470                         })
471                         //bind on drag to remove preset style as well
472                         .bind('dragstart', function(event, ui) {
473                                  _this.dmodalCss = {};
474                                  $j(this).css({});
475                         });
476                         //update the child position: (some of this should be pushed up-stream via dialog config options
477                         $j(_this.target_container +'~ .ui-dialog-buttonpane').css({
478                                 'position':'absolute',
479                                 'left':'0px',
480                                 'right':'0px',
481                                 'bottom':'0px'
482                         });
483                         //re add cancel button
484                         _this.cancelClipEditCB();
485                         js_log('done setup of target_container: ' +
486                                 $j(_this.target_container +'~ .ui-dialog-buttonpane').length);
489                         /*var resizeTimer = false;
490                         $j(window).bind('resize', function() {
491                                 var adjustModal = function(){
492                                         var layout = _this.getMaxModalLayout();
493                                         //js_log("should adjust: h " + layout.h + ' width:' + layout.w);
494                                         $j(_this.target_container).dialog('option', 'width', layout.w);
495                                         $j(_this.target_container).dialog('option', 'height', layout.h);
496                                 }
497                                 if (resizeTimer) clearTimeout(resizeTimer);
498                                 var resizeTimer = setTimeout(adjustModal, 100);
499                         });*/
500                 }
501         },
502         getMaxModalLayout:function(border){
503                 if(!border)
504                         border = 50;
505                 //js_log('setting h:' + (parseInt( $j(document).height() ) - parseInt(border*2)) + ' from:' + $j(document).height() );
506                 return {
507                         'h': parseInt( $j(document).height() ) - parseInt(border*4),
508                         'w': parseInt( $j(document).width() ) - parseInt(border*2),
509                         'r': border,
510                         't': border
511                 }
512         },
513         //sets up the initial html interface
514         init_interface_html:function(){
515                 js_log('init_interface_html');
516                 var _this = this;
517                 var dq = (this.default_query)? this.default_query : '';
518                 js_log('f::init_interface_html');
520                 var o = '<div class="rsd_control_container" style="width:100%">' +
521                                         '<form id="rsd_form" action="javascript:return false;" method="GET">'+
522                                                 '<input class="ui-widget-content ui-corner-all" type="text" tabindex="1" value="' + dq + '" maxlength="512" id="rsd_q" name="rsd_q" '+
523                                                         'size="20" autocomplete="off"/> '+
524                                                 $j.btnHtml( gM('mwe-media_search'), 'rms_search_button', 'search') +
525                                         '</form>';
526                 //close up the control container:
527                 o+='</div>';
529                 //search provider tabs based on "checked" and "enabled" and "combined tab"
530                 o+='<div id="rsd_results_container" style="top:0px;bottom:0px;left:0px;right:0px;"></div>';
531                 $j(this.target_container).html( o );
533                 //add simple styles:
534                 $j(this.target_container + ' .rms_search_button').btnBind().click(function(){
535                         _this.runSearch();
536                 });
538                 //draw the tabs:
539                 this.drawTabs();
540                 //run the default search:
541                 if( this.default_query )
542                         this.runSearch();
543         },
544         add_interface_bindings:function(){
545                 var _this = this;
546                 js_log("f:add_interface_bindings:");
549                 $j('#mso_selprovider,#mso_selprovider_close').unbind().click(function(){
550                         if($j('#rsd_options_bar:hidden').length !=0 ){
551                                 $j('#rsd_options_bar').animate({
552                                         'height':'110px',
553                                         'opacity':1
554                                 }, "normal");
555                         }else{
556                                 $j('#rsd_options_bar').animate({
557                                         'height':'0px',
558                                         'opacity':0
559                                 }, "normal", function(){
560                                         $j(this).hide();
561                                 });
562                         }
563                 });
564                 //set form bindings
565                 $j('#rsd_form').unbind().submit(function(){
566                         _this.runSearch();
567                         //don't submit the form
568                         return false;
569                 });
570         },
571         doUploadInteface:function(){
572                 js_log("doUploadInteface::");
573                 var _this = this;
574                 //set it to loading:
575                 mv_set_loading('#tab-upload');
576                 //do things async to keep interface snapy
577                 setTimeout(function(){
578                         //do config variable reality checks:
579                         if( _this.upload_api_target == 'local' ){
580                                 if( ! _this.local_wiki_api_url ){
581                                         $j('#tab-upload').html( gM( 'rsd_config_error', 'missing_local_api_url' ) );
582                                         return false;
583                                 }else{
584                                         _this.upload_api_target = _this.local_wiki_api_url;
585                                 }
586                         }
587                         //make sure we have a url for the upload target:
588                         if(  parseUri( _this.upload_api_target ).host ==  _this.upload_api_target ){
589                                 $j('#tab-upload').html( gM('rsd_config_error', 'bad_api_url') );
590                                 return false;
591                         }
592                         //output the form
593                         //set the form action based on domain:
594                         if( parseUri( document.URL ).host == parseUri( _this.upload_api_target ).host ){
595                                 mvJsLoader.doLoad(['$j.fn.simpleUploadForm'],function(){
597                                         //get extened info about the file
598                                         var cp = _this.content_providers['this_wiki'];
599                                         //check for "this_wiki" enabled
600                                         if(!cp.enabled){
601                                                 $j('#tab-upload').html('error this_wiki not enabled (can\'t get uploaded file info)');
602                                                 return false;
603                                         }
605                                         //load  this_wiki search system to grab the rObj
606                                         _this.loadSearchLib(cp, function(){
607                                                 //do basic layout form on left upload "bin" on right
608                                                 $j('#tab-upload').html('<table>' +
609                                                 '<tr>' +
610                                                         '<td valign="top" style="width:350px; padding-right: 12px;">' +
611                                                                 '<h4>' + gM('mwe-upload_a_file') + '</h4>' +
612                                                                 '<div id="upload_form">' +
613                                                                         mv_get_loading_img() +
614                                                                 '</div>' +
615                                                         '</td>' +
616                                                         '<td valign="top" id="upload_bin_cnt">' +
617                                                         '<h4>' + gM('mwe-your_recent_uploads') + '</h4>' +
618                                                                 '<div id="upload_bin">' +
619                                                                         mv_get_loading_img() +
620                                                                 '</div>'+
621                                                         '</td>' +
622                                                 '</tr>' +
623                                                 '</table>');
626                                                 //fill in the user page:
627                                                 if(typeof wgUserName != 'undefined' && wgUserName){
628                                                         //load the upload bin with anything the current user has uploaded
629                                                         cp.sObj.getUserRecentUploads( wgUserName, function(){
630                                                                 _this.drawOutputResults();
631                                                         });
632                                                 }else{
633                                                         $j('#upload_bin_cnt').empty();
634                                                 }
636                                                 //deal with the api form upload form directly:
637                                                 $j('#upload_form').simpleUploadForm({
638                                                         "api_target" :  _this.upload_api_target ,
639                                                         "ondone_cb"     : function( resultData ){
640                                                                 var wTitle = resultData['filename'];    
641                                                                 //add a loading div
642                                                                 _this.addResourceEditLoader();
643                                                                 //@@note: we have most of what we need in resultData imageinfo
644                                                                 cp.sObj.addByTitle( wTitle, function( rObj ){                                                                   
645                                                                         //redraw (with added result if new)
646                                                                         _this.drawOutputResults();
647                                                                         //pull up recource editor:                                                                      
648                                                                         _this.resourceEdit( rObj, $j('#res_upload__' + rObj.id).get(0) );                                                                       
649                                                                 });
650                                                                 //return false to close progress window:
651                                                                 return false;
652                                                         }
653                                                 })
654                                         });
655                                 });
656                         }else{
657                                 //setup the proxy
658                                 js_log('do proxy:: ' + parseUri( _this.upload_api_target ).host);
659                                 $j('#tab-upload').html('proxy upload not yet ready');
660                         }
661                 },1);
662         },
663         runSearch: function(){
664                 js_log("f:runSearch::" + this.disp_item);
665                 //draw_direct_flag
666                 var draw_direct_flag = true;
667                 if( !this.content_providers[this.disp_item] ){
668                         //check if its the special upload tab case:
669                         if( this.disp_item == 'upload'){
670                                 this.doUploadInteface();
671                         }else{
672                                 js_log("can't run search for:" + this.disp_item);
673                         }
674                         return false;
675                 }
676                 cp = this.content_providers[this.disp_item];
678                 //check if we need to update:
679                 if( typeof cp.sObj != 'undefined' ){
680                         if(cp.sObj.last_query == $j('#rsd_q').val() && cp.sObj.last_offset == cp.offset){
681                                 js_log('last query is: ' + cp.sObj.last_query + ' matches: ' +  $j('#rsd_q').val() );
682                         }else{
683                                 js_log('last query is: ' + cp.sObj.last_query + ' not match: ' +  $j('#rsd_q').val() );
684                                 draw_direct_flag = false;
685                         }
686                 }else{
687                         draw_direct_flag = false;
688                 }
689                 if( !draw_direct_flag ){
690                         //set the content to loading while we do the search:
691                         $j('#tab-' + this.disp_item).html( mv_get_loading_img() );
693                         //make sure the search library is loaded and issue the search request
694                         this.getLibSearchResults( cp );
695                 }
696         },
697         //issue a api request & cache the result
698         //this check can be avoided by setting the this.import_url_mode = 'api' | 'form' | insted of 'autodetect' or 'none'
699         checkForCopyURLSupport:function ( callback ){
700                 var _this = this;
701                 js_log('checkForCopyURLSupport:: ');
702                 //see if we already have the import mode:
703                 if( this.import_url_mode != 'autodetect'){
704                         js_log('import mode: ' + _this.import_url_mode);
705                         callback();
706                 }
707                 //if we don't have the local wiki api defined we can't auto-detect use "link"
708                 if(!_this.local_wiki_api_url){
709                         js_log('import mode: remote link (no import_wiki_api_url)');
710                         _this.import_url_mode = 'remote_link';
711                         callback();
712                 }
713                 if( this.import_url_mode == 'autodetect' ){
714                         do_api_req( {
715                                 'data': { 'action':'paraminfo', 'modules':'upload' },
716                                 'url': _this.local_wiki_api_url
717                         }, function(data){
718                                 if( typeof data.paraminfo.modules[0].classname == 'undefined'){
719                                         //@@todo would be nice if API permission on: action=query&meta=userinfo&uiprop=rights
720                                         // upload_by_url property reflected if $wgAllowCopyUploads config value .. oh well.
721                                         $j.ajax({
722                                                 type: "GET",
723                                                 dataType: 'html',
724                                                 url: wgArticlePath.replace( '$1', 'Special:Upload' ), //@@todo may have problems in localized special pages
725                                                                                                                            //(could hit meta=siteinfo & specialpagealiases )
726                                                                                                                            // but might be overkill for now cuz we want to switch to new-upload branch soon.
727                                                 success: function( form_html ){
728                                                         if( form_html.indexOf( 'wpUploadFileURL' ) != -1){
729                                                                 _this.import_url_mode = 'form';
730                                                         }else{
731                                                                 _this.import_url_mode = 'none';
732                                                         }
733                                                         js_log('import mode: ' + _this.import_url_mode);
734                                                         callback();
735                                                 },
736                                                 error: function(){
737                                                         js_log('error in getting Special:Upload page');
738                                                         _this.import_url_mode = 'none';
740                                                         js_log('import mode: ' + _this.import_url_mode);
741                                                         callback();
742                                                 }
743                                         });
744                                 }else{
745                                         for( var i in data.paraminfo.modules[0].parameters ){
746                                                 var pname = data.paraminfo.modules[0].parameters[i].name;
747                                                 if( pname == 'url' ){
748                                                         js_log( 'Autodetect Upload Mode: api: copy by url:: ' );
749                                                         //check permission  too:
750                                                         _this.checkForCopyURLPermission(function( canCopyUrl ){
751                                                                 if(canCopyUrl){
752                                                                         _this.import_url_mode = 'api';
753                                                                         js_log('import mode: ' + _this.import_url_mode);
754                                                                         callback();
755                                                                 }else{
756                                                                         _this.import_url_mode = 'none';
757                                                                         js_log('import mode: ' + _this.import_url_mode);
758                                                                         callback();
759                                                                 }
760                                                         });
761                                                         break;
762                                                 }
763                                         }
764                                 }
765                         });
766                 }
767         },
768         /*
769          * checkForCopyURLPermission:
770          * not really nessesary the api request to upload will return apopprirate error if the user lacks permission. or $wgAllowCopyUploads is set to false
771          * (use this function if we want to issue a warning up front)
772          */
773         checkForCopyURLPermission:function( callback ){
774                 var _this = this;
775                 //do api check:
776                 do_api_req( {
777                                 'data':{ 'action' : 'query', 'meta' : 'userinfo', 'uiprop' : 'rights' },
778                                 'url': _this.local_wiki_api_url,
779                                 'userinfo' : true
780                 }, function(data){
781                         for( var i in data.query.userinfo.rights){
782                                 var right = data.query.userinfo.rights[i];
783                                 //js_log('checking: ' + right ) ;
784                                 if(right == 'upload_by_url'){
785                                         callback( true );
786                                         return true; //break out of the function
787                                 }
788                         }
789                         callback( false );
790                 });
791         },
792         getLibSearchResults:function( cp ){
793                 var _this = this;
795                 //first check if we should even run the search at all (can we import / insert into the page? )
796                 if( !this.checkRepoLocal( cp ) && this.import_url_mode == 'autodetect' ){
797                         //cp is not local check if we can support the import mode:
798                         this.checkForCopyURLSupport( function(){
799                                 _this.getLibSearchResults( cp );
800                         });
801                         return false;
802                 }else if( !this.checkRepoLocal( cp ) && this.import_url_mode == 'none'){
803                         if(  this.disp_item == 'combined' ){
804                                 //combined results are harder to error handle just ignore that repo
805                                 cp.sObj.loading = false;
806                         }else{
807                                 $j('#tab-' + this.disp_item).html( '<div style="padding:10px">'+ gM('mwe-no_import_by_url') +'</div>');
808                         }
809                         return false;
810                 }
811                 _this.loadSearchLib(cp, function(){
812                         //do search
813                         cp.sObj.getSearchResults();
814                         _this.checkResultsDone();
815                 });
816         },
817         loadSearchLib:function(cp, callback){
818                 var _this = this;
819                 //set up the library req:
820                 mvJsLoader.doLoad( [
821                         'baseRemoteSearch',
822                         cp.lib +'Search'
823                 ], function(){
824                         js_log("loaded lib:: " + cp.lib );
825                         //else we need to run the search:
826                         var iObj = {'cp':cp, 'rsd':_this};
827                         eval('cp.sObj = new '+cp.lib+'Search( iObj );');
828                         if(!cp.sObj){
829                                 js_log('Error: could not find search lib for ' + cp_id);
830                                 return false;
831                         }
833                         //inherit defaults if not set:
834                         cp.limit = (cp.limit) ? cp.limit : cp.sObj.limit;
835                         cp.offset = (cp.offset) ? cp.offset : cp.sObj.offset;
836                         callback();
837                 });
838         },
839         /* check for all the results to finish */
840         checkResultsDone: function(){
841                 //js_log('rsd:checkResultsDone');
842                 var _this = this;
843                 var loading_done = true;
845                 for(var cp_id in  this.content_providers){
846                         var cp = this.content_providers[ cp_id ];
847                         if(typeof cp['sObj'] != 'undefined'){
848                                 if( cp.sObj.loading )
849                                         loading_done=false;
850                         }
851                 }
852                 if( loading_done ){
853                         this.drawOutputResults();
854                 }else{
855                         //make sure the instance name is up-to-date refrence to _this;
856                         eval( _this.instance_name + ' = _this');
857                         setTimeout( _this.instance_name + '.checkResultsDone()', 50);
858                 }
859         },
860         drawTabs: function(){
861                 var _this = this;
862                 //add the tabs to the rsd_results container:
863                 var o='<div id="rsd_tabs_container" style="width:100%;">';
864                 var selected_tab = 0;
865                 var inx =0;
866                 o+= '<ul>';
867                         var tabc = '';
868                         for(var cp_id in  this.content_providers){
869                                         var cp = this.content_providers[cp_id];
870                                         if( cp.enabled && cp.checked && cp.api_url){
871                                                 //add selected default if set
872                                                 if( this.disp_item == cp_id)
873                                                         selected_tab=inx;
875                                                 o+='<li class="rsd_cp_tab">';
876                                                 o+='<a id="rsd_tab_' + cp_id + '" href="#tab-' + cp_id + '">';
877                                                         if(cp.tab_img === true){
878                                                                 o+='<img alt="' + cp.title +'" src="' + mv_skin_img_path + 'remote_cp/' + cp_id + '_tab.png">';
879                                                         }else{
880                                                                 o+= cp.title;
881                                                         }
882                                                 o+='</a>';
883                                                 o+='</li>';
884                                                 inx++;
885                                         }
886                                         tabc+='<div id="tab-'+ cp_id +'" class="rsd_results"/>';
888                         }
889                         //do an upload tab if enabled:
890                         if( this.enable_upload_tab ){
891                                 o+='<li class="rsd_cp_tab" ><a id="rsd_tab_upload" href="#tab-upload">' + gM('mwe-upload_tab') + '</a></li>';
892                                 tabc+='<div id="tab-upload" />';
893                                 if(this.disp_item == 'upload')
894                                         selected_tab = inx++;
895                         }
896                         o+='</ul>';
897                         //output the tab content containers:
898                         o+=tabc;
899                 o+='</div>'; //close tab container
901                 //output the respective results holders
902                 $j('#rsd_results_container').html(o);
903                 //setup bindings for tabs make them sortable: (@@todo remember order)
904                 js_log('selected tab is: ' + selected_tab);
905                 $j("#rsd_tabs_container").tabs({
906                         selected:selected_tab,
907                         select: function(event, ui) {
908                                 _this.selectTab( $j(ui.tab).attr('id').replace('rsd_tab_', '') );
909                         }
910                 //add sorting
911                 }).find(".ui-tabs-nav").sortable({axis:'x'});
913                 /*$j('.rsd_cp_tab').click(function(){
914                         _this.selectTab( $j(this).attr('id').replace(/rsd_tab_/, '') );
915                 });*/
917                 //setup key binding (no longer nessesary tabs provide this functionality)
918                 /*$j().keyup(function(e){
919                         js_log('keyup on : ' +e.which );
920                         //if escape pressed clear the interface:
921                         if(e.which == 27)
922                                 _this.closeAll();
923                 });*/
925         },
926         //resource title
927         getResourceFromTitle:function( rTitle , callback){
928                 var _this = this;
929                 reqObj={
930                         'action':'query',
931                         'titles': _this.cFileNS + ':' + rTitle
932                 };
933                 do_api_req( {
934                         'data':reqObj,
935                         'url':this.local_wiki_api_url
936                         }, function(data){
937                                 //@@todo propogate the rObj
938                                 var rObj = {};
939                         }
940                 );
941         },
942         //@@todo we could load the id with the content provider id to find the object faster...
943         getResourceFromId:function( rid ){
944                 js_log('getResourceFromId:' + rid );
945                 //strip out /res/ if preset:
946                 rid = rid.replace(/res_/, '');
947                 //js_log("looking at: " + rid);
948                 p = rid.split('__');
949                 var cp_id = p[0];
950                 var rid = p[1];
952                 if(cp_id == 'upload')
953                         cp_id = 'this_wiki';
955                 var cp = this.content_providers[cp_id];
956                 if(cp && cp['sObj'] && cp.sObj.resultsObj[rid]){
957                         return cp.sObj.resultsObj[rid];
958                 }
959                 js_log("ERROR: could not find " + rid);
960                 return false;
961         },
962         drawOutputResults: function(){
963                 js_log('f:drawOutputResults::' + this.disp_item);
964                 var _this = this;
965                 var o='';
967                 var cp_id = this.disp_item;
968                 var tab_target = '';
969                 if(this.disp_item == 'upload'){
970                         tab_target = '#upload_bin';
971                         var cp = this.content_providers['this_wiki'];
972                 }else{
973                         var cp = this.content_providers[this.disp_item];
974                         tab_target = '#tab-' + cp_id;
975                 }
976                 //empty the existing results:
977                 $j(tab_target).empty();
979                 //output the results bar / controls
980                 _this.setResultBarControl();
982                 var drawResultCount     =0;
984                 //output all the results for the current disp_item
985                 if( typeof cp['sObj'] != 'undefined' ){
986                         $j.each(cp.sObj.resultsObj, function(rInx, rItem){
987                                 if( _this.result_display_mode == 'box' ){
988                                         o+='<div id="mv_result_' + rInx + '" class="mv_clip_box_result" style="width:' +
989                                                         _this.thumb_width + 'px;height:'+ (_this.thumb_width-20) +'px;position:relative;">';
990                                                 //check for missing poster types for audio
991                                                 if( rItem.mime=='audio/ogg' && !rItem.poster ){
992                                                         rItem.poster = mv_skin_img_path + 'sound_music_icon-80.png';
993                                                 }
994                                                 //get a thumb with proper resolution transform if possible:
995                                                 o+='<img title="'+rItem.title+'" class="rsd_res_item" id="res_' + cp_id + '__' + rInx +
996                                                                 '" style="width:' + _this.thumb_width + 'px;" src="' +
997                                                                 cp.sObj.getImageTransform( rItem, {'width':_this.thumb_width } )
998                                                                 + '">';
999                                                 //add a linkback to resource page in upper right:
1000                                                 if( rItem.link )
1001                                                         o+='<a target="_new" style="position:absolute;top:0px;right:0px" title="' +
1002                                                                  gM('mwe-resource_description_page') +
1003                                                                 '" href="' + rItem.link + '"><img src="http://upload.wikimedia.org/wikipedia/commons/6/6b/Magnify-clip.png"></a>';
1004                                                 //add license icons if present
1005                                                 if( rItem.license )
1006                                                         o+= _this.getlicenseImgSet( rItem.license );
1007                                         o+='</div>';
1008                                 }else if(_this.result_display_mode == 'list'){
1009                                         o+='<div id="mv_result_' + rInx + '" class="mv_clip_list_result" style="width:90%">';
1010                                                 o+='<img title="'+rItem.title+'" class="rsd_res_item" id="res_' + cp_id + '__' + rInx +'" style="float:left;width:' +
1011                                                                  _this.thumb_width + 'px;" src="' +
1012                                                                  cp.sObj.getImageTransform( rItem, {'width':_this.thumb_width } )
1013                                                                   + '">';
1014                                                 //add license icons if present
1015                                                 if( rItem.license )
1016                                                         o+= _this.getlicenseImgSet( rItem.license );
1018                                                 o+= rItem.desc ;
1019                                         o+='<div style="clear:both" />';
1020                                         o+='</div>';
1021                                 }
1022                                 drawResultCount++;
1023                         });
1024                         js_log('append to: ' + '#tab-' + cp_id);
1025                         //put in the tab output (plus clear the output)
1026                         $j(tab_target).append( o + '<div style="clear:both"/>');
1027                 }
1029                 js_log( ' drawResultCount :: ' + drawResultCount + ' append: ' + $j('#rsd_q').val() );
1031                 //remove any old search res
1032                 $j('#rsd_no_search_res').remove();
1033                 if( drawResultCount == 0 )
1034                         $j('#tab-' + cp_id).append( '<span style="padding:10px">' + gM( 'rsd_no_results', $j('#rsd_q').val() ) + '</span>');
1036                 this.addResultBindings();
1037         },
1038         addResultBindings:function(){
1039                 var _this = this;
1040                 $j('.mv_clip_'+_this.result_display_mode+'_result').hover(function(){
1041                         $j(this).addClass('mv_clip_'+_this.result_display_mode+'_result_over');
1042                         //also set the animated image if avaliable
1043                         var res_id = $j(this).children('.rsd_res_item').attr('id');
1044                         var rObj = _this.getResourceFromId( res_id );
1045                         if( rObj.poster_ani )
1046                                 $j('#' + res_id ).attr('src', rObj.poster_ani);
1047                 },function(){
1048                         $j(this).removeClass('mv_clip_'+_this.result_display_mode+'_result_over');
1049                         var res_id = $j(this).children('.rsd_res_item').attr('id');
1050                         var rObj = _this.getResourceFromId( res_id );
1051                         //restore the original (non animated)
1052                         if( rObj.poster_ani )
1053                                 $j('#' + res_id ).attr('src', rObj.poster);
1054                 });
1055                 //resource click action: (bring up the resource editor)
1056                 $j('.rsd_res_item').unbind().click(function(){
1057                         var rObj = _this.getResourceFromId( $j(this).attr("id") );
1058                         _this.resourceEdit( rObj, this );
1059                 });
1060         },
1061         addResourceEditLoader:function(maxWidth, overflow_style){
1062                 var _this = this;
1063                 if(!maxWidth)maxWidth=400;
1064                 if(!overflow_style)overflow_style='overflow:auto;';
1065                 //remove any old instance:
1066                 $j( _this.target_container ).find('#rsd_resource_edit').remove();
1067                 //add the edit layout window with loading place holders
1068                 $j( _this.target_container ).append('<div id="rsd_resource_edit" '+
1069                         'style="position:absolute;top:0px;left:0px;bottom:5px;right:4px;background-color:#FFF;">' +
1070                                 '<div id="clip_edit_disp" style="position:absolute;' + overflow_style + 'width:100%;height:100%;padding:5px;'+
1071                                         'width:' + (maxWidth) + 'px;" >' +
1072                                                 mv_get_loading_img('position:absolute;top:30px;left:30px') +
1073                                 '</div>'+
1074                                 '<div id="clip_edit_ctrl" class="ui-widget ui-widget-content ui-corner-all" style="position:absolute;'+
1075                                         'left:' + ( maxWidth + 10 ) +'px;top:5px;bottom:10px;right:0px;overflow:auto;padding:5px;">'+
1076                                                 mv_get_loading_img() +
1077                                 '</div>'+
1078                 '</div>');
1079         },
1080         resourceEdit:function( rObj, rsdElement){
1081                 js_log('f:resourceEdit:' + rObj.title);
1082                 var _this = this;
1083                 //remove any existing resource edit interface:
1084                 $j('#rsd_resource_edit').remove();
1085                 //set the media type:
1086                 if(rObj.mime.indexOf('image')!=-1){
1087                         //set width to default image_edit_width
1088                         var maxWidth = _this.image_edit_width;
1089                         var mediaType = 'image';
1090                 }else if(rObj.mime.indexOf('audio')!=-1){
1091                         var maxWidth = _this.video_edit_width;
1092                         var mediaType = 'audio';
1093                 }else{
1094                         //set to default video size:
1095                         var maxWidth = _this.video_edit_width;
1096                         var mediaType = 'video';
1097                 }
1098                 //so that transcripts show ontop
1099                 var overflow_style = ( mediaType =='video' )?'':'overflow:auto;';
1100                 //append to the top level of model window:
1101                 _this.addResourceEditLoader(maxWidth, overflow_style);
1102                 //update add media wizard title:
1103                 $j( _this.target_container ).dialog( 'option', 'title', gM('mwe-add_media_wizard')+': '+ gM('rsd_resource_edit', rObj.title ) );
1104                 js_log('did append to: '+ _this.target_container );
1106                 $j('#rsd_resource_edit').css('opacity',0);
1108                 $j('#rsd_edit_img').remove();//remove any existing rsd_edit_img
1110                 //left side holds the image right size the controls /
1111                 $j(rsdElement).clone().attr('id', 'rsd_edit_img').appendTo('#clip_edit_disp').css({
1112                         'position':'absolute',
1113                         'top':'40%',
1114                         'left':'20%',
1115                         'cursor':'default',
1116                         'opacity':0
1117                 });
1120                 //try and keep aspect ratio for the thumbnail that we clicked:
1121                 var rh = $j('#rsd_edit_img').height();
1122                 var rw = $j('#rsd_edit_img').width(); 
1123                 if( rw > rh ){
1124                         var tRatio = rw / rh;
1125                 }else{
1126                         var tRatio = rh / rw;
1127                 }
1128                 if(     ! tRatio )
1129                         var tRatio = 1; //set ratio to 1 if the width of the thumbnail can't be found for some reason
1131                 js_log('set from ' +  $j('#rsd_edit_img').width()+'x'+ $j('#rsd_edit_img').height() + ' to init thumbimage to ' + maxWidth + ' x ' + parseInt( tRatio * maxWidth) );
1132                 //scale up image and to swap with high res version
1133                 $j('#rsd_edit_img').animate({
1134                         'opacity':1,
1135                         'top':'5px',
1136                         'left':'5px',
1137                         'width': maxWidth + 'px',
1138                         'height': parseInt( tRatio * maxWidth)  + 'px'
1139                 }, "slow"); // do it slow to give it a chance to finish loading the HQ version
1141                 if( mediaType == 'image' ){
1142                         _this.loadHQImg(rObj, {'width':maxWidth}, 'rsd_edit_img', function(){
1143                                 $j('.mv_loading_img').remove();
1144                         });
1145                 }
1146                 //also fade in the container:
1147                 $j('#rsd_resource_edit').animate({
1148                         'opacity':1,
1149                         'background-color':'#FFF',
1150                         'z-index':99
1151                 });
1152                 js_log('do load the media editor:');
1153                 //do load the media Editor
1154                 _this.doMediaEdit( rObj , mediaType );
1155         },
1156         loadHQImg:function(rObj, size, target_img_id, callback){
1157                 //get the HQ image url:
1158                 rObj.pSobj.getImageObj( rObj, size, function( imObj ){
1159                         rObj['edit_url'] = imObj.url;
1161                         js_log("edit url: " + rObj.edit_url);
1162                         //update the rObj
1163                         rObj['width'] = imObj.width;
1164                         rObj['height'] = imObj.height;
1166                         //see if we need to animate some transition
1167                         if( size.width != imObj.width ){
1168                                 js_log('loadHQImg:size mismatch: ' + size.width + ' != ' + imObj.width );
1169                                 //set the target id to the new size:
1170                                 $j('#'+target_img_id).animate( {
1171                                         'width':imObj.width + 'px',
1172                                         'height':imObj.height + 'px'
1173                                 });
1174                         }else{
1175                                 js_log('using req size: ' + imObj.width + 'x' + imObj.height);
1176                                 $j('#'+target_img_id).animate( {'width':imObj.width+'px', 'height' : imObj.height + 'px'});
1177                         }
1178                         //don't swap it in until its loaded:
1179                         var img = new Image();
1180                         // load the image image:
1181                         $j(img).load(function () {
1182                                          $j('#'+target_img_id).attr('src', rObj.edit_url );
1183                                          //let the caller know we are done and what size we ended up with:
1184                                          callback();
1185                                 }).error(function () {
1186                                         js_log("Error with:  " +  rObj.edit_url);
1187                                 }).attr('src', rObj.edit_url);
1188                         });
1189         },
1190         cancelClipEditCB:function(){
1191                 var _this = this;
1192                 var b_target =   _this.target_container + '~ .ui-dialog-buttonpane';
1193                 $j('#rsd_resource_edit').remove();
1194                 //restore the resource container:
1195                 $j('#rsd_results_container').show();
1196                 //restore the title:
1197                 $j( _this.target_container ).dialog( 'option', 'title', gM('mwe-add_media_wizard'));
1198                 js_log("should update: " + b_target + ' with: cancel');
1199                 //restore the buttons:
1200                 $j(b_target).html( $j.btnHtml( 'Cancel' , 'mv_cancel_rsd', 'close'))
1201                         .children('.mv_cancel_rsd')
1202                         .btnBind()
1203                         .click(function(){
1204                                 $j( _this.target_container).dialog('close');
1205                         })
1207         },
1208         /*set-up the control actions for clipEdit with relevent callbacks */
1209         getClipEditControlActions:function( cp ){
1210                 var _this = this;
1211                 var cConf= {};
1213                 cConf['insert'] = function(rObj){
1214                         _this.insertResource(rObj);
1215                 }
1216                 //if not directly inserting the resource is support a preview option:
1217                 if( _this.import_url_mode != 'remote_link'){
1218                         cConf['preview'] = function(rObj){
1219                                 _this.previewResource( rObj )
1220                         };
1221                 }
1222                 cConf['cancel'] = function(){
1223                         _this.cancelClipEditCB()
1224                 }
1225                 return cConf;
1226         },
1227         //loads the media editor:
1228         doMediaEdit:function( rObj , mediaType){
1229                 var _this = this;
1230                 var cp = rObj.pSobj.cp;
1231                 var mvClipInit = {
1232                                 'rObj':rObj, //the resource object
1233                                 'parent_ct'                     : 'rsd_modal_target',
1234                                 'clip_disp_ct'          : 'clip_edit_disp',
1235                                 'control_ct'            : 'clip_edit_ctrl',
1236                                 'media_type'            : mediaType,
1237                                 'p_rsdObj'                      : _this,
1238                                 'controlActionsCb'      : _this.getClipEditControlActions( cp )
1239                 };
1241                 var clibs = ['mvClipEdit'];
1242                 if( mediaType == 'image'){
1243                         //display the mvClipEdit obj once we are done loading:
1244                         mvJsLoader.doLoad( clibs, function(){
1245                                 //run the image clip tools
1246                                 _this.cEdit = new mvClipEdit( mvClipInit );
1247                         });
1248                 }
1249                 if( mediaType == 'video' || mediaType == 'audio'){
1250                         //get any additonal embedding helper meta data prior to doing the acutal embed
1251                         // normally this meta should be provided in the search result (but archive.org has a seperate query for more meida meta)
1252                         rObj.pSobj.getEmbedTimeMeta( rObj, function(){
1253                                 //make sure we have the embedVideo libs:
1254                                 mvJsLoader.embedVideoCheck( function(){
1255                                         js_log('append html: ' + rObj.pSobj.getEmbedHTML( rObj, {id:'embed_vid'}) );
1256                                         $j('#clip_edit_disp').html(
1257                                                 rObj.pSobj.getEmbedHTML( rObj, {id:'embed_vid'})
1258                                         );
1259                                         //rewrite by id
1260                                         rewrite_by_id('embed_vid',function(){
1261                                                 //grab any information that we got from the ROE xml or parsed from the media file
1262                                                 rObj.pSobj.getEmbedObjParsedInfo( rObj, 'embed_vid' );
1263                                                 //add the re-sizable to the doLoad request:
1264                                                 clibs.push( '$j.ui.resizable');
1265                                                 clibs.push( '$j.fn.hoverIntent');
1266                                                 mvJsLoader.doLoad(clibs, function(){
1267                                                         //make sure the rsd_edit_img is hidden:
1268                                                         $j('#rsd_edit_img').remove();
1269                                                         //run the image clip tools
1270                                                         _this.cEdit = new mvClipEdit( mvClipInit );
1271                                                 });
1272                                         });
1273                                 });
1274                         });
1275                 }
1276         },
1277         checkRepoLocal:function( cp ){
1278                 if( cp.local ){
1279                         return true;
1280                 }else{
1281                         //check if we can embed the content locally per a domain name check:
1282                         var local_host = parseUri( this.local_wiki_api_url ).host;
1283                         if( cp.local_domains ) {
1284                                 for(var i=0;i < cp.local_domains.length; i++){
1285                                         var ld = cp.local_domains[i];
1286                                          if( local_host.indexOf( ld ) != -1)
1287                                                  return true;
1288                                 }
1289                         }
1290                         return false;
1291                 }
1292         },
1293         checkImportResource:function( rObj, cir_callback){
1294                 //@@todo get the localized File/Image namespace name or do a general {NS}:Title
1295                 var cp = rObj.pSobj.cp;
1296                 var _this = this;
1298                 //update base target_resource_title:
1299                 rObj.target_resource_title = rObj.titleKey.replace(/File:|Image:/,'')
1301                 //check if local repository
1302                 //or if import mode if just "linking" (we should alaredy have the 'url'
1304                 if( this.checkRepoLocal( cp ) || this.import_url_mode == 'remote_link'){
1305                         //local repo jump directly to check Import Resource callback:
1306                          cir_callback( rObj );
1307                 }else{
1308                         //update target_resource_title with resource repository prefix:
1309                         rObj.target_resource_title = cp.resource_prefix + rObj.target_resource_title;
1311                         //check if the resource is not already on this wiki
1312                         reqObj={
1313                                 'action':'query',
1314                                 'titles': _this.cFileNS + ':' + rObj.target_resource_title,
1315                                 'prop'          : 'imageinfo',
1316                                 'iiprop'        : 'url',
1317                                 'iiurlwidth': '400'
1318                         };
1320                         do_api_req( {
1321                                 'data':reqObj,
1322                                 'url':this.local_wiki_api_url
1323                                 }, function(data){
1324                                         var found_title = false;
1325                                         for(var i in data.query.pages){
1326                                                 if( i != '-1' && i != '-2' ){
1327                                                         js_log('found title: ' + i + ':' +  data.query.pages[i]['title']);
1328                                                         found_title=data.query.pages[i]['title'];
1329                                                         //update to local src
1330                                                         rObj.local_src = data.query.pages[i]['imageinfo'][0].url;
1331                                                         //@@todo maybe  update poster too?
1332                                                         rObj.local_poster = data.query.pages[i]['imageinfo'][0].thumburl;
1333                                                 }
1334                                         }
1335                                         if( found_title ){
1336                                                 js_log("checkImportResource:found title:" + found_title);
1337                                                 //resource is already present (or resource with same name is already present)
1338                                                 rObj.target_resource_title = found_title.replace(/File:|Image:/,'');
1339                                                 cir_callback( rObj );
1340                                         }else{
1341                                                 js_log("resource not present: update:"+ _this.cFileNS + ':' + rObj.target_resource_title);
1343                                                 //update the rObj with import info
1344                                                 rObj.pSobj.updateDataForImport( rObj );
1346                                                 //setup the resource description from resource description:
1347                                                 var wt = '{{Information '+"\n";
1349                                                 if( rObj.desc ){
1350                                                         wt += '|Description= ' + rObj.desc + "\n";
1351                                                 }else{
1352                                                         wt += '|Description= ' + gM('mwe-missing_desc_see_source', rObj.link ) + "\n";
1353                                                 }
1355                                                 //output search specific info
1356                                                 wt+='|Source=' + rObj.pSobj.getImportResourceDescWiki( rObj ) + "\n";
1358                                                 if( rObj.author )
1359                                                         wt+='|Author=' + rObj.author +"\n";
1361                                                 if( rObj.date )
1362                                                         wt+='|Date=' + rObj.date +"\n";
1364                                                 //add the Permision info:
1365                                                 wt+='|Permission=' + rObj.pSobj.getPermissionWikiTag( rObj ) +"\n";
1367                                                 if( rObj.other_versions )
1368                                                         wt+='|other_versions=' + rObj.other_versions + "\n";
1370                                                 wt+='}}';
1372                                                 //get any extra categories or helpful links
1373                                                 wt+= rObj.pSobj.getExtraResourceDescWiki( rObj );
1376                                                 $j('#rsd_resource_import').remove();//remove any old resource imports
1378                                                 //@@ show user dialog to import the resource
1379                                                 $j( _this.target_container ).append('<div id="rsd_resource_import" '+
1380                                                 'class="ui-state-highlight ui-widget-content ui-state-error" ' +
1381                                                 'style="position:absolute;top:50px;left:50px;right:50px;bottom:50px;z-index:5">' +
1382                                                         '<h3 style="color:red">Resource: <span style="color:black">' + rObj.title + '</span> needs to be imported</h3>'+
1383                                                                 '<div id="rsd_preview_import_container" style="position:absolute;width:50%;bottom:0px;left:0px;overflow:auto;top:30px;">' +
1384                                                                         rObj.pSobj.getEmbedHTML( rObj, {'id': _this.target_container + '_rsd_pv_vid', 'max_height':'200','only_poster':true} )+ //get embedHTML with small thumb:
1385                                                                         '<br style="clear both">'+
1386                                                                         '<strong>'+gM('mwe-resource_page_desc') +'</strong>'+
1387                                                                         '<div id="rsd_import_desc" syle="display:inline;">'+
1388                                                                                 mv_get_loading_img('position:absolute;top:5px;left:5px') +
1389                                                                         '</div>'+
1390                                                                 '</div>'+
1391                                                                 '<div id="rds_edit_import_container" style="position:absolute;left:50%;' +
1392                                                                         'bottom:0px;top:30px;right:0px;overflow:auto;">'+
1393                                                                         '<strong>' + gM('mwe-local_resource_title') + '</strong><br>'+
1394                                                                         '<input type="text" size="30" value="' + rObj.target_resource_title + '" readonly="true"><br>'+
1395                                                                         '<strong>' + gM('mwe-edit_resource_desc') + '</strong>' +
1396                                                                         '<textarea id="rsd_import_ta" id="mv_img_desc" style="width:90%;" rows="8" cols="50">' +
1397                                                                                 wt +
1398                                                                         '</textarea><br>' +
1399                                                                         '<input type="checkbox" value="true" id="wpWatchthis" name="wpWatchthis" tabindex="7"/>' +
1400                                                                         '<label for="wpWatchthis">'+gM('mwe-watch_this_page')+'</label><br><br><br>' +
1402                                                                         $j.btnHtml(gM('mwe-do_import_resource'), 'rsd_import_doimport', 'check' ) + ' ' +
1404                                                                         $j.btnHtml(gM('mwe-update_preview'), 'rsd_import_apreview', 'refresh' ) + '<div style="clear:both;height:20px;"/>' +
1406                                                                         $j.btnHtml(gM('mwe-cancel_import'), 'rsd_import_acancel', 'close' ) + ' ' +
1408                                                                 '</div>'+
1409                                                                 //output the rendered and non-renderd version of description for easy swiching:
1410                                                 '</div>');
1411                                                 //add hover:
1412                                                 //update video tag
1413                                                 rewrite_by_id(_this.target_container + '_rsd_pv_vid');
1414                                                 //load the preview text:
1415                                                 _this.getParsedWikiText( wt, _this.cFileNS +':'+ rObj.target_resource_title, function( o ){
1416                                                         $j('#rsd_import_desc').html(o);
1417                                                 });
1418                                                 //add bidings:
1419                                                 $j( _this.target_container + ' .rsd_import_apreview').btnBind().click(function(){
1420                                                         /*$j('#rsd_import_desc').show().html(
1421                                                                 mv_get_loading_img()
1422                                                         );*/
1423                                                         //load the preview text:
1424                                                         _this.getParsedWikiText( $j('#rsd_import_ta').val(), _this.cFileNS +':'+ rObj.target_resource_title, function( o ){
1425                                                                 js_log('got updated preivew: ');
1426                                                                 $j('#rsd_import_desc').html(o);
1427                                                         });
1428                                                 });
1429                                                 $j(_this.target_container + ' .rsd_import_doimport').btnBind().click(function(){
1430                                                         //check import mode:
1431                                                         if(_this.import_url_mode=='form'){
1432                                                                 _this.doImportSpecialPage( rObj, cir_callback );
1433                                                         }else if( _this.import_url_mode=='api'){
1434                                                                 _this.doImportAPI( rObj , cir_callback);
1435                                                         }else{
1436                                                                 js_log("Error: import mode is not form or API (can not copy asset)");
1437                                                         }
1438                                                 });
1439                                                 $j( _this.target_container + ' .rsd_import_acancel').btnBind().click(function(){
1440                                                         $j('#rsd_resource_import').fadeOut("fast",function(){
1441                                                                 $j(this).remove();
1442                                                         });
1443                                                 });
1444                                         }
1445                                 }
1446                         );
1447                 }
1448         },
1449         doImportAPI:function(rObj, cir_callback){
1450                 var _this = this;
1451                 //baseUploadInterface
1452                 mvJsLoader.doLoad([
1453                         'mvBaseUploadInterface',
1454                         '$j.ui.progressbar'
1455                 ],function(){
1456                         //initicate a download similar to url copy:
1457                         myUp = new mvBaseUploadInterface({
1458                                 'api_url' : _this.local_wiki_api_url,
1459                                 'done_upload_cb':function(){
1460                                         js_log('doImportAPI:: run callback::' );
1461                                         //we have finished the upload:
1462                                 
1463                                         //close up the rsd_resource_import
1464                                         $j('#rsd_resource_import').remove();
1465                                         //return the parent callback:
1466                                         return cir_callback();                                  
1467                                 }
1468                         });
1469                         //set the edit token if we have it handy
1470                         _this.getEditToken(function( token ){
1471                                 myUp.etoken = token;
1472                                 myUp.doHttpUpload({
1473                                         'url'       : rObj.src,
1474                                         'filename'  : rObj.target_resource_title,
1475                                         'comment'   : $j('#rsd_import_ta').val()
1476                                 });
1477                         })
1480                 });
1481         },
1482         getEditToken:function(callback){
1483                 //first try the page form:
1484                 var etoken = $j("input[name='wpEditToken']").val();
1485                 if(etoken){
1486                         callback( etoken );
1487                         return ;
1488                 }
1489                 //@@todo try to load over ajax if( _this.local_wiki_api_url ) is set
1490                 // (your on the api domain but are inserting from a normal page view)
1491                 if( _this.local_wiki_api_url){
1492                         get_mw_token(null, _this.local_wiki_api_url, function(token){
1493                                         callback( token );
1494                         })
1495                 }
1496                 callback(false);
1497                 return false;
1498         },
1499         /**
1500          * doImportSpecialPage
1501          * can be depricated once we support upload api support is widespred.
1502          */
1503         doImportSpecialPage:function(rObj, cir_callback){
1504                 var _this = this;
1505                  //get an edittoken:
1506                 do_api_req( {
1507                         'data': {       'action':'query',
1508                                                 'prop':'info',
1509                                                 'intoken':'edit',
1510                                                 'titles': rObj.titleKey
1511                                         },
1512                         'url':_this.local_wiki_api_url
1513                         }, function(data){
1514                                 //could recheck if it has been created in the mean time
1515                                 if( data.query.pages[-1] ){
1516                                         var editToken = data.query.pages[-1]['edittoken'];
1517                                         if(!editToken){
1518                                                 //@@todo give an ajax login or be more friendly in some way:
1519                                                 js_error("You don't have permission to upload (are you logged in?)");
1520                                                 //remove top level:
1521                                                 $j('#modalbox').fadeOut("normal",function(){
1522                                                         $j(this).remove();
1523                                                         $j('#mv_overlay').remove();
1524                                                 });
1525                                         }else{
1526                                                 //not sure if we can do remote url uploads (so just do a local post)
1527                                                 js_log('got token for new page:' +editToken);
1528                                                 var postVars = {
1529                                                         'wpSourceType'                  :'web',
1530                                                         'wpUploadFileURL'               : rObj.src,
1531                                                         'wpDestFile'                    : rObj.target_resource_title,
1532                                                         'wpUploadDescription'   : $j('#rsd_import_ta').val(),
1533                                                         'wpWatchthis'                   : $j('#wpWatchthis').val(),
1534                                                         'wpUpload'                              : 'Upload file'
1535                                                 }
1536                                                 //set to uploading:
1537                                                 $j('#rsd_resource_import').append('<div id="rsd_import_progress"'+
1538                                                         'style="position:absolute;top:0px;'+
1539                                                                 'left:0px;width:100%;height:100%;'+
1540                                                                 'z-index:5;background:#FFF;overflow:auto;">'+
1541                                                                         '<div style="position:absolute;left:30%;right:30%"><h3>'+gM('mwe-importing_asset')+'</h3><br>' +
1542                                                                                 mv_get_loading_img('','mv_loading_bar_img') +
1543                                                                         '</div>'+
1544                                                         '</div>'
1545                                                 );
1546                                                 $j.post(wgArticlePath.replace(/\$1/,'Special:Upload'),
1547                                                         postVars,
1548                                                         function(data){
1549                                                                 //@@todo this will be replaced once we add upload image support to the api.
1551                                                                 //very basic test to see if we got passed to the image page:
1552                                                                 //@@todo more normalization stuff
1553                                                                 var sstring ='var wgPageName = "' + _this.cFileNS + ':' + rObj.target_resource_title.replace(/ /g,'_') +'"';
1554                                                                 if(data.indexOf( sstring ) !=-1){
1555                                                                         js_log('found: ' + sstring);
1556                                                                         $j('#rsd_resource_import').remove();
1557                                                                         cir_callback( rObj );
1558                                                                 }else{
1559                                                                         js_log("Error or warning: (did not find: \"" + sstring + ' in output' );
1560                                                                         pos_etitle = '<h1 class="firstHeading">';
1561                                                                         var error_txt = form_txt = '';
1562                                                                         var res = grabWikiFormError( data );
1564                                                                         if( res.error_txt )
1565                                                                                 error_txt = res.error_txt;
1567                                                                         if( res.form_txt )
1568                                                                                 form_txt = res.form_txt;
1570                                                                         js_log( 'error text is: ' + error_txt );
1571                                                                         $j( '#rsd_resource_import' ).html( '<h3>Error</h3>' + error_txt + '<br>' + form_txt +
1572                                                                                         '<br>'+
1573                                                                                 '<a href="#" id="rsd_import_error" >' + gM('mwe-cancel_import') + '</a>'
1574                                                                         );
1575                                                                         //set up cancel action:
1576                                                                         $j('#rsd_import_error').click(function(){
1577                                                                                 $j('#rsd_resource_import').remove();
1578                                                                         });
1579                                                                 }
1580                                                         }
1581                                                 );
1582                                         }
1583                                 }
1584                         }
1585                 );
1586         },
1587         previewResource:function( rObj ){
1588                 var _this = this;
1589                 this.checkImportResource( rObj, function(){
1590                         //put another window ontop:
1591                         $j( _this.target_container ).append('<div id="rsd_preview_display"' +
1592                                         'style="position:absolute;overflow:hidden;z-index:4;top:0px;bottom:75px;right:0px;left:0px;background-color:#FFF;">' +
1593                                                 mv_get_loading_img('top:30px;left:30px') +
1594                                         '</div>');
1596                         var bPlaneTarget = _this.target_container +'~ .ui-dialog-buttonpane';
1597                         var pTitle = $j( _this.target_container ).dialog('option', 'title');
1599                         //update title:
1600                         $j( _this.target_container ).dialog('option', 'title', gM('mwe-preview_insert_resource', rObj.title) );
1602                         //update buttons preview:
1603                         $j(bPlaneTarget).html( $j.btnHtml( gM('rsd_do_insert'), 'preview_do_insert', 'check') + ' ' )
1604                                 .children('.preview_do_insert')
1605                                 .click(function(){
1606                                         _this.insertResource( rObj );
1607                                 });
1608                         //update cancel button
1609                         $j(bPlaneTarget).append('<a href="#" class="preview_close">Do More Modification</a>')
1610                                 .children('.preview_close')
1611                                 .click(function(){
1612                                         $j('#rsd_preview_display').remove();
1613                                         //restore title:
1614                                         $j( _this.target_container ).dialog('option', 'title', pTitle);
1615                                         //restore buttons (from the clipEdit object::)
1616                                         _this.cEdit.updateInsertControlActions();
1617                                 });
1619                         //update the preview_wtext
1620                         _this.updatePreviewText( rObj );
1621                         _this.getParsedWikiText(_this.preview_wtext, _this.target_title,
1622                                 function(phtml){
1623                                         $j('#rsd_preview_display').html( phtml );
1624                                         //update the display of video tag items (if any)
1625                                         mwdomReady(true);
1626                                 }
1627                         );
1628                 });
1629         },
1630         updatePreviewText:function( rObj ){
1631                 var _this = this;
1633                 if( _this.import_url_mode == 'remote_link' ){
1634                         _this.cur_embed_code = rObj.pSobj.getEmbedHTML(rObj);
1635                 }else{
1636                         _this.cur_embed_code = rObj.pSobj.getEmbedWikiCode( rObj );
1637                 }
1639                 //insert at start if textInput cursor has not been set (ie == length)
1640                 if( _this.caret_pos &&  _this.caret_pos.text){
1641                         if( _this.caret_pos.text.length == _this.caret_pos.s)
1642                                 _this.caret_pos.s=0;
1643                         _this.preview_wtext = _this.caret_pos.text.substring(0, _this.caret_pos.s) +
1644                                                                         _this.cur_embed_code +
1645                                                                    _this.caret_pos.text.substring( _this.caret_pos.s );
1646                 }else{
1647                    _this.preview_wtext =  $j(_this.target_textbox).val() +  _this.cur_embed_code;
1648                 }
1649                 //check for missing </refrences>
1650                 if( _this.preview_wtext.indexOf('<references/>') ==-1 &&  _this.preview_wtext.indexOf('<ref>') != -1 )
1651                          _this.preview_wtext =  _this.preview_wtext + '<references/>';
1652         },
1653         getParsedWikiText:function( wikitext, title,  callback ){
1654                 do_api_req( {
1655                         'data':{'action':'parse',
1656                                         'text':wikitext
1657                                    },
1658                         'url':this.local_wiki_api_url
1659                         },function(data){
1660                                 callback( data.parse.text['*'] );
1661                         }
1662                 );
1663         },
1664         insertResource:function( rObj){
1665                 js_log('insertResource: ' + rObj.title);
1666                 var _this = this
1667                 //dobule check that the resource is present:
1668                 this.checkImportResource( rObj, function(){
1669                         _this.updatePreviewText( rObj );
1670                         $j(_this.target_textbox).val( _this.preview_wtext );
1672                         //update the render area (if present)
1673                         if(_this.target_render_area && _this.cur_embed_code){
1674                                  //output with some padding:
1675                                  $j(_this.target_render_area).append( _this.cur_embed_code + '<div style="clear:both;height:10px">')
1676                                  //update if its video or audio:
1677                                  if( rObj.mime.indexOf('audio')!=-1 ||
1678                                          rObj.mime.indexOf('video')!=-1 ||
1679                                          rObj.mime.indexOf('/ogg') !=-1){
1680                                          mvJsLoader.embedVideoCheck(function(){
1681                                                 mv_video_embed();
1682                                          });
1683                                  }
1684                         }
1685                         _this.closeAll();
1686                 });
1687         },
1688         closeAll:function(){
1689                  var _this = this;
1690                  js_log("close all:: "  + _this.target_container);
1691                  _this.cancelClipEditCB();
1692                  $j(_this.target_container).dialog('close');
1693         },
1694         setResultBarControl:function( ){
1695                 var _this = this;
1696                 var box_dark_url         = mv_skin_img_path + 'box_layout_icon_dark.png';
1697                 var box_light_url        = mv_skin_img_path + 'box_layout_icon.png';
1698                 var list_dark_url        = mv_skin_img_path + 'list_layout_icon_dark.png';
1699                 var list_light_url       = mv_skin_img_path + 'list_layout_icon.png';
1701                 var about_desc ='';
1702                 if( this.content_providers[this.disp_item] ){
1703                         var cp = this.content_providers[this.disp_item];
1704                         about_desc ='<span style="position:relative;top:0px;font-style:italic;">' +
1705                                         '<i>' + gM('mwe-results_from', [cp.homepage, cp.title]) + '</i></span>';
1706                         $j('#tab-'+this.disp_item).append( '<div id="rds_results_bar">'+
1707                                 '<span style="float:left;top:0px;font-style:italic;">'+
1708                                         gM('rsd_layout')+' '+
1709                                         '<img id="msc_box_layout" ' +
1710                                                 'title = "' + gM('rsd_box_layout') + '" '+
1711                                                 'src = "' +  ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) + '" ' +
1712                                                 'style="width:20px;height:20px;cursor:pointer;"> ' +
1713                                         '<img id="msc_list_layout" '+
1714                                                 'title = "' + gM('rsd_list_layout') + '" '+
1715                                                 'src = "' +  ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) + '" '+
1716                                                 'style="width:20px;height:20px;cursor:pointer;">'+
1717                                         about_desc +
1718                                 '</span>'+
1719                                 '<span id="rsd_paging_ctrl" style="float:right;"></span>'+
1720                                 '</div>'
1721                         );
1722                         //get paging with bindings:
1723                         this.getPaging('#rsd_paging_ctrl');
1725                         $j('#msc_box_layout').hover(function(){
1726                                 $j(this).attr("src", box_dark_url );
1727                         }, function(){
1728                                 $j(this).attr("src",  ( (_this.result_display_mode=='box')?box_dark_url:box_light_url ) );
1729                         }).click(function(){
1730                                 $j(this).attr("src", box_dark_url);
1731                                 $j('#msc_list_layout').attr("src", list_light_url);
1732                                 _this.setDispMode('box');
1733                         });
1735                         $j('#msc_list_layout').hover(function(){
1736                                 $j(this).attr("src", list_dark_url);
1737                         }, function(){
1738                                 $j(this).attr("src", ( (_this.result_display_mode=='list')?list_dark_url:list_light_url ) );
1739                         }).click(function(){
1740                                 $j(this).attr("src", list_dark_url);
1741                                 $j('#msc_box_layout').attr("src", box_light_url);
1742                                 _this.setDispMode('list');
1743                         });
1744                 }
1745         },
1746         getPaging:function(target){
1747                 var _this = this;
1748                 var cp_id = this.disp_item;
1749                 var cp = this.content_providers[ this.disp_item ];
1750                 //js_log('getPaging:'+ cp_id + ' len: ' + cp.sObj.num_results);
1751                 var to_num = ( cp.limit > cp.sObj.num_results )?
1752                                                 (cp.offset + cp.sObj.num_results):
1753                                                 (cp.offset + cp.limit);
1754                 var out = gM('rsd_results_desc') + ' ' +  (cp.offset+1) + ' to ' + to_num;
1755                 //check if we have more results (next prev link)
1756                 if(  cp.offset >=  cp.limit )
1757                         out+=' <a href="#" id="rsd_pprev">' + gM('rsd_results_prev') + ' ' + cp.limit + '</a>';
1759                 if( cp.sObj.more_results )
1760                         out+=' <a href="#" id="rsd_pnext">' + gM('rsd_results_next') + ' ' + cp.limit + '</a>';
1762                 $j(target).html(out);
1763                 //set bindings
1764                 $j('#rsd_pnext').click(function(){
1765                         cp.offset += cp.limit;
1766                         _this.runSearch();
1767                 });
1768                 $j('#rsd_pprev').click(function(){
1769                         cp.offset -= cp.limit;
1770                         if(cp.offset<0)
1771                                 cp.offset=0;
1772                         _this.runSearch();
1773                 });
1775                 return;
1777         },
1778         selectTab:function( selected_cp_id ){
1779                 js_log('select tab: ' + selected_cp_id);
1780                 this.disp_item = selected_cp_id;
1781                 if( this.disp_item == 'upload' ){
1782                         this.doUploadInteface();
1783                 }else{
1784                         //update the search results:
1785                         this.runSearch();
1786                 }
1787         },
1788         setDispMode:function(mode){
1789                 js_log('setDispMode:' + mode);
1790                 this.result_display_mode=mode;
1791                 //run /update search display:
1792                 this.drawOutputResults();
1793         }