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