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