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