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