Quellcode durchsuchen

Adding jquery multiple uploader script for documents see #2784 (need to be more preatty) the pbar.ani.gif is also very big 250kb need to be replaced

Julio Montoya vor 14 Jahren
Ursprung
Commit
9fb4257162

+ 60 - 279
main/document/upload.php

@@ -40,14 +40,13 @@ $language_file = array('document','gradebook');
 require_once '../inc/global.inc.php';
 
 // Including additional libraries
-require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
 require_once api_get_path(LIBRARY_PATH).'document.lib.php';
 require_once api_get_path(LIBRARY_PATH).'specific_fields_manager.lib.php';
 require_once api_get_path(LIBRARY_PATH).'formvalidator/FormValidator.class.php';
 require_once 'document.inc.php';
 
 // Adding extra javascript to the form
-$htmlHeadXtra[] = '<script src="../inc/lib/javascript/jquery.js" type="text/javascript" language="javascript"></script>';
+$htmlHeadXtra[] = api_get_jquery_libraries_js(array('jquery-ui', 'jquery-upload'));
 $htmlHeadXtra[] = '<script type="text/javascript">
 
 function check_unzip() {
@@ -71,94 +70,35 @@ function advanced_parameters() {
 			document.getElementById(\'img_plus_and_minus\').innerHTML=\'&nbsp;<img style="vertical-align:middle;" src="../img/div_show.gif" alt="" />&nbsp;'.get_lang('AdvancedParameters').'\';
 			}
 	}
-
 function setFocus(){
 	$("#title_file").focus();
 	}
 	$(document).ready(function () {
  	 setFocus();
-	});
+	});	
 </script>';
 
-/**
- * Obtains the text inside the file with the right parser
- */
-function get_text_content($doc_path, $doc_mime) {
-	// TODO: review w$ compatibility
-
-	// Use usual exec output lines array to store stdout instead of a temp file
-	// because we need to store it at RAM anyway before index on DokeosIndexer object
-	$ret_val = null;
-	switch ($doc_mime) {
-		case 'text/plain':
-			$handle = fopen($doc_path, 'r');
-			$output = array(fread($handle, filesize($doc_path)));
-			fclose($handle);
-			break;
-		case 'application/pdf':
-			exec("pdftotext $doc_path -", $output, $ret_val);
-			break;
-		case 'application/postscript':
-			$temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
-			exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
-			if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
-				return false;
-			}
-			exec("pdftotext $temp_file -", $output, $ret_val);
-			unlink($temp_file);
-			//var_dump($output);
-			break;
-		case 'application/msword':
-			exec("catdoc $doc_path", $output, $ret_val);
-			//var_dump($output);
-			break;
-		case 'text/html':
-			exec("html2text $doc_path", $output, $ret_val);
-			break;
-		case 'text/rtf':
-			// Note: correct handling of code pages in unrtf
-			// on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
-			exec("unrtf --text $doc_path", $output, $ret_val);
-			if ($ret_val == 127) { // command not found
-				return false;
-			}
-			// Avoid index unrtf comments
-			if (is_array($output) && count($output) > 1) {
-				$parsed_output = array();
-				foreach ($output as & $line) {
-					if (!preg_match('/^###/', $line, $matches)) {
-						if (!empty($line)) {
-							$parsed_output[] = $line;
-						}
-					}
-				}
-				$output = $parsed_output;
-			}
-			break;
-		case 'application/vnd.ms-powerpoint':
-			exec("catppt $doc_path", $output, $ret_val);
-			break;
-		case 'application/vnd.ms-excel':
-			exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
-			break;
-	}
-
-	$content = '';
-	if (!is_null($ret_val)) {
-		if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
-			return false;
-		}
-	}
-	if (isset($output)) {
-		foreach ($output as & $line) {
-			$content .= $line."\n";
-		}
-		return $content;
-	}
-	else {
-		return false;
-	}
-}
+$htmlHeadXtra[] = "
+<script type=\"text/javascript\">
+$(function () {
+    $('#file_upload').fileUploadUI({
+        uploadTable:   $('#files'),
+        downloadTable: $('#files'),
+        buildUploadRow: function (files, index) {
+            return $('<tr><td>' + files[index].name + '<\/td>' +
+                    '<td class=\"file_upload_progress\"><div><\/div><\/td>' +
+                    '<td class=\"file_upload_cancel\">' +
+                    '<button class=\"ui-state-default ui-corner-all\" title=\"".get_lang('Cancel')."\">' +
+                    '<span class=\"ui-icon ui-icon-cancel\">".get_lang('Cancel')."<\/span>' +
+                    '<\/button><\/td><\/tr>');
+        },
+        buildDownloadRow: function (file) {
+            return $('<tr><td>' + file.name + '<\/td><\/tr>');
+        }
+    });    
+    $('#tabs').tabs();
+});
+</script>";
 
 // Variables
 
@@ -184,17 +124,17 @@ if (!DocumentManager::get_document_id($_course, $path)) {
 }
 
 // This needs cleaning!
-if (isset($_SESSION['_gid']) && $_SESSION['_gid'] != '') { // If the group id is set, check if the user has the right to be here
+if (api_get_group_id()) { // If the group id is set, check if the user has the right to be here
 	// Needed for group related stuff
 	require_once api_get_path(LIBRARY_PATH).'groupmanager.lib.php';
 	// Get group info
-	$group_properties = GroupManager::get_group_properties($_SESSION['_gid']);
+	$group_properties = GroupManager::get_group_properties(api_get_group_id());
 	$noPHP_SELF = true;
 
-	if ($is_allowed_to_edit || GroupManager::is_user_in_group($_user['user_id'], $_SESSION['_gid'])) { // Only courseadmin or group members allowed
-		$to_group_id = $_SESSION['_gid'];
-		$req_gid = '&amp;gidReq='.$_SESSION['_gid'];
-		$interbreadcrumb[] = array('url' => '../group/group_space.php?gidReq='.$_SESSION['_gid'], 'name' => get_lang('GroupSpace'));
+	if ($is_allowed_to_edit || GroupManager::is_user_in_group($_user['user_id'], api_get_group_id())) { // Only courseadmin or group members allowed
+		$to_group_id = api_get_group_id();
+		$req_gid = '&amp;gidReq='.api_get_group_id();
+		$interbreadcrumb[] = array('url' => '../group/group_space.php?gidReq='.api_get_group_id(), 'name' => get_lang('GroupSpace'));
 	} else {
 		api_not_allowed(true);
 	}
@@ -218,13 +158,8 @@ if ($is_certificate_array[0] == 'certificates') {
 	$is_certificate_mode = true;
 }
 
-// If we want to unzip a file, we need the library
-if (isset($_POST['unzip']) && $_POST['unzip'] == 1) {
-	require_once api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php';
-}
-
 // Variables
-$max_filled_space = DocumentManager::get_course_quota();
+//$max_filled_space = DocumentManager::get_course_quota();
 
 // Title of the tool
 if ($to_group_id != 0) { // Add group name after for group documents
@@ -243,6 +178,7 @@ if ($is_certificate_mode) {
 	$interbreadcrumb[] = array('url' => './document.php?curdirpath='.urlencode($path).$req_gid, 'name'=> get_lang('Documents'));
 }
 
+
 $this_section = SECTION_COURSES;
 
 // Display the header
@@ -251,182 +187,12 @@ Display::display_header($nameTools, 'Doc');
 /*	Here we do all the work */
 
 // User has submitted a file
-if (isset($_FILES['user_upload'])) {
-	//echo('<pre>');
-	//print_r($_FILES['user_upload']);
-	//echo('</pre>');
-
-	$upload_ok = process_uploaded_file($_FILES['user_upload']);
-	if ($upload_ok) {
-		// File got on the server without problems, now process it
-		$new_path = handle_uploaded_document($_course, $_FILES['user_upload'], $base_work_dir, $_POST['curdirpath'], $_user['user_id'], $to_group_id, $to_user_id, $max_filled_space, $_POST['unzip'], $_POST['if_exists']);
-
-		$new_comment = isset($_POST['comment']) ? trim($_POST['comment']) : '';
-		$new_title = isset($_POST['title']) ? trim($_POST['title']) : '';
-
-		if ($new_path && ($new_comment || $new_title)) {
-			if (($docid = DocumentManager::get_document_id($_course, $new_path))) {
-				$table_document = Database::get_course_table(TABLE_DOCUMENT);
-				$ct = '';
-				if ($new_comment) $ct .= ", comment='$new_comment'";
-				if ($new_title)   $ct .= ", title='$new_title'";
-				Database::query("UPDATE $table_document SET".substr($ct, 1)." WHERE id = '$docid'");
-			}
-		}
-		// Showing message when sending zip files
-		if ($new_path === true && $_POST['unzip'] == 1) {
-			Display::display_confirmation_message(get_lang('UplUploadSucceeded').'<br />', false);
-		}
-
-		if ((api_get_setting('search_enabled') == 'true') && ($docid = DocumentManager::get_document_id($_course, $new_path))) {
-			$table_document = Database::get_course_table(TABLE_DOCUMENT);
-			$result = Database::query("SELECT * FROM $table_document WHERE id = '$docid' LIMIT 1");
-			if (Database::num_rows($result) == 1) {
-				$row = Database::fetch_array($result);
-				$doc_path = api_get_path(SYS_COURSE_PATH).$courseDir.$row['path'];
-				//TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
-				// now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
-				$doc_mime = mime_content_type($doc_path);
-				//echo $doc_mime;
-				//TODO: more mime types
-				$allowed_mime_types = array('text/plain', 'application/pdf', 'application/postscript', 'application/msword', 'text/html', 'text/rtf', 'application/vnd.ms-powerpoint', 'application/vnd.ms-excel');
-
-				// mime_content_type does not detect correctly some formats that are going to be supported for index, so an extensions array is used by the moment
-				if (empty($doc_mime)) {
-					$allowed_extensions = array('ppt', 'pps', 'xls');
-					$extensions = preg_split("/[\/\\.]/", $doc_path) ;
-					$doc_ext = strtolower($extensions[count($extensions) - 1]);
-					if (in_array($doc_ext, $allowed_extensions)) {
-						switch ($doc_ext) {
-							case 'ppt':
-							case 'pps':
-								$doc_mime = 'application/vnd.ms-powerpoint';
-								break;
-							case 'xls':
-								$doc_mime = 'application/vnd.ms-excel';
-								break;
-						}
-					}
-				}
-
-				if (in_array($doc_mime, $allowed_mime_types) && isset($_POST['index_document']) && $_POST['index_document']) {
-					$file_title = $row['title'];
-					$file_content = get_text_content($doc_path, $doc_mime);
-					$courseid = api_get_course_id();
-					$lang = isset($_POST['language']) ? Database::escape_string($_POST['language']) : 'english';
-
-					require_once api_get_path(LIBRARY_PATH).'search/DokeosIndexer.class.php';
-					require_once api_get_path(LIBRARY_PATH).'search/IndexableChunk.class.php';
-
-					$ic_slide = new IndexableChunk();
-					$ic_slide->addValue('title', $file_title);
-					$ic_slide->addCourseId($courseid);
-					$ic_slide->addToolId(TOOL_DOCUMENT);
-					$xapian_data = array(
-						SE_COURSE_ID => $courseid,
-						SE_TOOL_ID => TOOL_DOCUMENT,
-						SE_DATA => array('doc_id' => (int)$docid),
-						SE_USER => (int)api_get_user_id(),
-					);
-					$ic_slide->xapian_data = serialize($xapian_data);
-					$di = new DokeosIndexer();
-					$di->connectDb(null, null, $lang);
-
-					$specific_fields = get_specific_field_list();
-
-					// process different depending on what to do if file exists
-					/**
-					 * FIXME: Find a way to really verify if the file had been
-					 * overwriten. Now all work is done at
-					 * handle_uploaded_document() and it's difficult to verify it
-					 */
-					if (!empty($_POST['if_exists']) && $_POST['if_exists'] == 'overwrite') {
-						// overwrite the file on search engine
-						// actually, it consists on delete terms from db, insert new ones, create a new search engine document, and remove the old one
-
-						// Get search_did
-						$tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
-						$sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
-						$sql = sprintf($sql, $tbl_se_ref, $courseid, TOOL_DOCUMENT, $docid);
-						$res = Database::query($sql);
-
-						if (Database::num_rows($res) > 0) {
-							$se_ref = Database::fetch_array($res);
-							$di->remove_document((int)$se_ref['search_did']);
-							$all_specific_terms = '';
-							foreach ($specific_fields as $specific_field) {
-								delete_all_specific_field_value($courseid, $specific_field['id'], TOOL_DOCUMENT, $docid);
-								// Update search engine
-								$sterms = trim($_REQUEST[$specific_field['code']]);
-								$all_specific_terms .= ' '. $sterms;
-								$sterms = explode(',', $sterms);
-								foreach ($sterms as $sterm) {
-									$sterm = trim($sterm);
-									if (!empty($sterm)) {
-										$ic_slide->addTerm($sterm, $specific_field['code']);
-										add_specific_field_value($specific_field['id'], $courseid, TOOL_DOCUMENT, $docid, $value);
-									}
-								}
-							}
-							// Add terms also to content to make terms findable by probabilistic search
-							$file_content = $all_specific_terms .' '. $file_content;
-							$ic_slide->addValue('content', $file_content);
-							$di->addChunk($ic_slide);
-							// Index and return a new search engine document id
-							$did = $di->index();
-							if ($did) {
-								// update the search_did on db
-								$tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
-								$sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
-								$sql = sprintf($sql, $tbl_se_ref, (int)$did, (int)$se_ref['id']);
-								Database::query($sql);
-							}
-
-						}
-					} else {
-						// Add all terms
-						$all_specific_terms = '';
-						foreach ($specific_fields as $specific_field) {
-							if (isset($_REQUEST[$specific_field['code']])) {
-								$sterms = trim($_REQUEST[$specific_field['code']]);
-								$all_specific_terms .= ' '. $sterms;
-								if (!empty($sterms)) {
-									$sterms = explode(',', $sterms);
-									foreach ($sterms as $sterm) {
-										$ic_slide->addTerm(trim($sterm), $specific_field['code']);
-										add_specific_field_value($specific_field['id'], $courseid, TOOL_DOCUMENT, $docid, $sterm);
-									}
-								}
-							}
-						}
-						// Add terms also to content to make terms findable by probabilistic search
-						$file_content = $all_specific_terms .' '. $file_content;
-						$ic_slide->addValue('content', $file_content);
-						$di->addChunk($ic_slide);
-						// Index and return search engine document id
-						$did = $di->index();
-						if ($did) {
-							// Save it to db
-							$tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
-							$sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
-								VALUES (NULL , \'%s\', \'%s\', %s, %s)';
-							$sql = sprintf($sql, $tbl_se_ref, $courseid, TOOL_DOCUMENT, $docid, $did);
-							Database::query($sql);
-						}
-					}
-				}
-			}
-		}
-
-		// Check for missing images in html files
-		$missing_files = check_for_missing_files($base_work_dir.$new_path);
-		if ($missing_files) {
-			// Show a form to upload the missing files
-			Display::display_normal_message(build_missing_files_form($missing_files, $_POST['curdirpath'], $_FILES['user_upload']['name']), false);
-		}
-	}
+if (!empty($_FILES)) {    
+    DocumentManager::upload_document($_FILES, $_POST['curdirpath'], $_POST['title'], $_POST['comment'], $_POST['unzip'], $_POST['if_exists'], $_POST['index_document'], true);
 }
 
+// @todo remove this  submit_image ???
+/*
 // Missing images are submitted
 if (isset($_POST['submit_image'])) {
 	$number_of_uploaded_images = count($_FILES['img_file']['name']);
@@ -444,7 +210,9 @@ if (isset($_POST['submit_image'])) {
 		item_property_update_on_folder($_course, $_POST['curdirpath'], $_user['user_id']);
 	}
 }
-
+*/
+//@todo keep it simple this page should only upload files!
+/*
 // They want to create a directory
 if (isset($_POST['create_dir']) && $_POST['dirname'] != '') {
 	$added_slash = ($path=='/') ? '' : '/';
@@ -456,13 +224,13 @@ if (isset($_POST['create_dir']) && $_POST['dirname'] != '') {
 	} else {
 		display_error(get_lang('CannotCreateDir'));
 	}
-}
+}*/
 
 // Tracking not needed here?
 //event_access_tool(TOOL_DOCUMENT);
 
 /* They want to create a new directory */
-
+/*
 if (isset($_GET['createdir'])) {
 	// create the form that asks for the directory name
 	$new_folder_text = '<form action="'.api_get_self().'" method="POST">';
@@ -475,7 +243,7 @@ if (isset($_GET['createdir'])) {
 	//Display::display_normal_message($new_folder_text, false);
 
 	echo create_dir_form();
-}
+}*/
 
 // Actions
 echo '<div class="actions">';
@@ -488,9 +256,10 @@ if ($is_certificate_mode) {
 }
 
 // Link to create a folder
+/*
 if (!isset($_GET['createdir']) && !is_my_shared_folder($_user['user_id'], $path, api_get_session_id()) && !$is_certificate_mode) {
 	echo '<a href="'.api_get_self().'?path='.$path.'&amp;createdir=1">'.Display::return_icon('new_folder.png', get_lang('CreateDir'),'','32').'</a>';
-}
+}*/
 echo '</div>';
 
 // Form to select directory
@@ -501,9 +270,8 @@ if (!$is_certificate_mode) {
 
 $form = new FormValidator('upload', 'POST', api_get_self(), '', 'enctype="multipart/form-data"');
 $form->addElement('hidden', 'curdirpath', $path);
-$form->addElement('file', 'user_upload', get_lang('File'), 'id="user_upload" size="45"');
+$form->addElement('file', 'file', get_lang('File'), 'id="user_upload" size="45"');
 $form->addElement('html', '<div class="row" style="font-size:smaller;font-style:italic;"><div class="label">&nbsp;</div><div class="formw">'.get_lang('MaxFileSize').': '.ini_get('upload_max_filesize').'<br/>'.get_lang('DocumentQuota').': '.(round(DocumentManager::get_course_quota()/1000000)-round(documents_total_space($_course)/1000000)).' M</div></div>');
-
 if (api_get_setting('use_document_title') == 'true') {
 	$form->addElement('text', 'title', get_lang('Title'), array('size' => '20', 'style' => 'width:300px', 'id' => 'title_file'));
 	$form->addElement('textarea', 'comment', get_lang('Comment'), 'wrap="virtual" style="width:300px;"');
@@ -542,6 +310,7 @@ $form->addElement('radio', 'if_exists', '', get_lang('UplRenameLong'), 'rename')
 // Close the java script and avoid the footer up
 $form -> addElement('html', '</div>');
 
+
 // Button send document
 $form->addElement('style_submit_button', 'submitDocument', get_lang('SendDocument'), 'class="upload"');
 $form->add_real_progress_bar('DocumentUpload', 'user_upload');
@@ -550,7 +319,19 @@ $defaults = array('index_document' => 'checked="checked"');
 
 $form->setDefaults($defaults);
 
-$form->display();
-
+$simple_form = $form->return_form();
+
+// Multiple uploads
+$url = api_get_path(WEB_AJAX_PATH).'document.ajax.php';
+$multiple_form =  get_lang('ClickToSelectOrDragAndDropMultipleFilesOnTheUploadField').'<br />';
+$multiple_form .=  '<form id="file_upload" action="'.$url.'" method="POST" enctype="multipart/form-data">
+    <input type="hidden" name="curdirpath" value="'.$path.'" />    
+    <input type="file" name="file" multiple>
+    <button>Upload</button>
+    <div>'.get_lang('UploadFiles').'</div>
+</form>';
+$multiple_form  .='<table id="files"></table>';
+$headers = array(get_lang('Simple') , get_lang('Multiple'));
+echo Display::tabs($headers, array($simple_form, $multiple_form ),'tabs');
 // Footer
-Display::display_footer();
+Display::display_footer();

+ 16 - 0
main/inc/ajax/document.ajax.php

@@ -0,0 +1,16 @@
+<?php
+/* For licensing terms, see /license.txt */
+/**
+ * Responses to AJAX calls for the document upload 
+ */
+require_once '../global.inc.php';
+if (api_is_anonymous()){
+    exit;
+}
+if(!empty($_FILES)) {
+    require_once api_get_path(LIBRARY_PATH).'document.lib.php';
+    DocumentManager::upload_document($_FILES, $_POST['curdirpath'], '', '', 0);
+    $file = $_FILES['file'];
+    echo '{"name":"'.$file['name'].'","type":"'.$file['type'].'","size":"'.$file['size'].'"}';
+}
+exit;

+ 274 - 0
main/inc/lib/document.lib.php

@@ -1800,5 +1800,279 @@ class DocumentManager {
         $pdf = new PDF();
         $pdf->html_to_pdf($file_path, $document_data['title'], $course_code);
     }
+    
+    public function upload_document($files, $path, $title = '', $comment = '', $unzip = 0, $if_exists = '', $index_document = false, $show_output = false) {
+        require_once api_get_path(LIBRARY_PATH).'fileUpload.lib.php';
+        //If we want to unzip a file, we need the library
+        if (isset($unzip) && $unzip == 1) {
+            require_once api_get_path(LIBRARY_PATH).'pclzip/pclzip.lib.php';
+        }
+        
+        $max_filled_space = self::get_course_quota();
+        $course_info = api_get_course_info();
+        
+        $courseDir = $course_info['path'].'/document';
+        $sys_course_path = api_get_path(SYS_COURSE_PATH);
+        $base_work_dir = $sys_course_path.$courseDir;
+             
+        if (isset($files['file'])) {
+            //echo('<pre>');
+        
+            //echo('</pre>');
+                
+            $upload_ok = process_uploaded_file($files['file']);
+            if ($upload_ok) {
+                // File got on the server without problems, now process it
+                $new_path = handle_uploaded_document($course_info, $files['file'], $base_work_dir, $path, api_get_user_id(), api_get_group_id(), null, $max_filled_space, $unzip, $if_exists, $show_output);
+        
+                $new_comment = isset($title) ? trim($comment) : '';
+                $new_title = isset($title) ? trim($title) : '';
+        
+                if ($new_path && ($new_comment || $new_title)) {
+                    if (($docid = DocumentManager::get_document_id($course_info, $new_path))) {
+                        $table_document = Database::get_course_table(TABLE_DOCUMENT);
+                        $ct = '';
+                        if ($new_comment) $ct .= ", comment='$new_comment'";
+                        if ($new_title)   $ct .= ", title='$new_title'";
+                        Database::query("UPDATE $table_document SET ".substr($ct, 1)." WHERE id = $docid");
+                    }
+                }
+                // Showing message when sending zip files
+                if ($new_path === true && $unzip == 1) {
+                    //Display::display_confirmation_message(get_lang('UplUploadSucceeded').'<br />', false);                    
+                }
+        
+                if ((api_get_setting('search_enabled') == 'true') && ($docid = DocumentManager::get_document_id($course_info, $new_path))) {
+                    $table_document = Database::get_course_table(TABLE_DOCUMENT);
+                    $result = Database::query("SELECT * FROM $table_document WHERE id = '$docid' LIMIT 1");
+                    if (Database::num_rows($result) == 1) {
+                        $row = Database::fetch_array($result);
+                        $doc_path = api_get_path(SYS_COURSE_PATH).$courseDir.$row['path'];
+                        //TODO: mime_content_type is deprecated, fileinfo php extension is enabled by default as of PHP 5.3.0
+                        // now versions of PHP on Debian testing(5.2.6-5) and Ubuntu(5.2.6-2ubuntu) are lower, so wait for a while
+                        $doc_mime = mime_content_type($doc_path);
+                        //echo $doc_mime;
+                        //TODO: more mime types
+                        $allowed_mime_types = array('text/plain', 'application/pdf', 'application/postscript', 'application/msword', 'text/html', 'text/rtf', 'application/vnd.ms-powerpoint', 'application/vnd.ms-excel');
+        
+                        // mime_content_type does not detect correctly some formats that are going to be supported for index, so an extensions array is used by the moment
+                        if (empty($doc_mime)) {
+                            $allowed_extensions = array('ppt', 'pps', 'xls');
+                            $extensions = preg_split("/[\/\\.]/", $doc_path) ;
+                            $doc_ext = strtolower($extensions[count($extensions) - 1]);
+                            if (in_array($doc_ext, $allowed_extensions)) {
+                                switch ($doc_ext) {
+                                    case 'ppt':
+                                    case 'pps':
+                                        $doc_mime = 'application/vnd.ms-powerpoint';
+                                        break;
+                                    case 'xls':
+                                        $doc_mime = 'application/vnd.ms-excel';
+                                        break;
+                                }
+                            }
+                        }
+        
+                        //@todo move this nightmare in a search controller or something like that!!! J.M
+                         
+                        if (in_array($doc_mime, $allowed_mime_types) && isset($index_document) && $index_document) {
+                            $file_title = $row['title'];
+                            $file_content = self::get_text_content($doc_path, $doc_mime);
+                            $courseid = api_get_course_id();
+                            $lang = isset($_POST['language']) ? Database::escape_string($_POST['language']) : 'english';
+        
+                            require_once api_get_path(LIBRARY_PATH).'search/DokeosIndexer.class.php';
+                            require_once api_get_path(LIBRARY_PATH).'search/IndexableChunk.class.php';
+        
+                            $ic_slide = new IndexableChunk();
+                            $ic_slide->addValue('title', $file_title);
+                            $ic_slide->addCourseId($courseid);
+                            $ic_slide->addToolId(TOOL_DOCUMENT);
+                            $xapian_data = array(
+                                SE_COURSE_ID => $courseid,
+                                SE_TOOL_ID => TOOL_DOCUMENT,
+                                SE_DATA => array('doc_id' => (int)$docid),
+                                SE_USER => (int)api_get_user_id(),
+                            );
+                            $ic_slide->xapian_data = serialize($xapian_data);
+                            $di = new DokeosIndexer();
+                            $di->connectDb(null, null, $lang);
+        
+                            $specific_fields = get_specific_field_list();
+        
+                            // process different depending on what to do if file exists
+                            /**
+                             * FIXME: Find a way to really verify if the file had been
+                             * overwriten. Now all work is done at
+                             * handle_uploaded_document() and it's difficult to verify it
+                             */
+                            if (!empty($if_exists) && $if_exists == 'overwrite') {
+                                // overwrite the file on search engine
+                                // actually, it consists on delete terms from db, insert new ones, create a new search engine document, and remove the old one
+        
+                                // Get search_did
+                                $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
+                                $sql = 'SELECT * FROM %s WHERE course_code=\'%s\' AND tool_id=\'%s\' AND ref_id_high_level=%s LIMIT 1';
+                                $sql = sprintf($sql, $tbl_se_ref, $courseid, TOOL_DOCUMENT, $docid);
+                                $res = Database::query($sql);
+        
+                                if (Database::num_rows($res) > 0) {
+                                    $se_ref = Database::fetch_array($res);
+                                    $di->remove_document((int)$se_ref['search_did']);
+                                    $all_specific_terms = '';
+                                    foreach ($specific_fields as $specific_field) {
+                                        delete_all_specific_field_value($courseid, $specific_field['id'], TOOL_DOCUMENT, $docid);
+                                        // Update search engine
+                                        $sterms = trim($_REQUEST[$specific_field['code']]);
+                                        $all_specific_terms .= ' '. $sterms;
+                                        $sterms = explode(',', $sterms);
+                                        foreach ($sterms as $sterm) {
+                                            $sterm = trim($sterm);
+                                            if (!empty($sterm)) {
+                                                $ic_slide->addTerm($sterm, $specific_field['code']);
+                                                add_specific_field_value($specific_field['id'], $courseid, TOOL_DOCUMENT, $docid, $value);
+                                            }
+                                        }
+                                    }
+                                    // Add terms also to content to make terms findable by probabilistic search
+                                    $file_content = $all_specific_terms .' '. $file_content;
+                                    $ic_slide->addValue('content', $file_content);
+                                    $di->addChunk($ic_slide);
+                                    // Index and return a new search engine document id
+                                    $did = $di->index();
+                                    if ($did) {
+                                        // update the search_did on db
+                                        $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
+                                        $sql = 'UPDATE %s SET search_did=%d WHERE id=%d LIMIT 1';
+                                        $sql = sprintf($sql, $tbl_se_ref, (int)$did, (int)$se_ref['id']);
+                                        Database::query($sql);
+                                    }
+        
+                                }
+                            } else {
+                                // Add all terms
+                                $all_specific_terms = '';
+                                foreach ($specific_fields as $specific_field) {
+                                    if (isset($_REQUEST[$specific_field['code']])) {
+                                        $sterms = trim($_REQUEST[$specific_field['code']]);
+                                        $all_specific_terms .= ' '. $sterms;
+                                        if (!empty($sterms)) {
+                                            $sterms = explode(',', $sterms);
+                                            foreach ($sterms as $sterm) {
+                                                $ic_slide->addTerm(trim($sterm), $specific_field['code']);
+                                                add_specific_field_value($specific_field['id'], $courseid, TOOL_DOCUMENT, $docid, $sterm);
+                                            }
+                                        }
+                                    }
+                                }
+                                // Add terms also to content to make terms findable by probabilistic search
+                                $file_content = $all_specific_terms .' '. $file_content;
+                                $ic_slide->addValue('content', $file_content);
+                                $di->addChunk($ic_slide);
+                                // Index and return search engine document id
+                                $did = $di->index();
+                                if ($did) {
+                                    // Save it to db
+                                    $tbl_se_ref = Database::get_main_table(TABLE_MAIN_SEARCH_ENGINE_REF);
+                                    $sql = 'INSERT INTO %s (id, course_code, tool_id, ref_id_high_level, search_did)
+                                        VALUES (NULL , \'%s\', \'%s\', %s, %s)';
+                                    $sql = sprintf($sql, $tbl_se_ref, $courseid, TOOL_DOCUMENT, $docid, $did);
+                                    Database::query($sql);
+                                }
+                            }
+                        }
+                    }
+                }
+        
+                // Check for missing images in html files
+                $missing_files = check_for_missing_files($base_work_dir.$new_path);
+                if ($missing_files) {
+                    // Show a form to upload the missing files
+                    //Display::display_normal_message(build_missing_files_form($missing_files, $path, $files['file']['name']), false);
+                }
+            }
+        }
+    }
+
+    /**
+     * Obtains the text inside the file with the right parser
+
+     */
+    function get_text_content($doc_path, $doc_mime) {
+        // TODO: review w$ compatibility
+    
+        // Use usual exec output lines array to store stdout instead of a temp file
+        // because we need to store it at RAM anyway before index on DokeosIndexer object
+        $ret_val = null;
+        switch ($doc_mime) {
+            case 'text/plain':
+                $handle = fopen($doc_path, 'r');
+                $output = array(fread($handle, filesize($doc_path)));
+                fclose($handle);
+                break;
+            case 'application/pdf':
+                exec("pdftotext $doc_path -", $output, $ret_val);
+                break;
+            case 'application/postscript':
+                $temp_file = tempnam(sys_get_temp_dir(), 'chamilo');
+                exec("ps2pdf $doc_path $temp_file", $output, $ret_val);
+                if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
+                    return false;
+                }
+                exec("pdftotext $temp_file -", $output, $ret_val);
+                unlink($temp_file);
+                //var_dump($output);
+                break;
+            case 'application/msword':
+                exec("catdoc $doc_path", $output, $ret_val);
+                //var_dump($output);
+                break;
+            case 'text/html':
+                exec("html2text $doc_path", $output, $ret_val);
+                break;
+            case 'text/rtf':
+                // Note: correct handling of code pages in unrtf
+                // on debian lenny unrtf v0.19.2 can not, but unrtf v0.20.5 can
+                exec("unrtf --text $doc_path", $output, $ret_val);
+                if ($ret_val == 127) { // command not found
+                    return false;
+                }
+                // Avoid index unrtf comments
+                if (is_array($output) && count($output) > 1) {
+                    $parsed_output = array();
+                    foreach ($output as & $line) {
+                        if (!preg_match('/^###/', $line, $matches)) {
+                            if (!empty($line)) {
+                                $parsed_output[] = $line;
+                            }
+                        }
+                    }
+                    $output = $parsed_output;
+                }
+                break;
+            case 'application/vnd.ms-powerpoint':
+                exec("catppt $doc_path", $output, $ret_val);
+                break;
+            case 'application/vnd.ms-excel':
+                exec("xls2csv -c\" \" $doc_path", $output, $ret_val);
+                break;
+        }
+    
+        $content = '';
+        if (!is_null($ret_val)) {
+            if ($ret_val !== 0) { // shell fail, probably 127 (command not found)
+                return false;
+            }
+        }
+        if (isset($output)) {
+            foreach ($output as & $line) {
+                $content .= $line."\n";
+            }
+            return $content;
+        }
+        else {
+            return false;
+        }
+    }
 }
 //end class DocumentManager

+ 24 - 8
main/inc/lib/fileUpload.lib.php

@@ -139,7 +139,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 	$current_session_id = api_get_session_id();
 	// Check if there is enough space to save the file
 	if (!enough_space($uploaded_file['size'], $maxFilledSpace)) {
-		Display::display_error_message(get_lang('UplNotEnoughSpace'));
+	    if ($output){
+		  Display::display_error_message(get_lang('UplNotEnoughSpace'));
+		}
 		return false;
 	}
 
@@ -150,7 +152,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 	}
 	// We can only unzip ZIP files (no gz, tar,...)
 	elseif ($unzip == 1 && !preg_match('/.zip$/', strtolower($uploaded_file['name']))) {
-		Display::display_error_message(get_lang('UplNotAZip')." ".get_lang('PleaseTryAgain'));
+	    if ($output) {	
+            Display::display_error_message(get_lang('UplNotAZip')." ".get_lang('PleaseTryAgain'));
+	    }
 		return false;
 	} else {
 		// Clean up the name, only ASCII characters should stay. (and strict)
@@ -158,7 +162,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 		// No "dangerous" files
 		$clean_name = disable_dangerous_file($clean_name);
 		if (!filter_extension($clean_name)) {
-			Display::display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
+		    if ($output){
+                Display::display_error_message(get_lang('UplUnableToSaveFileFilteredExtension'));
+		    }
 			return false;
 		} else {
 			// Extension is good
@@ -175,7 +181,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 			$where_to_save = $base_work_dir.$upload_path;
 			// At least if the directory doesn't exist, tell so
 			if (!is_dir($where_to_save)) {
-				Display::display_error_message(get_lang('DestDirectoryDoesntExist').' ('.$upload_path.')');
+			    if ($output){
+				    Display::display_error_message(get_lang('DestDirectoryDoesntExist').' ('.$upload_path.')');
+				}
 				return false;
 			}
 			//echo '<br />where to save = '.$where_to_save;
@@ -223,11 +231,15 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 							// If the file is in a folder, we need to update all parent folders
 							item_property_update_on_folder($_course, $upload_path, $user_id);
 							// Display success message to user
-							Display::display_confirmation_message(get_lang('UplUploadSucceeded').'<br />'.$file_path, false);
+							if ($output){
+                                Display::display_confirmation_message(get_lang('UplUploadSucceeded').'<br />'.$file_path, false);
+							}
 							return $file_path;
 						}
 					} else {
-						Display::display_error_message(get_lang('UplUnableToSaveFile'));
+					    if ($output){
+						  Display::display_error_message(get_lang('UplUnableToSaveFile'));
+					    }
 						return false;
 					}
 					break;
@@ -264,7 +276,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 				// Only save the file if it doesn't exist or warn user if it does exist
 				default:
 					if (file_exists($store_path)) {
-						Display::display_error_message($clean_name.' '.get_lang('UplAlreadyExists'));
+					    if ($output){
+						  Display::display_error_message($clean_name.' '.get_lang('UplAlreadyExists'));
+						}
 					} else {
 						if (@move_uploaded_file($uploaded_file['tmp_name'], $store_path)) {
 							chmod($store_path, $files_perm);
@@ -283,7 +297,9 @@ function handle_uploaded_document($_course, $uploaded_file, $base_work_dir, $upl
 							}
 							return $file_path;
 						} else {
-							Display::display_error_message(get_lang('UplUnableToSaveFile'));
+						    if ($output){
+                                Display::display_error_message(get_lang('UplUnableToSaveFile'));
+							}
 							return false;
 						}
 					}

+ 61 - 0
main/inc/lib/javascript/jquery-upload/README.txt

@@ -0,0 +1,61 @@
+jQuery File Upload Plugin
+=========================
+
+Demo
+----
+http://aquantum-demo.appspot.com/file-upload
+
+Features
+--------
+  - Multiple file upload:
+    Allows to select multiple files at once and upload them simultaneously.
+  - Drag & Drop support:
+    Allows to upload files by dragging them from your desktop or filemanager and dropping them on your browser window.
+  - Upload progress bar:
+    Shows a progress bar indicating the upload progress for individual files.
+  - Cancelable uploads:
+    Individual file uploads can be canceled to stop the upload progress.
+  - No browser plugins (e.g. Adobe Flash) required:
+    The implementation is based on open standards like HTML5 and JavaScript and requires no additional browser plugins.
+  - Graceful fallback for legacy browsers:
+    Uploads files via XMLHttpRequests if supported and uses iframes as fallback for legacy browsers.
+  - HTML file upload form fallback:
+    Shows a standard HTML file upload form if JavaScript is disabled.
+  - Cross-site file uploads:
+    Supports uploading files to a different domain with Cross-site XMLHttpRequests.
+  - Multiple plugin instances:
+    Allows to use multiple plugin instances on the same webpage.
+  - Customizable and extensible:
+    Provides an API to set individual options and define callBack methods for various upload events.
+  - Multipart and file contents stream uploads:
+    Files can be uploaded as standard "multipart/form-data" or file contents stream (HTTP PUT file upload).
+  - Compatible with any server-side application platform:
+    Works with Google App Engine (Python, Java), Ruby on Rails, PHP and any other platform that supports HTTP file uploads.
+
+Requirements
+------------
+  - jQuery v. 1.4+
+  - jQuery UI v. 1.8+ (optional)
+
+Browser Support (tested versions)
+---------------------------------
+  - Google Chrome - 7.0, 8.0, 9.0
+  - Apple Safari - 5.0 ¹
+  - Mozilla Firefox - 3.6
+  - Opera - 10.60 ², 11.00 ²
+  - Microsoft Internet Explorer 6.0 ², 7.0 ², 8.0 ², 9.0 ²
+¹ Drag & Drop is not supported on the Windows version of Safari.
+² MSIE and Opera have no support for Drag & Drop, multiple file selection or upload progress indication.
+
+License
+-------
+Released under the MIT license:
+http://creativecommons.org/licenses/MIT/
+
+Source Code & Download
+----------------------
+https://github.com/blueimp/jQuery-File-Upload
+
+Documentation
+-------------
+https://github.com/blueimp/jQuery-File-Upload/wiki

+ 74 - 0
main/inc/lib/javascript/jquery-upload/jquery.fileupload-ui.css

@@ -0,0 +1,74 @@
+.file_upload {
+  position: relative;
+  overflow: hidden;
+  direction: ltr;
+  cursor: pointer;
+  text-align: center;
+  color: #333;
+  font-weight: bold;
+  -moz-border-radius: 10px;
+  -webkit-border-radius: 10px;
+  border-radius: 10px;
+  width: 200px;
+  height: 30px;
+  line-height: 30px;
+  background: palegreen;
+  border: 1px solid limegreen;
+}
+
+.file_upload_small {
+  width: 200px;
+  height: 30px;
+  line-height: 30px;
+  font-size: auto;
+  background: palegreen;
+  border: 1px solid limegreen;
+}
+
+.file_upload_large {
+  width: 100%;
+  height: 150px;
+  line-height: 150px;
+  font-size: 20px;
+  background: palegreen;
+  border: 1px solid limegreen;
+}
+
+.file_upload_highlight {
+  background: lawngreen;
+}
+
+.file_upload input {
+  position: absolute;
+  top: 0;
+  right: 0;
+  margin: 0;
+  border: 300px solid transparent;
+  opacity: 0;
+  -ms-filter: 'alpha(opacity=0)';
+  filter: alpha(opacity=0);
+  -o-transform: translate(-300px, -300px) scale(10);
+  -moz-transform: translate(-800px, 0) scale(10);
+  cursor: pointer;
+}
+
+.file_upload iframe, .file_upload button {
+  display: none;
+}
+
+.file_upload_preview img {
+  width: 80px;
+}
+
+.file_upload_progress .ui-progressbar-value {
+  background: url(pbar-ani.gif);
+}
+
+.file_upload_progress div {
+  width: 150px;
+  height: 15px;
+}
+
+.file_upload_cancel button {
+  cursor: pointer;
+}

+ 308 - 0
main/inc/lib/javascript/jquery-upload/jquery.fileupload-ui.js

@@ -0,0 +1,308 @@
+/*
+ * jQuery File Upload User Interface Plugin 3.6
+ *
+ * Copyright 2010, Sebastian Tschan, AQUANTUM
+ * Licensed under the MIT license:
+ * http://creativecommons.org/licenses/MIT/
+ *
+ * https://blueimp.net
+ * http://www.aquantum.de
+ */
+
+/*jslint browser: true */
+/*global jQuery, FileReader, URL */
+
+(function ($) {
+
+    var undef = 'undefined',
+        func = 'function',
+        UploadHandler,
+        methods,
+
+        LocalImage = function (file, imageTypes) {
+            var img,
+                fileReader;
+            if (!imageTypes.test(file.type)) {
+                return null;
+            }
+            img = document.createElement('img');
+            if (typeof URL !== undef && typeof URL.createObjectURL === func) {
+                img.src = URL.createObjectURL(file);
+                img.onload = function () {
+                    URL.revokeObjectURL(this.src);
+                };
+                return img;
+            }
+            if (typeof FileReader !== undef) {
+                fileReader = new FileReader();
+                if (typeof fileReader.readAsDataURL === func) {
+                    fileReader.onload = function (e) {
+                        img.src = e.target.result;
+                    };
+                    fileReader.readAsDataURL(file);
+                    return img;
+                }
+            }
+            return null;
+        };
+        
+    UploadHandler = function (container, options) {
+        var uploadHandler = this,
+            dragOverTimeout,
+            isDropZoneEnlarged;
+        
+        this.dropZone = container;
+        this.imageTypes = /^image\/(gif|jpeg|png)$/;
+        this.previewSelector = '.file_upload_preview';
+        this.progressSelector = '.file_upload_progress div';
+        this.cancelSelector = '.file_upload_cancel button';
+        this.cssClassSmall = 'file_upload_small';
+        this.cssClassLarge = 'file_upload_large';
+        this.cssClassHighlight = 'file_upload_highlight';
+        this.dropEffect = 'highlight';
+        this.uploadTable = this.downloadTable = null;
+        
+        this.buildUploadRow = this.buildDownloadRow = function () {
+            return null;
+        };
+
+        this.addNode = function (parentNode, node, callBack) {
+            if (node) {
+                node.css('display', 'none').appendTo(parentNode).fadeIn(function () {
+                    if (typeof callBack === func) {
+                        try {
+                            callBack();
+                        } catch (e) {
+                            // Fix endless exception loop:
+                            $(this).stop();
+                            throw e;
+                        }
+                    }
+                });
+            } else if (typeof callBack === func) {
+                callBack();
+            }
+        };
+
+        this.removeNode = function (node, callBack) {
+            if (node) {
+                node.fadeOut(function () {
+                    $(this).remove();
+                    if (typeof callBack === func) {
+                        try {
+                            callBack();
+                        } catch (e) {
+                            // Fix endless exception loop:
+                            $(this).stop();
+                            throw e;
+                        }
+                    }
+                });
+            } else if (typeof callBack === func) {
+                callBack();
+            }
+        };
+
+        this.onAbort = function (event, files, index, xhr, handler) {
+            handler.removeNode(handler.uploadRow);
+        };
+        
+        this.cancelUpload = function (event, files, index, xhr, handler) {
+            var readyState = xhr.readyState;
+            xhr.abort();
+            // If readyState is below 2, abort() has no effect:
+            if (isNaN(readyState) || readyState < 2) {
+                handler.onAbort(event, files, index, xhr, handler);
+            }
+        };
+        
+        this.initProgressBar = function (node, value) {
+            if (typeof node.progressbar === func) {
+                return node.progressbar({
+                    value: value
+                });
+            } else {
+                var progressbar = $('<progress value="' + value + '" max="100"/>').appendTo(node);
+                progressbar.progressbar = function (key, value) {
+                    progressbar.attr('value', value);
+                };
+                return progressbar;
+            }
+        };
+        
+        this.initUploadRow = function (event, files, index, xhr, handler, callBack) {
+            var uploadRow = handler.uploadRow = handler.buildUploadRow(files, index, handler);
+            if (uploadRow) {
+                handler.progressbar = handler.initProgressBar(
+                    uploadRow.find(handler.progressSelector),
+                    (xhr.upload ? 0 : 100)
+                );
+                uploadRow.find(handler.cancelSelector).click(function (e) {
+                    handler.cancelUpload(e, files, index, xhr, handler);
+                });
+                uploadRow.find(handler.previewSelector).each(function () {
+                    $(this).append(new LocalImage(files[index], handler.imageTypes));
+                });
+            }
+            handler.addNode(
+                (typeof handler.uploadTable === func ? handler.uploadTable(handler) : handler.uploadTable),
+                uploadRow,
+                callBack
+            );
+        };
+        
+        this.initUpload = function (event, files, index, xhr, handler, callBack) {
+            handler.initUploadRow(event, files, index, xhr, handler, function () {
+                if (typeof handler.beforeSend === func) {
+                    handler.beforeSend(event, files, index, xhr, handler, callBack);
+                } else {
+                    callBack();
+                }
+            });
+        };
+        
+        this.onProgress = function (event, files, index, xhr, handler) {
+            if (handler.progressbar) {
+                handler.progressbar.progressbar(
+                    'value',
+                    parseInt(event.loaded / event.total * 100, 10)
+                );
+            }
+        };
+        
+        this.parseResponse = function (xhr) {
+            if (typeof xhr.responseText !== undef) {
+                return $.parseJSON(xhr.responseText);
+            } else {
+                // Instead of an XHR object, an iframe is used for legacy browsers:
+                return $.parseJSON(xhr.contents().text());
+            }
+        };
+        
+        this.initDownloadRow = function (event, files, index, xhr, handler, callBack) {
+            var json, downloadRow;
+            try {
+                json = handler.response = handler.parseResponse(xhr);
+                downloadRow = handler.downloadRow = handler.buildDownloadRow(json, handler);
+                handler.addNode(
+                    (typeof handler.downloadTable === func ? handler.downloadTable(handler) : handler.downloadTable),
+                    downloadRow,
+                    callBack
+                );
+            } catch (e) {
+                if (typeof handler.onError === func) {
+                    handler.originalEvent = event;
+                    handler.onError(e, files, index, xhr, handler);
+                } else {
+                    throw e;
+                }
+            }
+        };
+        
+        this.onLoad = function (event, files, index, xhr, handler) {
+            handler.removeNode(handler.uploadRow, function () {
+                handler.initDownloadRow(event, files, index, xhr, handler, function () {
+                    if (typeof handler.onComplete === func) {
+                        handler.onComplete(event, files, index, xhr, handler);
+                    }
+                });
+            });
+        };
+
+        this.dropZoneEnlarge = function () {
+            if (!isDropZoneEnlarged) {
+                if (typeof uploadHandler.dropZone.switchClass === func) {
+                    uploadHandler.dropZone.switchClass(
+                        uploadHandler.cssClassSmall,
+                        uploadHandler.cssClassLarge
+                    );
+                } else {
+                    uploadHandler.dropZone.addClass(uploadHandler.cssClassLarge);
+                    uploadHandler.dropZone.removeClass(uploadHandler.cssClassSmall);
+                }
+                isDropZoneEnlarged = true;
+            }
+        };
+        
+        this.dropZoneReduce = function () {
+            if (typeof uploadHandler.dropZone.switchClass === func) {
+                uploadHandler.dropZone.switchClass(
+                    uploadHandler.cssClassLarge,
+                    uploadHandler.cssClassSmall
+                );
+            } else {
+                uploadHandler.dropZone.addClass(uploadHandler.cssClassSmall);
+                uploadHandler.dropZone.removeClass(uploadHandler.cssClassLarge);
+            }
+            isDropZoneEnlarged = false;
+        };
+
+        this.onDocumentDragEnter = function (event) {
+            uploadHandler.dropZoneEnlarge();
+        };
+        
+        this.onDocumentDragOver = function (event) {
+            if (dragOverTimeout) {
+                clearTimeout(dragOverTimeout);
+            }
+            dragOverTimeout = setTimeout(function () {
+                uploadHandler.dropZoneReduce();
+            }, 200);
+        };
+        
+        this.onDragEnter = this.onDragLeave = function (event) {
+            uploadHandler.dropZone.toggleClass(uploadHandler.cssClassHighlight);
+        };
+        
+        this.onDrop = function (event) {
+            if (dragOverTimeout) {
+                clearTimeout(dragOverTimeout);
+            }
+            if (uploadHandler.dropEffect && typeof uploadHandler.dropZone.effect === func) {
+                uploadHandler.dropZone.effect(uploadHandler.dropEffect, function () {
+                    uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);
+                    uploadHandler.dropZoneReduce();
+                });
+            } else {
+                uploadHandler.dropZone.removeClass(uploadHandler.cssClassHighlight);
+                uploadHandler.dropZoneReduce();
+            }
+        };
+
+        $.extend(this, options);
+    };
+
+    methods = {
+        init : function (options) {
+            return this.each(function () {
+                $(this).fileUpload(new UploadHandler($(this), options));
+            });
+        },
+        
+        option: function (option, value, namespace) {
+            if (typeof option === undef || (typeof option === 'string' && typeof value === undef)) {
+                return $(this).fileUpload('option', option, value, namespace);
+            }
+            return this.each(function () {
+                $(this).fileUpload('option', option, value, namespace);
+            });
+        },
+            
+        destroy : function (namespace) {
+            return this.each(function () {
+                $(this).fileUpload('destroy', namespace);
+            });
+        }
+    };
+    
+    $.fn.fileUploadUI = function (method) {
+        if (methods[method]) {
+            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+        } else if (typeof method === 'object' || !method) {
+            return methods.init.apply(this, arguments);
+        } else {
+            $.error('Method ' + method + ' does not exist on jQuery.fileUploadUI');
+        }
+    };
+    
+}(jQuery));

+ 629 - 0
main/inc/lib/javascript/jquery-upload/jquery.fileupload.js

@@ -0,0 +1,629 @@
+/*
+ * jQuery File Upload Plugin 3.7.1
+ *
+ * Copyright 2010, Sebastian Tschan, AQUANTUM
+ * Licensed under the MIT license:
+ * http://creativecommons.org/licenses/MIT/
+ *
+ * https://blueimp.net
+ * http://www.aquantum.de
+ */
+
+/*jslint browser: true */
+/*global File, FileReader, FormData, unescape, jQuery */
+
+(function ($) {
+
+    var defaultNamespace = 'file_upload',
+        undef = 'undefined',
+        func = 'function',
+        num = 'number',
+        FileUpload,
+        methods,
+
+        MultiLoader = function (callBack, numberComplete) {
+            var loaded = 0;
+            this.complete = function () {
+                loaded += 1;
+                if (loaded === numberComplete) {
+                    callBack();
+                }
+            };
+        };
+        
+    FileUpload = function (container) {
+        var fileUpload = this,
+            uploadForm,
+            fileInput,
+            settings = {
+                namespace: defaultNamespace,
+                uploadFormFilter: function (index) {
+                    return true;
+                },
+                fileInputFilter: function (index) {
+                    return true;
+                },
+                cssClass: defaultNamespace,
+                dragDropSupport: true,
+                dropZone: container,
+                url: function (form) {
+                    return form.attr('action');
+                },
+                method: function (form) {
+                    return form.attr('method');
+                },
+                fieldName: function (input) {
+                    return input.attr('name');
+                },
+                formData: function (form) {
+                    return form.serializeArray();
+                },
+                multipart: true,
+                multiFileRequest: false,
+                withCredentials: false,
+                forceIframeUpload: false
+            },
+            documentListeners = {},
+            dropZoneListeners = {},
+            protocolRegExp = /^http(s)?:\/\//,
+            optionsReference,
+
+            isXHRUploadCapable = function () {
+                return typeof XMLHttpRequest !== undef && typeof File !== undef && (
+                    !settings.multipart || typeof FormData !== undef || typeof FileReader !== undef
+                );
+            },
+
+            initEventHandlers = function () {
+                if (settings.dragDropSupport) {
+                    if (typeof settings.onDocumentDragEnter === func) {
+                        documentListeners['dragenter.' + settings.namespace] = function (e) {
+                            settings.onDocumentDragEnter(e);
+                        };
+                    }
+                    if (typeof settings.onDocumentDragLeave === func) {
+                        documentListeners['dragleave.' + settings.namespace] = function (e) {
+                            settings.onDocumentDragLeave(e);
+                        };
+                    }
+                    documentListeners['dragover.'   + settings.namespace] = fileUpload.onDocumentDragOver;
+                    documentListeners['drop.'       + settings.namespace] = fileUpload.onDocumentDrop;
+                    $(document).bind(documentListeners);
+                    if (typeof settings.onDragEnter === func) {
+                        dropZoneListeners['dragenter.' + settings.namespace] = function (e) {
+                            settings.onDragEnter(e);
+                        };
+                    }
+                    if (typeof settings.onDragLeave === func) {
+                        dropZoneListeners['dragleave.' + settings.namespace] = function (e) {
+                            settings.onDragLeave(e);
+                        };
+                    }
+                    dropZoneListeners['dragover.'   + settings.namespace] = fileUpload.onDragOver;
+                    dropZoneListeners['drop.'       + settings.namespace] = fileUpload.onDrop;
+                    settings.dropZone.bind(dropZoneListeners);
+                }
+                fileInput.bind('change.' + settings.namespace, fileUpload.onChange);
+            },
+
+            removeEventHandlers = function () {
+                $.each(documentListeners, function (key, value) {
+                    $(document).unbind(key, value);
+                });
+                $.each(dropZoneListeners, function (key, value) {
+                    settings.dropZone.unbind(key, value);
+                });
+                fileInput.unbind('change.' + settings.namespace);
+            },
+
+            initUploadEventHandlers = function (files, index, xhr, settings) {
+                if (typeof settings.onProgress === func) {
+                    xhr.upload.onprogress = function (e) {
+                        settings.onProgress(e, files, index, xhr, settings);
+                    };
+                }
+                if (typeof settings.onLoad === func) {
+                    xhr.onload = function (e) {
+                        settings.onLoad(e, files, index, xhr, settings);
+                    };
+                }
+                if (typeof settings.onAbort === func) {
+                    xhr.onabort = function (e) {
+                        settings.onAbort(e, files, index, xhr, settings);
+                    };
+                }
+                if (typeof settings.onError === func) {
+                    xhr.onerror = function (e) {
+                        settings.onError(e, files, index, xhr, settings);
+                    };
+                }
+            },
+
+            getUrl = function (settings) {
+                if (typeof settings.url === func) {
+                    return settings.url(settings.uploadForm || uploadForm);
+                }
+                return settings.url;
+            },
+            
+            getMethod = function (settings) {
+                if (typeof settings.method === func) {
+                    return settings.method(settings.uploadForm || uploadForm);
+                }
+                return settings.method;
+            },
+            
+            getFieldName = function (settings) {
+                if (typeof settings.fieldName === func) {
+                    return settings.fieldName(settings.fileInput || fileInput);
+                }
+                return settings.fieldName;
+            },
+
+            getFormData = function (settings) {
+                var formData;
+                if (typeof settings.formData === func) {
+                    return settings.formData(settings.uploadForm || uploadForm);
+                } else if ($.isArray(settings.formData)) {
+                    return settings.formData;
+                } else if (settings.formData) {
+                    formData = [];
+                    $.each(settings.formData, function (name, value) {
+                        formData.push({name: name, value: value});
+                    });
+                    return formData;
+                }
+                return [];
+            },
+
+            isSameDomain = function (url) {
+                if (protocolRegExp.test(url)) {
+                    var host = location.host,
+                        indexStart = location.protocol.length + 2,
+                        index = url.indexOf(host, indexStart),
+                        pathIndex = index + host.length;
+                    if ((index === indexStart || index === url.indexOf('@', indexStart) + 1) &&
+                            (url.length === pathIndex || $.inArray(url.charAt(pathIndex), ['/', '?', '#']) !== -1)) {
+                        return true;
+                    }
+                    return false;
+                }
+                return true;
+            },
+
+            nonMultipartUpload = function (file, xhr, sameDomain) {
+                if (sameDomain) {
+                    xhr.setRequestHeader('X-File-Name', unescape(encodeURIComponent(file.name)));
+                }
+                xhr.setRequestHeader('Content-Type', file.type);
+                xhr.send(file);
+            },
+
+            formDataUpload = function (files, xhr, settings) {
+                var formData = new FormData(),
+                    i;
+                $.each(getFormData(settings), function (index, field) {
+                    formData.append(field.name, field.value);
+                });
+                for (i = 0; i < files.length; i += 1) {
+                    formData.append(getFieldName(settings), files[i]);
+                }
+                xhr.send(formData);
+            },
+
+            loadFileContent = function (file, callBack) {
+                var fileReader = new FileReader();
+                fileReader.onload = function (e) {
+                    file.content = e.target.result;
+                    callBack();
+                };
+                fileReader.readAsBinaryString(file);
+            },
+
+            buildMultiPartFormData = function (boundary, files, filesFieldName, fields) {
+                var doubleDash = '--',
+                    crlf     = '\r\n',
+                    formData = '';
+                $.each(fields, function (index, field) {
+                    formData += doubleDash + boundary + crlf +
+                        'Content-Disposition: form-data; name="' +
+                        unescape(encodeURIComponent(field.name)) +
+                        '"' + crlf + crlf +
+                        unescape(encodeURIComponent(field.value)) + crlf;
+                });
+                $.each(files, function (index, file) {
+                    formData += doubleDash + boundary + crlf +
+                        'Content-Disposition: form-data; name="' +
+                        unescape(encodeURIComponent(filesFieldName)) +
+                        '"; filename="' + unescape(encodeURIComponent(file.name)) + '"' + crlf +
+                        'Content-Type: ' + file.type + crlf + crlf +
+                        file.content + crlf;
+                });
+                formData += doubleDash + boundary + doubleDash + crlf;
+                return formData;
+            },
+            
+            fileReaderUpload = function (files, xhr, settings) {
+                var boundary = '----MultiPartFormBoundary' + (new Date()).getTime(),
+                    loader,
+                    i;
+                xhr.setRequestHeader('Content-Type', 'multipart/form-data; boundary=' + boundary);
+                loader = new MultiLoader(function () {
+                    xhr.sendAsBinary(buildMultiPartFormData(
+                        boundary,
+                        files,
+                        getFieldName(settings),
+                        getFormData(settings)
+                    ));
+                }, files.length);
+                for (i = 0; i < files.length; i += 1) {
+                    loadFileContent(files[i], loader.complete);
+                }
+            },
+
+            upload = function (files, index, xhr, settings) {
+                var url = getUrl(settings),
+                    sameDomain = isSameDomain(url),
+                    filesToUpload;
+                initUploadEventHandlers(files, index, xhr, settings);
+                xhr.open(getMethod(settings), url, true);
+                if (sameDomain) {
+                    xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
+                } else if (settings.withCredentials) {
+                    xhr.withCredentials = true;
+                }
+                if (!settings.multipart) {
+                    nonMultipartUpload(files[index], xhr, sameDomain);
+                } else {
+                    if (typeof index === num) {
+                        filesToUpload = [files[index]];
+                    } else {
+                        filesToUpload = files;
+                    }
+                    if (typeof FormData !== undef) {
+                        formDataUpload(filesToUpload, xhr, settings);
+                    } else if (typeof FileReader !== undef) {
+                        fileReaderUpload(filesToUpload, xhr, settings);
+                    } else {
+                        $.error('Browser does neither support FormData nor FileReader interface');
+                    }
+                }
+            },
+
+            handleUpload = function (event, files, input, form, index) {
+                var xhr = new XMLHttpRequest(),
+                    uploadSettings = $.extend({}, settings);
+                uploadSettings.fileInput = input;
+                uploadSettings.uploadForm = form;
+                if (typeof uploadSettings.initUpload === func) {
+                    uploadSettings.initUpload(
+                        event,
+                        files,
+                        index,
+                        xhr,
+                        uploadSettings,
+                        function () {
+                            upload(files, index, xhr, uploadSettings);
+                        }
+                    );
+                } else {
+                    upload(files, index, xhr, uploadSettings);
+                }
+            },
+
+            handleFiles = function (event, files, input, form) {
+                var i;
+                if (settings.multiFileRequest) {
+                    handleUpload(event, files, input, form);
+                } else {
+                    for (i = 0; i < files.length; i += 1) {
+                        handleUpload(event, files, input, form, i);
+                    }
+                }
+            },
+
+            legacyUploadFormDataInit = function (input, form, settings) {
+                var formData = getFormData(settings);
+                form.find(':input').not(':disabled')
+                    .attr('disabled', true)
+                    .addClass(settings.namespace + '_disabled');
+                $.each(formData, function (index, field) {
+                    $('<input type="hidden"/>')
+                        .attr('name', field.name)
+                        .val(field.value)
+                        .addClass(settings.namespace + '_form_data')
+                        .appendTo(form);
+                });
+                input
+                    .attr('name', getFieldName(settings))
+                    .appendTo(form);
+            },
+
+            legacyUploadFormDataReset = function (input, form, settings) {
+                input.detach();
+                form.find('.' + settings.namespace + '_disabled')
+                    .removeAttr('disabled')
+                    .removeClass(settings.namespace + '_disabled');
+                form.find('.' + settings.namespace + '_form_data').remove();
+            },
+
+            legacyUpload = function (input, form, iframe, settings) {
+                var originalAction = form.attr('action'),
+                    originalMethod = form.attr('method'),
+                    originalTarget = form.attr('target');
+                iframe
+                    .unbind('abort')
+                    .bind('abort', function (e) {
+                        iframe.readyState = 0;
+                        // javascript:false as iframe src prevents warning popups on HTTPS in IE6
+                        // concat is used here to prevent the "Script URL" JSLint error:
+                        iframe.unbind('load').attr('src', 'javascript'.concat(':false;'));
+                        if (typeof settings.onAbort === func) {
+                            settings.onAbort(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
+                        }
+                    })
+                    .unbind('load')
+                    .bind('load', function (e) {
+                        iframe.readyState = 4;
+                        if (typeof settings.onLoad === func) {
+                            settings.onLoad(e, [{name: input.val(), type: null, size: null}], 0, iframe, settings);
+                        }
+                        // Fix for IE endless progress bar activity bug (happens on form submits to iframe targets):
+                        $('<iframe src="javascript:false;" style="display:none"></iframe>').appendTo(form).remove();
+                    });
+                form
+                    .attr('action', getUrl(settings))
+                    .attr('method', getMethod(settings))
+                    .attr('target', iframe.attr('name'));
+                legacyUploadFormDataInit(input, form, settings);
+                iframe.readyState = 2;
+                form.get(0).submit();
+                legacyUploadFormDataReset(input, form, settings);
+                form
+                    .attr('action', originalAction)
+                    .attr('method', originalMethod)
+                    .attr('target', originalTarget);
+            },
+
+            handleLegacyUpload = function (event, input, form) {
+                // javascript:false as iframe src prevents warning popups on HTTPS in IE6:
+                var iframe = $('<iframe src="javascript:false;" style="display:none" name="iframe_' +
+                    settings.namespace + '_' + (new Date()).getTime() + '"></iframe>'),
+                    uploadSettings = $.extend({}, settings);
+                uploadSettings.fileInput = input;
+                uploadSettings.uploadForm = form;
+                iframe.readyState = 0;
+                iframe.abort = function () {
+                    iframe.trigger('abort');
+                };
+                iframe.bind('load', function () {
+                    iframe.unbind('load');
+                    if (typeof uploadSettings.initUpload === func) {
+                        uploadSettings.initUpload(
+                            event,
+                            [{name: input.val(), type: null, size: null}],
+                            0,
+                            iframe,
+                            uploadSettings,
+                            function () {
+                                legacyUpload(input, form, iframe, uploadSettings);
+                            }
+                        );
+                    } else {
+                        legacyUpload(input, form, iframe, uploadSettings);
+                    }
+                }).appendTo(form);
+            },
+            
+            initUploadForm = function () {
+                uploadForm = (container.is('form') ? container : container.find('form'))
+                    .filter(settings.uploadFormFilter);
+            },
+            
+            initFileInput = function () {
+                fileInput = uploadForm.find('input:file')
+                    .filter(settings.fileInputFilter);
+            },
+            
+            replaceFileInput = function (input) {
+                var inputClone = input.clone(true);
+                $('<form/>').append(inputClone).get(0).reset();
+                input.after(inputClone).detach();
+                initFileInput();
+            };
+
+        this.onDocumentDragOver = function (e) {
+            if (typeof settings.onDocumentDragOver === func &&
+                    settings.onDocumentDragOver(e) === false) {
+                return false;
+            }
+            e.preventDefault();
+        };
+        
+        this.onDocumentDrop = function (e) {
+            if (typeof settings.onDocumentDrop === func &&
+                    settings.onDocumentDrop(e) === false) {
+                return false;
+            }
+            e.preventDefault();
+        };
+
+        this.onDragOver = function (e) {
+            if (typeof settings.onDragOver === func &&
+                    settings.onDragOver(e) === false) {
+                return false;
+            }
+            var dataTransfer = e.originalEvent.dataTransfer;
+            if (dataTransfer) {
+                dataTransfer.dropEffect = dataTransfer.effectAllowed = 'copy';
+            }
+            e.preventDefault();
+        };
+
+        this.onDrop = function (e) {
+            if (typeof settings.onDrop === func &&
+                    settings.onDrop(e) === false) {
+                return false;
+            }
+            var dataTransfer = e.originalEvent.dataTransfer;
+            if (dataTransfer && dataTransfer.files && isXHRUploadCapable()) {
+                handleFiles(e, dataTransfer.files);
+            }
+            e.preventDefault();
+        };
+        
+        this.onChange = function (e) {
+            if (typeof settings.onChange === func &&
+                    settings.onChange(e) === false) {
+                return false;
+            }
+            var input = $(e.target),
+                form = $(e.target.form);
+            if (form.length === 1) {
+                input.data(defaultNamespace + '_form', form);
+                replaceFileInput(input);
+            } else {
+                form = input.data(defaultNamespace + '_form');
+            }
+            if (!settings.forceIframeUpload && e.target.files && isXHRUploadCapable()) {
+                handleFiles(e, e.target.files, input, form);
+            } else {
+                handleLegacyUpload(e, input, form);
+            }
+        };
+
+        this.init = function (options) {
+            if (options) {
+                $.extend(settings, options);
+                optionsReference = options;
+            }
+            initUploadForm();
+            initFileInput();
+            if (container.data(settings.namespace)) {
+                $.error('FileUpload with namespace "' + settings.namespace + '" already assigned to this element');
+                return;
+            }
+            container
+                .data(settings.namespace, fileUpload)
+                .addClass(settings.cssClass);
+            settings.dropZone.not(container).addClass(settings.cssClass);
+            initEventHandlers();
+        };
+
+        this.options = function (options) {
+            var oldCssClass,
+                oldDropZone,
+                uploadFormFilterUpdate,
+                fileInputFilterUpdate;
+            if (typeof options === undef) {
+                return $.extend({}, settings);
+            }
+            if (optionsReference) {
+                $.extend(optionsReference, options);
+            }
+            removeEventHandlers();
+            $.each(options, function (name, value) {
+                switch (name) {
+                case 'namespace':
+                    $.error('The FileUpload namespace cannot be updated.');
+                    return;
+                case 'uploadFormFilter':
+                    uploadFormFilterUpdate = true;
+                    fileInputFilterUpdate = true;
+                    break;
+                case 'fileInputFilter':
+                    fileInputFilterUpdate = true;
+                    break;
+                case 'cssClass':
+                    oldCssClass = settings.cssClass;
+                    break;
+                case 'dropZone':
+                    oldDropZone = settings.dropZone;
+                    break;
+                }
+                settings[name] = value;
+            });
+            if (uploadFormFilterUpdate) {
+                initUploadForm();
+            }
+            if (fileInputFilterUpdate) {
+                initFileInput();
+            }
+            if (typeof oldCssClass !== undef) {
+                container
+                    .removeClass(oldCssClass)
+                    .addClass(settings.cssClass);
+                (oldDropZone ? oldDropZone : settings.dropZone).not(container)
+                    .removeClass(oldCssClass);
+                settings.dropZone.not(container).addClass(settings.cssClass);
+            } else if (oldDropZone) {
+                oldDropZone.not(container).removeClass(settings.cssClass);
+                settings.dropZone.not(container).addClass(settings.cssClass);
+            }
+            initEventHandlers();
+        };
+        
+        this.option = function (name, value) {
+            var options;
+            if (typeof value === undef) {
+                return settings[name];
+            }
+            options = {};
+            options[name] = value;
+            fileUpload.options(options);
+        };
+        
+        this.destroy = function () {
+            removeEventHandlers();
+            container
+                .removeData(settings.namespace)
+                .removeClass(settings.cssClass);
+            settings.dropZone.not(container).removeClass(settings.cssClass);
+        };
+    };
+
+    methods = {
+        init : function (options) {
+            return this.each(function () {
+                (new FileUpload($(this))).init(options);
+            });
+        },
+        
+        option: function (option, value, namespace) {
+            namespace = namespace ? namespace : defaultNamespace;
+            var fileUpload = $(this).data(namespace);
+            if (fileUpload) {
+                if (typeof option === 'string') {
+                    return fileUpload.option(option, value);
+                }
+                return fileUpload.options(option);
+            } else {
+                $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
+            }
+        },
+                
+        destroy : function (namespace) {
+            namespace = namespace ? namespace : defaultNamespace;
+            return this.each(function () {
+                var fileUpload = $(this).data(namespace);
+                if (fileUpload) {
+                    fileUpload.destroy();
+                } else {
+                    $.error('No FileUpload with namespace "' + namespace + '" assigned to this element');
+                }
+            });
+
+        }
+    };
+    
+    $.fn.fileUpload = function (method) {
+        if (methods[method]) {
+            return methods[method].apply(this, Array.prototype.slice.call(arguments, 1));
+        } else if (typeof method === 'object' || !method) {
+            return methods.init.apply(this, arguments);
+        } else {
+            $.error('Method ' + method + ' does not exist on jQuery.fileUpload');
+        }
+    };
+    
+}(jQuery));

BIN
main/inc/lib/javascript/jquery-upload/pbar-ani.gif


+ 5 - 5
main/inc/lib/main_api.lib.php

@@ -4839,12 +4839,12 @@ function api_get_jquery_libraries_js($libraries, $include_jquery = true) {
         $js .= '<script src="'.$js_path.'jqgrid/js/i18n/grid.locale-'.$languaje.'.js" type="text/javascript" language="javascript"></script>'; 
         $js .= '<script src="'.$js_path.'jqgrid/js/jquery.jqGrid.min.js" type="text/javascript" language="javascript"></script>';
     }
-    
-    
-    
-    if (in_array('jquery-ui',$libraries)) {
+        
+    if (in_array('jquery-upload',$libraries)) {
         //Adding default CSS changes of the jquery-ui themes for Chamilo in order to preserve the original jquery-ui css
-        $js .= '<link rel="stylesheet" href="'.$js_path.'jquery-ui/default.css" type="text/css">';
+        $js .= '<script src="'.$js_path.'jquery-upload/jquery.fileupload.js" type="text/javascript" language="javascript"></script>'; 
+        $js .= '<script src="'.$js_path.'jquery-upload/jquery.fileupload-ui.js" type="text/javascript" language="javascript"></script>';
+        $js .= '<link rel="stylesheet" href="'.$js_path.'jquery-upload/jquery.fileupload-ui.css" type="text/css">';        
     } 
     return $js;	
 }