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