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