--- inc/imce.page.inc 2010-11-01 09:21:41.000000000 -0400 +++ inc/imce.page.inc 2010-10-28 16:09:04.000000000 -0400 @@ -1,1103 +1,1104 @@ - &$imce); - $forms = ''; - - if (!$imce['error']) { - //process file upload. - if (imce_perm_exists($imce, 'upload')) { - $forms .= drupal_get_form('imce_upload_form', $imce_ref); - } - //process file operations. - $forms .= drupal_get_form('imce_fileop_form', $imce_ref); - } - - //run custom content functions. possible to insert extra forms. content is invisible when js is enabled. - foreach (variable_get('imce_custom_content', array()) as $func => $state) { - if ($state && function_exists($func) && $output = $func($imce)) { - $forms .= $output; - } - } - - $content = theme('imce_content', imce_create_tree($imce), $forms, $imce_ref); - - //make necessary changes for js conversion - $imce['dir'] = str_replace('%2F', '/', rawurlencode($imce['dir'])); - unset($imce['files'], $imce['name'], $imce['directories'], $imce['subdirectories'], $imce['filesize'], $imce['quota'], $imce['tuquota'], $imce['thumbnails'], $imce['uid'], $imce['usertab']); - - drupal_add_js($imce_ref, 'setting'); - - return $content; -} - -/** - * Ajax operations. q=imce&jsop={op} - */ -function imce_js($user, $jsop = '') { - $response = array(); - - //data - if ($imce = imce_initiate_profile($user)) { - imce_process_profile($imce); - if (!$imce['error']) { - module_load_include('inc', 'imce', 'inc/imce.js'); - if (function_exists($func = 'imce_js_'. $jsop)) { - $response['data'] = $func($imce); - } - } - } - //messages - $response['messages'] = drupal_get_messages(); - - //disable devel log. - $GLOBALS['devel_shutdown'] = FALSE; - //for upload we must return plain text header. - drupal_set_header('Content-Type: text/'. ($jsop == 'upload' ? 'html' : 'javascript') .'; charset=utf-8'); - print drupal_to_js($response); - exit(); -} - -/** - * Upload form. - */ -function imce_upload_form(&$form_state, $ref) { - $imce =& $ref['imce']; - $form['imce'] = array( - '#type' => 'file', - '#title' => t('File'), - '#size' => 30, - ); - if (!empty($imce['thumbnails'])) { - $form['thumbnails'] = array( - '#type' => 'checkboxes', - '#title' => t('Create thumbnails'), - '#options' => imce_thumbnail_options($imce['thumbnails']), - ); - } - $form['upload'] = array( - '#type' => 'submit', - '#value' => t('Upload'), - '#submit' => $imce['perm']['upload'] ? array('imce_upload_submit') : NULL, - ); - $form = array('fset_upload' => array('#type' => 'fieldset', '#title' => t('Upload file')) + $form); - $form['#attributes']['enctype'] = 'multipart/form-data'; - $form['#action'] = $imce['url']; - return $form; -} - -/** - * File operations form. - */ -function imce_fileop_form(&$form_state, $ref) { - $imce =& $ref['imce']; - $form['filenames'] = array( - '#type' => 'textfield', - '#title' => t('Selected files'), - '#maxlength' => $imce['filenum'] ? $imce['filenum']*255 : NULL, - ); - - //thumbnail - if (!empty($imce['thumbnails']) && imce_perm_exists($imce, 'thumb')) { - $form['fset_thumb'] = array( - '#type' => 'fieldset', - '#title' => t('Thumbnails'), - ) + imce_thumb_form($imce); - } - - //delete - if (imce_perm_exists($imce, 'delete')) { - $form['fset_delete'] = array( - '#type' => 'fieldset', - '#title' => t('Delete'), - ) + imce_delete_form($imce); - } - - //resize - if (imce_perm_exists($imce, 'resize')) { - $form['fset_resize'] = array( - '#type' => 'fieldset', - '#title' => t('Resize'), - ) + imce_resize_form($imce); - } - - $form['#action'] = $imce['url']; - return $form; -} - -/** - * Thumbnail form. - */ -function imce_thumb_form(&$imce) { - $form['thumbnails'] = array( - '#type' => 'checkboxes', - '#title' => t('Thumbnails'), - '#options' => imce_thumbnail_options($imce['thumbnails']), - ); - $form['thumb'] = array( - '#type' => 'submit', - '#value' => t('Create thumbnails'), - '#submit' => $imce['perm']['thumb'] ? array('imce_thumb_submit') : NULL, - ); - return $form; -} - -/** - * Delete form. - */ -function imce_delete_form(&$imce) { - $form['delete'] = array( - '#type' => 'submit', - '#value' => t('Delete'), - '#submit' => $imce['perm']['delete'] ? array('imce_delete_submit') : NULL, - ); - return $form; -} - -/** - * Resizing form. - */ -function imce_resize_form(&$imce) { - $form['width'] = array( - '#type' => 'textfield', - '#title' => t('Width x Height'), - '#size' => 5, - '#maxlength' => 4, - '#prefix' => '
', - ); - $form['height'] = array( - '#type' => 'textfield', - '#size' => 5, - '#maxlength' => 4, - '#prefix' => 'x', - ); - $form['resize'] = array( - '#type' => 'submit', - '#value' => t('Resize'), - '#submit' => $imce['perm']['resize'] ? array('imce_resize_submit') : NULL,//permission for submission - '#suffix' => '
', - ); - $form['copy'] = array( - '#type' => 'checkbox', - '#title' => t('Create a new image'), - '#default_value' => 1, - ); - return $form; -} - -/** - * Validate file operations form. - */ -function imce_fileop_form_validate($form, &$form_state) { - $imce =& $form['#parameters'][2]['imce']; - - //check if the filenames is empty - if ($form_state['values']['filenames'] == '') { - return form_error($form['filenames'], t('Please select a file.')); - } - - //filenames come seperated by colon - $filenames = explode(':', $form_state['values']['filenames']); - $cnt = count($filenames); - //check the number of files. - if ($imce['filenum'] && $cnt > $imce['filenum']) { - return form_error($form['filenames'], t('You are not allowed to operate on more than %num files.', array('%num' => $imce['filenum']))); - } - - //check if there is any illegal choice - for ($i = 0; $i < $cnt; $i++) { - $filenames[$i] = $filename = rawurldecode($filenames[$i]); - if (!isset($imce['files'][$filename])) { - watchdog('imce', 'Illegal choice %choice in !name element.', array('%choice' => $filename, '!name' => t('directory (%dir)', array('%dir' => file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir'])))), WATCHDOG_ERROR); - return form_error($form['filenames'], t('An illegal choice has been detected. Please contact the site administrator.')); - } - } - - $form_state['values']['filenames'] = $filenames; -} - -/** - * Submit upload form. - */ -function imce_upload_submit($form, &$form_state) { - $form_state['redirect'] = FALSE; - $imce =& $form['#parameters'][2]['imce']; - $validators = array('imce_validate_all' => array(&$imce)); - $dirpath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']); - - //save uploaded file. - $replace = variable_get('imce_settings_replace', FILE_EXISTS_RENAME); - if ($file = file_save_upload('imce', $validators, $dirpath, $replace)) { - - //core bug #203204. - @chmod($file->filepath, 0664); - - //core bug #54223. - if ($replace == FILE_EXISTS_RENAME) { - $name = basename($file->filepath); - if ($name != $file->filename) { - $file->filename = $name; - drupal_set_message(t('The file has been renamed to %filename.', array('%filename' => $file->filename))); - } - } - elseif ($replace == FILE_EXISTS_REPLACE) {//check duplicates - if ($_file = db_fetch_object(db_query("SELECT fid FROM {files} WHERE filepath = '%s' AND fid <> %d", $file->filepath, $file->fid))) { - db_query("DELETE FROM {files} WHERE fid = %d", $file->fid); - $file->fid = $_file->fid; - } - } - - $file->uid = $imce['uid'];//global user may not be the owner. - $file->status = FILE_STATUS_PERMANENT;//make permanent - drupal_write_record('files', $file, array('fid'));//update - imce_file_register($file); - drupal_set_message(t('%filename has been uploaded.', array('%filename' => $file->filename))); - - //update file list - $img = imce_image_info($file->filepath); - $file->width = $img ? $img['width'] : 0; - $file->height = $img ? $img['height'] : 0; - imce_add_file($file, $imce); - - //create thumbnails - if (isset($form_state['values']['thumbnails']) && $img) { - imce_create_thumbnails($file->filename, $imce, $form_state['values']['thumbnails']); - } - } - else { - drupal_set_message(t('Upload failed.'), 'error'); - } -} - -/** - * Submit thumbnail form. - */ -function imce_thumb_submit($form, &$form_state) { - $form_state['redirect'] = FALSE; - $imce =& $form['#parameters'][2]['imce']; - //create thumbnails - imce_process_files($form_state['values']['filenames'], $imce, 'imce_create_thumbnails', array($form_state['values']['thumbnails'])); -} - -/** - * Submit delete form. - */ -function imce_delete_submit($form, &$form_state) { - $form_state['redirect'] = FALSE; - $imce =& $form['#parameters'][2]['imce']; - - $deleted = imce_process_files($form_state['values']['filenames'], $imce, 'imce_delete_file'); - - if (!empty($deleted)) { - drupal_set_message(t('File deletion successful: %files.', array('%files' => utf8_encode(implode(', ', $deleted))))); - } - -} - -/** - * Submit resize form. - */ -function imce_resize_submit($form, &$form_state) { - $form_state['redirect'] = FALSE; - $imce =& $form['#parameters'][2]['imce']; - - //check dimensions - $width = (int) $form_state['values']['width']; - $height = (int) $form_state['values']['height']; - list($maxw, $maxh) = explode('x', $imce['dimensions']); - if ($width < 1 || $height < 1 || ($maxw && ($width > $maxw || $height > $maxh))) { - drupal_set_message(t('Please specify dimensions within the allowed range that is from 1x1 to @dimensions.', array('@dimensions' => $imce['dimensions'] ? $imce['dimensions'] : t('unlimited'))), 'error'); - return; - } - - $resized = imce_process_files($form_state['values']['filenames'], $imce, 'imce_resize_image', array($width, $height, $form_state['values']['copy'])); - - if (!empty($resized)) { - drupal_set_message(t('File resizing successful: %files.', array('%files' => utf8_encode(implode(', ', $resized))))); - } - -} - -/** - * Do batch operations on files. - * Used by delete, resize, create thumbnail submissions. - */ -function imce_process_files($filenames, &$imce, $function, $args = array()) { - $args = array_merge(array('', &$imce), $args); - $processed = array(); - - foreach ($filenames as $filename) { - $args[0] = $filename; - if (call_user_func_array($function, $args)) { - $processed[] = $filename; - } - } - - return $processed; -} - -/** - * Delete a file in the file list. - */ -function imce_delete_file($filename, &$imce) { - $filepath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']) .'/'. $filename; - if (!imce_delete_filepath($filepath)) { - return FALSE; - } - imce_remove_file($filename, $imce); - return TRUE; -} - -/** - * Delete a file by path. - */ -function imce_delete_filepath($filepath) { - $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE filepath = '%s'", $filepath)); - - //file exists in database - if ($file) { - //prevent imce returning ref count - $file->imce_noref = TRUE; - //check references - $refs = array_filter(module_invoke_all('file_references', $file)); - //file is in use - if (!empty($refs)) { - drupal_set_message(t('%filename is in use by another application.', array('%filename' => $file->filename)), 'error'); - return FALSE; - } - //prepare deletion - module_invoke_all('file_delete', $file); - if (!file_delete($file->filepath)) { - return FALSE; - } - db_query('DELETE FROM {files} WHERE fid = %d', $file->fid); - } - //not in db. probably loaded via ftp. - elseif (!file_delete($filepath)) { - return FALSE; - } - - return TRUE; -} - -/** - * Create all selected thumbnails. - */ -function imce_create_thumbnails($filename, &$imce, $values) { - $created = array(); - foreach ($imce['thumbnails'] as $thumbnail) { - if ($values[$thumbnail['name']] && imce_create_thumbnail($filename, $imce, $thumbnail)) { - $created[] = $thumbnail['name']; - } - } - if (!empty($created)) { - drupal_set_message(t('Thumbnail creation (%thumbnames) successful for %filename.', array('%thumbnames' => implode(', ', $created), '%filename' => utf8_encode($filename)))); - } - return $created; -} - -/** - * Create a thumbnail. - */ -function imce_create_thumbnail($filename, &$imce, $thumbnail) { - //generate thumbnail name - $name = $thumbnail['prefix']; - if ($thumbnail['suffix'] != '' && $dot = strrpos($filename, '.')) { - $name .= substr($filename, 0, $dot); - $name .= $thumbnail['suffix']; - $name .= substr($filename, $dot); - } - else { - $name .= $filename; - } - //scale the image - list($width, $height) = explode('x', $thumbnail['dimensions']); - return imce_resize_image($filename, $imce, $width, $height, TRUE, $name, variable_get('imce_settings_thumb_method', 'scale_and_crop')); -} - -/** - * Resize an image in the file list. Also used for thumbnail creation. - */ -function imce_resize_image($filename, &$imce, $width, $height, $copy = TRUE, $dest = FALSE, $op = 'resize') { - $dirpath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']); - $filepath = $dirpath .'/'. $filename; - - //check if the file is an image - if (!$imce['files'][$filename]['width'] || !$img = imce_image_info($filepath)) { - drupal_set_message(t('%filename is not an image.', array('%filename' => utf8_encode($filename))), 'error', FALSE); - return FALSE; - } - - if (substr($op, 0, 5) == 'scale' && !($width < $img['width'] || $height < $img['height'])) { - drupal_set_message(t('Scaling up is not allowed.'), 'error', FALSE); - return FALSE; - } - - //create file object - $file = new stdClass(); - $file->filepath = $dirpath .'/'. $dest; - if (!$dest || $dest == $filename) { - $file->filepath = $copy ? file_create_filename($filename, $dirpath) : $filepath; - } - $file->filename = basename($file->filepath); - - //check if a file having the same properties exists already. - if (isset($imce['files'][$file->filename])) { - if (($f = $imce['files'][$file->filename]) && $f['width'] == $width && $f['height'] == $height) { - drupal_set_message(t('%filename(%dimensions) already exists.', array('%filename' => utf8_encode($file->filename), '%dimensions' => $width .'x'. $height)), 'error'); - return FALSE; - } - } - - //validate file name - $errors = file_validate_name_length($file); - if (!empty($errors)) { - drupal_set_message($errors[0], 'error'); - return FALSE; - } - - //resize image to a temp file - $temp = tempnam(realpath(file_directory_temp()), 'imc'); - register_shutdown_function('file_delete', $temp); - $function = 'image_'. $op; - if (!$function($filepath, $temp, $width, $height)) { - drupal_set_message(t('%filename cannot be resized to %dimensions', array('%filename' => utf8_encode($filename), '%dimensions' => $width .'x'. $height)), 'error', FALSE); - return FALSE; - } - - //validate quota - $file->filesize = filesize($temp); - $overwrite = $file->filename == $filename; - if (!imce_validate_quotas($file, $imce, $overwrite ? -$imce['files'][$filename]['size'] : 0)) { - return FALSE; - } - - //copy from temp to filepath - if (!@copy($temp, $file->filepath)) { - drupal_set_message(t('The selected file %file could not be copied.', array('%file' => utf8_encode($file->filename))), 'error', FALSE); - return FALSE; - } - @chmod($file->filepath, 0664); - - //build the rest of the file object - $file->uid = $imce['uid']; - $file->filemime = $img['mime']; - $file->status = FILE_STATUS_PERMANENT; - $file->timestamp = time(); - - //if we are overwriting the file and it is already in database. - $update = array(); - if ($overwrite && $_file = db_fetch_object(db_query("SELECT f.* FROM {files} f WHERE f.filepath = '%s'", $file->filepath))) { - $file->fid = $_file->fid; - $file->uid = $_file->uid; - $update[] = 'fid'; - } - - //save the file - drupal_write_record('files', $file, $update); - imce_file_register($file); - - //update file list - //if the file was scaled get the new dimensions - if ($op == 'scale') { - $img = imce_image_info($file->filepath); - $width = $img['width']; - $height = $img['height']; - } - $file->width = $width; - $file->height = $height; - imce_add_file($file, $imce); - - return $file; -} - -/** - * Add a new file to the file list. - */ -function imce_add_file($file, &$imce) { - $imce['dirsize'] += $file->filesize; - if (isset($imce['files'][$file->filename])) { - $imce['dirsize'] -= $imce['files'][$file->filename]['size']; - } - $imce['files'][$file->filename] = array( - 'name' => $file->filename, - 'size' => $file->filesize, - 'width' => $file->width, - 'height' => $file->height, - 'date' => $file->timestamp - ); - if (isset($_GET['jsop'])) { - $add = $imce['files'][$file->filename]; - $add['name'] = rawurlencode($file->filename); - $add['fsize'] = format_size($file->filesize); - $add['fdate'] = format_date($file->timestamp, 'small'); - $add['id'] = $file->fid; - $imce['added'][] = $add; - } -} - -/** - * Remove a file from the file list. - */ -function imce_remove_file($filename, &$imce) { - if (isset($imce['files'][$filename])) { - $imce['dirsize'] -= $imce['files'][$filename]['size']; - unset($imce['files'][$filename]); - if (isset($_GET['jsop'])) { - $imce['removed'][] = rawurlencode($filename); - } - } -} - -/** - * Validate uploaded file. - */ -function imce_validate_all(&$file, $imce) { - - //fix FILE_EXISTS_ERROR bug. core bug #54223. - if (!$file->destination && variable_get('imce_settings_replace', FILE_EXISTS_RENAME) == FILE_EXISTS_ERROR) { - return array(t('File browser is set to reject the upload of existing files.')); - } - - //validate image resolution only if filesize validation passes. - //because user might have uploaded a very big image - //and scaling it may exploit system memory. - $errors = imce_validate_filesize($file, $imce['filesize']); - //image resolution validation - if (empty($errors)) { - $errors = array_merge($errors, file_validate_image_resolution($file, $imce['dimensions'])); - } - //directory quota validation - if ($imce['quota']) { - $errors = array_merge($errors, imce_validate_quota($file, $imce['quota'], $imce['dirsize'])); - } - //file extension validation - if ($imce['extensions'] != '*') { - $errors = array_merge($errors, file_validate_extensions($file, $imce['extensions'])); - } - //user quota validation. check it if no errors were thrown. - if (empty($errors) && $imce['tuquota']) { - $errors = imce_validate_tuquota($file, $imce['tuquota'], file_space_used($imce['uid'])); - } - return $errors; -} - -/** - * Validate filesize for maximum allowed file size. - */ -function imce_validate_filesize($file, $maxsize = 0) { - $errors = array(); - if ($maxsize && $file->filesize > $maxsize) { - $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($maxsize))); - } - return $errors; -} - -/** - * Validate filesize for directory quota. - */ -function imce_validate_quota($file, $quota = 0, $currentsize = 0) { - $errors = array(); - if ($quota && ($currentsize + $file->filesize) > $quota) { - $errors[] = t('%filename is %filesize which would exceed your directory quota. You are currently using %size of %total_quota.', array('%size' => format_size($currentsize), '%total_quota' => format_size($quota), '%filesize' => format_size($file->filesize), '%filename' => utf8_encode($file->filename))); - } - return $errors; -} - -/** - * Validate filesize for total user quota. - */ -function imce_validate_tuquota($file, $quota = 0, $currentsize = 0) { - $errors = array(); - if ($quota && ($currentsize + $file->filesize) > $quota) { - $errors[] = t('%filename is %filesize which would exceed your total user quota. You are currently using %size of %total_quota.', array('%size' => format_size($currentsize), '%total_quota' => format_size($quota), '%filesize' => format_size($file->filesize), '%filename' => utf8_encode($file->filename))); - } - return $errors; -} - -/** - * Validate both directory and total user quota. Returns true/false not errors. - */ -function imce_validate_quotas($file, &$imce, $add = 0) { - $errors = imce_validate_quota($file, $imce['quota'], $imce['dirsize'] + $add); - if (empty($errors) && $imce['tuquota']) { - $errors = imce_validate_tuquota($file, $imce['tuquota'], file_space_used($imce['uid']) + $add); - } - if (!empty($errors)) { - drupal_set_message($errors[0], 'error'); - return FALSE; - } - return TRUE; -} - -/** - * Check if the file is an image and return info. - */ -function imce_image_info($file) { - if (is_file($file) && ($dot = strrpos($file, '.')) && in_array(strtolower(substr($file, $dot+1)), array('jpg', 'jpeg', 'gif', 'png')) && ($info = @getimagesize($file)) && in_array($info[2], array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG)) ) { - return array('width' => $info[0], 'height' => $info[1], 'type' => $info[2], 'mime' => $info['mime']); - } - return FALSE; -} - -/** - * Return thumbnails as options to be used in upload form. - */ -function imce_thumbnail_options($thumbs = array()) { - $options = array(); - foreach ($thumbs as $thumb) { - $options[$thumb['name']] = $thumb['name'] .' ('. $thumb['dimensions'] .')'; - } - return $options; -} - -/** - * Initiate and return configuration profile for the $user. - */ -function imce_initiate_profile($user) { - - //check user profile and translate tokens in directory paths and evaluate php paths. - if ($imce = imce_user_profile($user)) { - imce_process_directories($imce, $user); - if (!empty($imce['directories'])) { - $imce['uid'] = (int) $user->uid; - $imce['url'] = url($_GET['q']); - $imce['clean'] = variable_get('clean_url', 0) == 1; - $imce['absurls'] = variable_get('imce_settings_absurls', 0) == 1; - $imce['furl'] = file_create_url(''); - $imce['filesize'] *= 1048576;//convert from Mb to byte - $imce['quota'] *= 1048576; - $imce['tuquota'] *= 1048576; - $imce['filenum'] = (int) $imce['filenum']; - //check and set the active directory - if ($info = imce_working_directory($imce)) { - $imce['direct'] = isset($imce['directories'][$info['name']]); - $imce['directories'][$info['name']] = $info; - $imce['dir'] = $info['name']; - $imce['perm'] = $info;//copy permissions of the active directory. - unset($imce['perm']['name']); - } - else { - drupal_set_message(t('Unable to get a working directory for the file browser!'), 'error'); - $imce['dir'] = FALSE; - $imce['error'] = TRUE; - } - return $imce; - } - drupal_set_message(t('There is no valid directory specified for the file browser!'), 'error'); - } - else { - drupal_set_message(t('You do not have access to any configuration profile to use the file browser!'), 'error'); - } - - return FALSE; -} - -/** - * Get files and folders of the actve directory. Do custom processing. - */ -function imce_process_profile(&$imce) { - //get directory content. do a custom scan if it is set - $scan = ($scan = variable_get('imce_custom_scan', '')) && function_exists($scan) ? $scan : 'imce_scan_directory'; - $imce += $scan($imce['dir'], $imce); - - //run custom process functions - foreach (variable_get('imce_custom_process', array()) as $func => $state) { - if ($state && function_exists($func)) { - $func($imce); - } - } - - //set subdirectories - if (!$imce['error'] && !imce_subdirectories_accessible($imce)) { - $imce['subdirectories'] = array(); - } -} - -/** - * Translate tokens and evaluate php in directory names. - * Convert directories into an associative array (dirname => info) - */ -function imce_process_directories(&$imce, $user) { - $directories = $imce['directories']; - $paths = array(); - $translate = array('%uid' => $user->uid); - - foreach ($directories as $directory) { - if (substr($directory['name'], 0, 4) == 'php:') { - $directory['name'] = eval(substr($directory['name'], 4)); - //php may return an array of directories - if (is_array($directory['name'])) { - foreach ($directory['name'] as $name) { - $paths[$name] = array('name' => $name) + $directory; - } - continue; - } - } - else { - $directory['name'] = strtr($directory['name'], $translate); - } - if ($directory['name']) { - $paths[$directory['name']] = $directory; - } - } - - $imce['directories'] = $paths; -} - -/** - * Return an avaliable directory for the profile. - */ -function imce_working_directory(&$imce) { - //Do not use session if there is only one directory assigned. - $sess = TRUE; - if (count($imce['directories']) < 2) { - $perms = reset($imce['directories']); - if (!isset($perms['subnav']) || !$perms['subnav']) { - $sess = FALSE; - } - } - //check GET. - if (isset($_GET['dir'])) { - if ($info = imce_directory_info($_GET['dir'], $imce)) { - if (imce_check_directory($_GET['dir'], $imce)) { - if ($sess) { - $_SESSION['imce_directory'] = rawurlencode($info['name']); - } - } - else { - $info = FALSE; - } - } - else { - imce_inaccessible_directory($_GET['dir'], $imce); - } - return $info; - } - - //check session - if ($sess && isset($_SESSION['imce_directory'])) { - $dirname = rawurldecode($_SESSION['imce_directory']); - if ($info = imce_directory_info($dirname, $imce)) { - if (imce_check_directory($dirname, $imce)) { - return $info; - } - } - } - - //or the whole list. - foreach ($imce['directories'] as $dirname => $info) { - if (imce_check_directory($dirname, $imce)) { - if ($sess) { - $_SESSION['imce_directory'] = rawurlencode($dirname); - } - return $info; - } - } - - return FALSE; -} - -/** - * Create a writable directory(any level) under file system directory. - */ -function imce_check_directory($dirname, $imce = array()) { - - $root = file_directory_path(); - $dirpath = $root .'/'. $dirname; - - if (!file_check_directory($dirpath)) {//directory does not exist. try to create it. - $path = $root; - foreach (explode('/', $dirname) as $arg) { - $path .= '/'. $arg; - if (!file_check_location($path, $root) || !file_check_directory($path, FILE_CREATE_DIRECTORY)) { - return imce_inaccessible_directory($dirname, $imce); - } - } - } - elseif (!file_check_location($dirpath, $root)) {//directory exists outside of root. - return imce_inaccessible_directory($dirname, $imce); - } - - return TRUE; -} - -/** - * Generate and log a directory access error. - */ -function imce_inaccessible_directory($dirname, $imce = array()) { - if (is_string($dirname)) { - $dirname = utf8_encode($dirname); - drupal_set_message(t('Directory %dirname is not accessible.', array('%dirname' => $dirname)), 'error'); - watchdog('imce', 'Access to %directory was denied.', array('%directory' => $dirname), WATCHDOG_ERROR); - } - return FALSE; -} - -/** - * Return the permissions for a directory that is accessed directly or indirectly. - * A child of a predefined directory in the directory list takes its parent's properties. - * If it has multiple parents, it gets the properties of the latter in the list. - */ -function imce_directory_info($dirname, $imce) { - - if (isset($imce['directories'][$dirname])) { - return $imce['directories'][$dirname]; - } - - $info = FALSE; - $root = file_directory_path(); - $dirpath = $root .'/'. $dirname; - if (imce_reg_dir($dirname) && file_check_directory($dirpath)) { - foreach ($imce['directories'] as $name => $prop) { - if ($prop['subnav'] && file_check_location($dirpath, $root .'/'. $name)) { - $info = $prop; - $info['name'] = $dirname; - } - } - } - - return $info; -} - -/** - * Detect if the subdirectories are accessible through any directory(not just the current one) in the list. - */ -function imce_subdirectories_accessible(&$imce) { - - if (!empty($imce['subdirectories'])) { - $root = file_directory_path() .'/'; - //checking only the first one is sufficient. - $dirname = ($imce['dir'] == '.' ? '' : $imce['dir'] .'/') . $imce['subdirectories'][0]; - $dirpath = $root . $dirname; - - //check if any setting is applicable for this subdirectory through any directory in the list. - foreach ($imce['directories'] as $name => $info) { - if ($info['subnav'] && $dirname != $name && file_check_location($dirpath, $root . $name)) { - return TRUE; - } - } - } - - return FALSE; -} - -/** - * Check if a permission is given to at least one directory in the list. - */ -function imce_perm_exists(&$imce, $perm) { - static $perms = array(); - - if (isset($perms[$perm])) { - return $perms[$perm]; - } - - if (isset($imce['perm'][$perm]) && $imce['perm'][$perm]) { - return $perms[$perm] = TRUE; - } - - foreach ($imce['directories'] as $name => $info) { - if (isset($info[$perm]) && $info[$perm]) { - return $perms[$perm] = TRUE; - } - } - - return $perms[$perm] = FALSE; -} - -/** - * Scan directory and return file list, subdirectories, and total size. - */ -function imce_scan_directory($dirname, $imce = array()) { - - $directory = array('dirsize' => 0, 'files' => array(), 'subdirectories' => array(), 'error' => FALSE); - $dirpath = file_directory_path() .'/'. $dirname; - - if (!is_string($dirname) || $dirname == '' || !$handle = opendir($dirpath)) { - imce_inaccessible_directory($dirname, $imce); - $directory['error'] = TRUE; - return $directory; - } - - $exclude = array('.' => 1, '..' => 1, 'CVS' => 1, '.svn' => 1, '.htaccess' => 1); - while (($file = readdir($handle)) !== FALSE) { - if (isset($exclude[$file])) { - continue; - } - - $path = $dirpath .'/'. $file; - - if (is_dir($path)) { - $directory['subdirectories'][] = $file; - continue; - } - - $width = $height = 0; - if ($img = imce_image_info($path)) { - $width = $img['width']; - $height = $img['height']; - } - $size = filesize($path); - $date = filemtime($path); - $directory['files'][$file] = array( - 'name' => $file, - 'size' => $size, - 'width' => $width, - 'height' => $height, - 'date' => $date - ); - $directory['dirsize'] += $size; - } - - closedir($handle); - sort($directory['subdirectories']); - return $directory; -} - -/** - * Create directory tree. - */ -function imce_create_tree(&$imce) { - $paths = array(); - //rearrange paths as arg0=>arg1=>... - foreach ($imce['directories'] as $path => $arr) { - $tmp =& $paths; - if ($path != '.') { - $args = explode('/', $path); - foreach ($args as $arg) { - if (!isset($tmp[$arg])) { - $tmp[$arg] = array(); - } - $tmp =& $tmp[$arg]; - } - $tmp[':access:'] = TRUE; - } - if ("$path" == $imce['dir']) { - $tmp[':active:'] = TRUE; - foreach ($imce['subdirectories'] as $arg) { - $tmp[$arg][':access:'] = TRUE; - } - } - } - //set root branch - $root = theme('imce_root_text', array('imce' => &$imce)); - $q = $imce['clean'] ? '?' : '&'; - if (isset($imce['directories']['.'])) { - $root = ''. $root .''; - } - else { - $root = ''. $root .''; - } - - return $root . imce_tree_html($imce, $paths, $q); -} - -/** - * Return tree html. - * This is not themable because it is complex and needs to be in a proper format for js processing. - */ -function imce_tree_html(&$imce, $paths, $q = '?', $prefix = '', $eprefix = '') { - unset($paths[':access:'], $paths[':active:']); - $html = ''; - foreach ($paths as $arg => $children) { - $path = $prefix . $arg; - $earg = rawurlencode($arg); - $epath = $eprefix . $earg; - if (isset($children[':access:']) || imce_directory_info($path, $imce)) { - $a = ''. $earg .''; - } - else { - $a = ''. $earg .''; - } - $ul = imce_tree_html($imce, $children, $q, $path .'/', $epath .'/'); - $class = $ul ? ' class="expanded"' : (isset($children[':active:']) ? ' class="leaf"' : ''); - $html .= ''. $a . $ul .''; - } - if ($html) { - $html = ''; - } - return $html; -} - -/** - * Returns the text for the root directory in a directory tree. - */ -function theme_imce_root_text($imce_ref) { - //$imce = &$imce_ref['imce']; - return '<' . t('root') . '>'; -} - -/** - * Returns the html for user's file browser tab. - */ -function theme_imce_user_page($account) { - global $user; - $options = array(); - //switch to account's active folder - if ($user->uid == 1 && $account->uid != 1) { - $imce = imce_initiate_profile($account); - $options['query'] = array('dir' => $imce['dir']); - } - return ''; -} - -/** - * Registers the file as an IMCE file. - */ -function imce_file_register($file) { - return $file->fid && @db_query('INSERT INTO {imce_files} (fid) VALUES(%d)', $file->fid); -} + &$imce); + $forms = ''; + + if (!$imce['error']) { + //process file upload. + if (imce_perm_exists($imce, 'upload')) { + $forms .= drupal_get_form('imce_upload_form', $imce_ref); + } + //process file operations. + $forms .= drupal_get_form('imce_fileop_form', $imce_ref); + } + + //run custom content functions. possible to insert extra forms. content is invisible when js is enabled. + foreach (variable_get('imce_custom_content', array()) as $func => $state) { + if ($state && function_exists($func) && $output = $func($imce)) { + $forms .= $output; + } + } + + $content = theme('imce_content', imce_create_tree($imce), $forms, $imce_ref); + + //make necessary changes for js conversion + $imce['dir'] = str_replace('%2F', '/', rawurlencode($imce['dir'])); + unset($imce['files'], $imce['name'], $imce['directories'], $imce['subdirectories'], $imce['filesize'], $imce['quota'], $imce['tuquota'], $imce['thumbnails'], $imce['uid'], $imce['usertab']); + + drupal_add_js($imce_ref, 'setting'); + + return $content; +} + +/** + * Ajax operations. q=imce&jsop={op} + */ +function imce_js($user, $jsop = '') { + $response = array(); + + //data + if ($imce = imce_initiate_profile($user)) { + imce_process_profile($imce); + if (!$imce['error']) { + module_load_include('inc', 'imce', 'inc/imce.js'); + if (function_exists($func = 'imce_js_'. $jsop)) { + $response['data'] = $func($imce); + } + } + } + //messages + $response['messages'] = drupal_get_messages(); + + //disable devel log. + $GLOBALS['devel_shutdown'] = FALSE; + //for upload we must return plain text header. + drupal_set_header('Content-Type: text/'. ($jsop == 'upload' ? 'html' : 'javascript') .'; charset=utf-8'); + print drupal_to_js($response); + exit(); +} + +/** + * Upload form. + */ +function imce_upload_form(&$form_state, $ref) { + $imce =& $ref['imce']; + $form['imce'] = array( + '#type' => 'file', + '#title' => t('File'), + '#size' => 30, + ); + if (!empty($imce['thumbnails'])) { + $form['thumbnails'] = array( + '#type' => 'checkboxes', + '#title' => t('Create thumbnails'), + '#options' => imce_thumbnail_options($imce['thumbnails']), + ); + } + $form['upload'] = array( + '#type' => 'submit', + '#value' => t('Upload'), + '#submit' => $imce['perm']['upload'] ? array('imce_upload_submit') : NULL, + ); + $form = array('fset_upload' => array('#type' => 'fieldset', '#title' => t('Upload file')) + $form); + $form['#attributes']['enctype'] = 'multipart/form-data'; + $form['#action'] = $imce['url']; + return $form; +} + +/** + * File operations form. + */ +function imce_fileop_form(&$form_state, $ref) { + $imce =& $ref['imce']; + $form['filenames'] = array( + '#type' => 'textfield', + '#title' => t('Selected files'), + '#maxlength' => $imce['filenum'] ? $imce['filenum']*255 : NULL, + ); + + //thumbnail + if (!empty($imce['thumbnails']) && imce_perm_exists($imce, 'thumb')) { + $form['fset_thumb'] = array( + '#type' => 'fieldset', + '#title' => t('Thumbnails'), + ) + imce_thumb_form($imce); + } + + //delete + if (imce_perm_exists($imce, 'delete')) { + $form['fset_delete'] = array( + '#type' => 'fieldset', + '#title' => t('Delete'), + ) + imce_delete_form($imce); + } + + //resize + if (imce_perm_exists($imce, 'resize')) { + $form['fset_resize'] = array( + '#type' => 'fieldset', + '#title' => t('Resize'), + ) + imce_resize_form($imce); + } + + $form['#action'] = $imce['url']; + return $form; +} + +/** + * Thumbnail form. + */ +function imce_thumb_form(&$imce) { + $form['thumbnails'] = array( + '#type' => 'checkboxes', + '#title' => t('Thumbnails'), + '#options' => imce_thumbnail_options($imce['thumbnails']), + ); + $form['thumb'] = array( + '#type' => 'submit', + '#value' => t('Create thumbnails'), + '#submit' => $imce['perm']['thumb'] ? array('imce_thumb_submit') : NULL, + ); + return $form; +} + +/** + * Delete form. + */ +function imce_delete_form(&$imce) { + $form['delete'] = array( + '#type' => 'submit', + '#value' => t('Delete'), + '#submit' => $imce['perm']['delete'] ? array('imce_delete_submit') : NULL, + ); + return $form; +} + +/** + * Resizing form. + */ +function imce_resize_form(&$imce) { + $form['width'] = array( + '#type' => 'textfield', + '#title' => t('Width x Height'), + '#size' => 5, + '#maxlength' => 4, + '#prefix' => '
', + ); + $form['height'] = array( + '#type' => 'textfield', + '#size' => 5, + '#maxlength' => 4, + '#prefix' => 'x', + ); + $form['resize'] = array( + '#type' => 'submit', + '#value' => t('Resize'), + '#submit' => $imce['perm']['resize'] ? array('imce_resize_submit') : NULL,//permission for submission + '#suffix' => '
', + ); + $form['copy'] = array( + '#type' => 'checkbox', + '#title' => t('Create a new image'), + '#default_value' => 1, + ); + return $form; +} + +/** + * Validate file operations form. + */ +function imce_fileop_form_validate($form, &$form_state) { + $imce =& $form['#parameters'][2]['imce']; + + //check if the filenames is empty + if ($form_state['values']['filenames'] == '') { + return form_error($form['filenames'], t('Please select a file.')); + } + + //filenames come seperated by colon + $filenames = explode(':', $form_state['values']['filenames']); + $cnt = count($filenames); + //check the number of files. + if ($imce['filenum'] && $cnt > $imce['filenum']) { + return form_error($form['filenames'], t('You are not allowed to operate on more than %num files.', array('%num' => $imce['filenum']))); + } + + //check if there is any illegal choice + for ($i = 0; $i < $cnt; $i++) { + $filenames[$i] = $filename = rawurldecode($filenames[$i]); + if (!isset($imce['files'][$filename])) { + watchdog('imce', 'Illegal choice %choice in !name element.', array('%choice' => $filename, '!name' => t('directory (%dir)', array('%dir' => file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir'])))), WATCHDOG_ERROR); + return form_error($form['filenames'], t('An illegal choice has been detected. Please contact the site administrator.')); + } + } + + $form_state['values']['filenames'] = $filenames; +} + +/** + * Submit upload form. + */ +function imce_upload_submit($form, &$form_state) { + $form_state['redirect'] = FALSE; + $imce =& $form['#parameters'][2]['imce']; + $validators = array('imce_validate_all' => array(&$imce)); + $dirpath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']); + + //save uploaded file. + $replace = variable_get('imce_settings_replace', FILE_EXISTS_RENAME); + if ($file = file_save_upload('imce', $validators, $dirpath, $replace)) { + + //core bug #203204. + @chmod($file->filepath, 0664); + + //core bug #54223. + if ($replace == FILE_EXISTS_RENAME) { + $name = basename($file->filepath); + if ($name != $file->filename) { + $file->filename = $name; + drupal_set_message(t('The file has been renamed to %filename.', array('%filename' => $file->filename))); + } + } + elseif ($replace == FILE_EXISTS_REPLACE) {//check duplicates + if ($_file = db_fetch_object(db_query("SELECT fid FROM {files} WHERE filepath = '%s' AND fid <> %d", $file->filepath, $file->fid))) { + db_query("DELETE FROM {files} WHERE fid = %d", $file->fid); + $file->fid = $_file->fid; + } + } + + $file->uid = $imce['uid'];//global user may not be the owner. + $file->status = FILE_STATUS_PERMANENT;//make permanent + drupal_write_record('files', $file, array('fid'));//update + imce_file_register($file); + drupal_set_message(t('%filename has been uploaded.', array('%filename' => $file->filename))); + + //update file list + $img = imce_image_info($file->filepath); + $file->width = $img ? $img['width'] : 0; + $file->height = $img ? $img['height'] : 0; + imce_add_file($file, $imce); + + //create thumbnails + if (isset($form_state['values']['thumbnails']) && $img) { + imce_create_thumbnails($file->filename, $imce, $form_state['values']['thumbnails']); + } + } + else { + drupal_set_message(t('Upload failed.'), 'error'); + } +} + +/** + * Submit thumbnail form. + */ +function imce_thumb_submit($form, &$form_state) { + $form_state['redirect'] = FALSE; + $imce =& $form['#parameters'][2]['imce']; + //create thumbnails + imce_process_files($form_state['values']['filenames'], $imce, 'imce_create_thumbnails', array($form_state['values']['thumbnails'])); +} + +/** + * Submit delete form. + */ +function imce_delete_submit($form, &$form_state) { + $form_state['redirect'] = FALSE; + $imce =& $form['#parameters'][2]['imce']; + + $deleted = imce_process_files($form_state['values']['filenames'], $imce, 'imce_delete_file'); + + if (!empty($deleted)) { + drupal_set_message(t('File deletion successful: %files.', array('%files' => utf8_encode(implode(', ', $deleted))))); + } + +} + +/** + * Submit resize form. + */ +function imce_resize_submit($form, &$form_state) { + $form_state['redirect'] = FALSE; + $imce =& $form['#parameters'][2]['imce']; + + //check dimensions + $width = (int) $form_state['values']['width']; + $height = (int) $form_state['values']['height']; + list($maxw, $maxh) = explode('x', $imce['dimensions']); + if ($width < 1 || $height < 1 || ($maxw && ($width > $maxw || $height > $maxh))) { + drupal_set_message(t('Please specify dimensions within the allowed range that is from 1x1 to @dimensions.', array('@dimensions' => $imce['dimensions'] ? $imce['dimensions'] : t('unlimited'))), 'error'); + return; + } + + $resized = imce_process_files($form_state['values']['filenames'], $imce, 'imce_resize_image', array($width, $height, $form_state['values']['copy'])); + + if (!empty($resized)) { + drupal_set_message(t('File resizing successful: %files.', array('%files' => utf8_encode(implode(', ', $resized))))); + } + +} + +/** + * Do batch operations on files. + * Used by delete, resize, create thumbnail submissions. + */ +function imce_process_files($filenames, &$imce, $function, $args = array()) { + $args = array_merge(array('', &$imce), $args); + $processed = array(); + + foreach ($filenames as $filename) { + $args[0] = $filename; + if (call_user_func_array($function, $args)) { + $processed[] = $filename; + } + } + + return $processed; +} + +/** + * Delete a file in the file list. + */ +function imce_delete_file($filename, &$imce) { + $filepath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']) .'/'. $filename; + if (!imce_delete_filepath($filepath)) { + return FALSE; + } + imce_remove_file($filename, $imce); + return TRUE; +} + +/** + * Delete a file by path. + */ +function imce_delete_filepath($filepath) { + $file = db_fetch_object(db_query("SELECT * FROM {files} WHERE filepath = '%s'", $filepath)); + + //file exists in database + if ($file) { + //prevent imce returning ref count + $file->imce_noref = TRUE; + //check references + $refs = array_filter(module_invoke_all('file_references', $file)); + //file is in use + if (!empty($refs)) { + drupal_set_message(t('%filename is in use by another application.', array('%filename' => $file->filename)), 'error'); + return FALSE; + } + //prepare deletion + module_invoke_all('file_delete', $file); + if (!file_delete($file->filepath)) { + return FALSE; + } + db_query('DELETE FROM {files} WHERE fid = %d', $file->fid); + } + //not in db. probably loaded via ftp. + elseif (!file_delete($filepath)) { + return FALSE; + } + + return TRUE; +} + +/** + * Create all selected thumbnails. + */ +function imce_create_thumbnails($filename, &$imce, $values) { + $created = array(); + foreach ($imce['thumbnails'] as $thumbnail) { + if ($values[$thumbnail['name']] && imce_create_thumbnail($filename, $imce, $thumbnail)) { + $created[] = $thumbnail['name']; + } + } + if (!empty($created)) { + drupal_set_message(t('Thumbnail creation (%thumbnames) successful for %filename.', array('%thumbnames' => implode(', ', $created), '%filename' => utf8_encode($filename)))); + } + return $created; +} + +/** + * Create a thumbnail. + */ +function imce_create_thumbnail($filename, &$imce, $thumbnail) { + //generate thumbnail name + $name = $thumbnail['prefix']; + if ($thumbnail['suffix'] != '' && $dot = strrpos($filename, '.')) { + $name .= substr($filename, 0, $dot); + $name .= $thumbnail['suffix']; + $name .= substr($filename, $dot); + } + else { + $name .= $filename; + } + //scale the image + list($width, $height) = explode('x', $thumbnail['dimensions']); + return imce_resize_image($filename, $imce, $width, $height, TRUE, $name, variable_get('imce_settings_thumb_method', 'scale_and_crop')); +} + +/** + * Resize an image in the file list. Also used for thumbnail creation. + */ +function imce_resize_image($filename, &$imce, $width, $height, $copy = TRUE, $dest = FALSE, $op = 'resize') { + $dirpath = file_directory_path() . ($imce['dir'] == '.' ? '' : '/'. $imce['dir']); + $filepath = $dirpath .'/'. $filename; + + //check if the file is an image + if (!$imce['files'][$filename]['width'] || !$img = imce_image_info($filepath)) { + drupal_set_message(t('%filename is not an image.', array('%filename' => utf8_encode($filename))), 'error', FALSE); + return FALSE; + } + + if (substr($op, 0, 5) == 'scale' && !($width < $img['width'] || $height < $img['height'])) { + drupal_set_message(t('Scaling up is not allowed.'), 'error', FALSE); + return FALSE; + } + + //create file object + $file = new stdClass(); + $file->filepath = $dirpath .'/'. $dest; + if (!$dest || $dest == $filename) { + $file->filepath = $copy ? file_create_filename($filename, $dirpath) : $filepath; + } + $file->filename = basename($file->filepath); + + //check if a file having the same properties exists already. + if (isset($imce['files'][$file->filename])) { + if (($f = $imce['files'][$file->filename]) && $f['width'] == $width && $f['height'] == $height) { + drupal_set_message(t('%filename(%dimensions) already exists.', array('%filename' => utf8_encode($file->filename), '%dimensions' => $width .'x'. $height)), 'error'); + return FALSE; + } + } + + //validate file name + $errors = file_validate_name_length($file); + if (!empty($errors)) { + drupal_set_message($errors[0], 'error'); + return FALSE; + } + + //resize image to a temp file + $temp = tempnam(realpath(file_directory_temp()), 'imc'); + register_shutdown_function('file_delete', $temp); + $function = 'image_'. $op; + if (!$function($filepath, $temp, $width, $height)) { + drupal_set_message(t('%filename cannot be resized to %dimensions', array('%filename' => utf8_encode($filename), '%dimensions' => $width .'x'. $height)), 'error', FALSE); + return FALSE; + } + + //validate quota + $file->filesize = filesize($temp); + $overwrite = $file->filename == $filename; + if (!imce_validate_quotas($file, $imce, $overwrite ? -$imce['files'][$filename]['size'] : 0)) { + return FALSE; + } + + //copy from temp to filepath + if (!@copy($temp, $file->filepath)) { + drupal_set_message(t('The selected file %file could not be copied.', array('%file' => utf8_encode($file->filename))), 'error', FALSE); + return FALSE; + } + @chmod($file->filepath, 0664); + + //build the rest of the file object + $file->uid = $imce['uid']; + $file->filemime = $img['mime']; + $file->status = FILE_STATUS_PERMANENT; + $file->timestamp = time(); + + //if we are overwriting the file and it is already in database. + $update = array(); + if ($overwrite && $_file = db_fetch_object(db_query("SELECT f.* FROM {files} f WHERE f.filepath = '%s'", $file->filepath))) { + $file->fid = $_file->fid; + $file->uid = $_file->uid; + $update[] = 'fid'; + } + + //save the file + drupal_write_record('files', $file, $update); + imce_file_register($file); + + //update file list + //if the file was scaled get the new dimensions + if ($op == 'scale') { + $img = imce_image_info($file->filepath); + $width = $img['width']; + $height = $img['height']; + } + $file->width = $width; + $file->height = $height; + imce_add_file($file, $imce); + + return $file; +} + +/** + * Add a new file to the file list. + */ +function imce_add_file($file, &$imce) { + $imce['dirsize'] += $file->filesize; + if (isset($imce['files'][$file->filename])) { + $imce['dirsize'] -= $imce['files'][$file->filename]['size']; + } + $imce['files'][$file->filename] = array( + 'name' => $file->filename, + 'size' => $file->filesize, + 'width' => $file->width, + 'height' => $file->height, + 'date' => $file->timestamp + ); + if (isset($_GET['jsop'])) { + $add = $imce['files'][$file->filename]; + $add['name'] = rawurlencode($file->filename); + $add['fsize'] = format_size($file->filesize); + $add['fdate'] = format_date($file->timestamp, 'small'); + $add['id'] = $file->fid; + $imce['added'][] = $add; + } +} + +/** + * Remove a file from the file list. + */ +function imce_remove_file($filename, &$imce) { + if (isset($imce['files'][$filename])) { + $imce['dirsize'] -= $imce['files'][$filename]['size']; + unset($imce['files'][$filename]); + if (isset($_GET['jsop'])) { + $imce['removed'][] = rawurlencode($filename); + } + } +} + +/** + * Validate uploaded file. + */ +function imce_validate_all(&$file, $imce) { + + //fix FILE_EXISTS_ERROR bug. core bug #54223. + if (!$file->destination && variable_get('imce_settings_replace', FILE_EXISTS_RENAME) == FILE_EXISTS_ERROR) { + return array(t('File browser is set to reject the upload of existing files.')); + } + + //validate image resolution only if filesize validation passes. + //because user might have uploaded a very big image + //and scaling it may exploit system memory. + $errors = imce_validate_filesize($file, $imce['filesize']); + //image resolution validation + if (empty($errors)) { + $errors = array_merge($errors, file_validate_image_resolution($file, $imce['dimensions'])); + } + //directory quota validation + if ($imce['quota']) { + $errors = array_merge($errors, imce_validate_quota($file, $imce['quota'], $imce['dirsize'])); + } + //file extension validation + if ($imce['extensions'] != '*') { + $errors = array_merge($errors, file_validate_extensions($file, $imce['extensions'])); + } + //user quota validation. check it if no errors were thrown. + if (empty($errors) && $imce['tuquota']) { + $errors = imce_validate_tuquota($file, $imce['tuquota'], file_space_used($imce['uid'])); + } + return $errors; +} + +/** + * Validate filesize for maximum allowed file size. + */ +function imce_validate_filesize($file, $maxsize = 0) { + $errors = array(); + if ($maxsize && $file->filesize > $maxsize) { + $errors[] = t('The file is %filesize exceeding the maximum file size of %maxsize.', array('%filesize' => format_size($file->filesize), '%maxsize' => format_size($maxsize))); + } + return $errors; +} + +/** + * Validate filesize for directory quota. + */ +function imce_validate_quota($file, $quota = 0, $currentsize = 0) { + $errors = array(); + if ($quota && ($currentsize + $file->filesize) > $quota) { + $errors[] = t('%filename is %filesize which would exceed your directory quota. You are currently using %size of %total_quota.', array('%size' => format_size($currentsize), '%total_quota' => format_size($quota), '%filesize' => format_size($file->filesize), '%filename' => utf8_encode($file->filename))); + } + return $errors; +} + +/** + * Validate filesize for total user quota. + */ +function imce_validate_tuquota($file, $quota = 0, $currentsize = 0) { + $errors = array(); + if ($quota && ($currentsize + $file->filesize) > $quota) { + $errors[] = t('%filename is %filesize which would exceed your total user quota. You are currently using %size of %total_quota.', array('%size' => format_size($currentsize), '%total_quota' => format_size($quota), '%filesize' => format_size($file->filesize), '%filename' => utf8_encode($file->filename))); + } + return $errors; +} + +/** + * Validate both directory and total user quota. Returns true/false not errors. + */ +function imce_validate_quotas($file, &$imce, $add = 0) { + $errors = imce_validate_quota($file, $imce['quota'], $imce['dirsize'] + $add); + if (empty($errors) && $imce['tuquota']) { + $errors = imce_validate_tuquota($file, $imce['tuquota'], file_space_used($imce['uid']) + $add); + } + if (!empty($errors)) { + drupal_set_message($errors[0], 'error'); + return FALSE; + } + return TRUE; +} + +/** + * Check if the file is an image and return info. + */ +function imce_image_info($file) { + if (is_file($file) && ($dot = strrpos($file, '.')) && in_array(strtolower(substr($file, $dot+1)), array('jpg', 'jpeg', 'gif', 'png')) && ($info = @getimagesize($file)) && in_array($info[2], array(IMAGETYPE_JPEG, IMAGETYPE_GIF, IMAGETYPE_PNG)) ) { + return array('width' => $info[0], 'height' => $info[1], 'type' => $info[2], 'mime' => $info['mime']); + } + return FALSE; +} + +/** + * Return thumbnails as options to be used in upload form. + */ +function imce_thumbnail_options($thumbs = array()) { + $options = array(); + foreach ($thumbs as $thumb) { + $options[$thumb['name']] = $thumb['name'] .' ('. $thumb['dimensions'] .')'; + } + return $options; +} + +/** + * Initiate and return configuration profile for the $user. + */ +function imce_initiate_profile($user) { + + //check user profile and translate tokens in directory paths and evaluate php paths. + if ($imce = imce_user_profile($user)) { + imce_process_directories($imce, $user); + if (!empty($imce['directories'])) { + $imce['uid'] = (int) $user->uid; + $imce['url'] = url($_GET['q']); + $imce['clean'] = variable_get('clean_url', 0) == 1; + $imce['absurls'] = variable_get('imce_settings_absurls', 0) == 1; + $imce['furl'] = file_create_url(''); + $imce['filesize'] *= 1048576;//convert from Mb to byte + $imce['quota'] *= 1048576; + $imce['tuquota'] *= 1048576; + $imce['filenum'] = (int) $imce['filenum']; + //check and set the active directory + if ($info = imce_working_directory($imce)) { + $imce['direct'] = isset($imce['directories'][$info['name']]); + $imce['directories'][$info['name']] = $info; + $imce['dir'] = $info['name']; + $imce['perm'] = $info;//copy permissions of the active directory. + unset($imce['perm']['name']); + } + else { + drupal_set_message(t('Unable to get a working directory for the file browser!'), 'error'); + $imce['dir'] = FALSE; + $imce['error'] = TRUE; + } + return $imce; + } + drupal_set_message(t('There is no valid directory specified for the file browser!'), 'error'); + } + else { + drupal_set_message(t('You do not have access to any configuration profile to use the file browser!'), 'error'); + } + + return FALSE; +} + +/** + * Get files and folders of the actve directory. Do custom processing. + */ +function imce_process_profile(&$imce) { + //get directory content. do a custom scan if it is set + $scan = ($scan = variable_get('imce_custom_scan', '')) && function_exists($scan) ? $scan : 'imce_scan_directory'; + $imce += $scan($imce['dir'], $imce); + + //run custom process functions + foreach (variable_get('imce_custom_process', array()) as $func => $state) { + if ($state && function_exists($func)) { + $func($imce); + } + } + + //set subdirectories + if (!$imce['error'] && !imce_subdirectories_accessible($imce)) { + $imce['subdirectories'] = array(); + } +} + +/** + * Translate tokens and evaluate php in directory names. + * Convert directories into an associative array (dirname => info) + */ +function imce_process_directories(&$imce, $user) { + $directories = $imce['directories']; + $paths = array(); + $translate = array('%uid' => $user->uid); + + foreach ($directories as $directory) { + if (substr($directory['name'], 0, 4) == 'php:') { + $directory['name'] = eval(substr($directory['name'], 4)); + //php may return an array of directories + if (is_array($directory['name'])) { + foreach ($directory['name'] as $name) { + $paths[$name] = array('name' => $name) + $directory; + } + continue; + } + } + else { + $directory['name'] = strtr($directory['name'], $translate); + } + if ($directory['name']) { + $paths[$directory['name']] = $directory; + } + } + + $imce['directories'] = $paths; +} + +/** + * Return an avaliable directory for the profile. + */ +function imce_working_directory(&$imce) { + //Do not use session if there is only one directory assigned. + $sess = TRUE; + if (count($imce['directories']) < 2) { + $perms = reset($imce['directories']); + if (!isset($perms['subnav']) || !$perms['subnav']) { + $sess = FALSE; + } + } + //check GET. + if (isset($_GET['dir'])) { + if ($info = imce_directory_info($_GET['dir'], $imce)) { + if (imce_check_directory($_GET['dir'], $imce)) { + if ($sess) { + $_SESSION['imce_directory'] = rawurlencode($info['name']); + } + } + else { + $info = FALSE; + } + } + else { + imce_inaccessible_directory($_GET['dir'], $imce); + } + return $info; + } + + //check session + if ($sess && isset($_SESSION['imce_directory'])) { + $dirname = rawurldecode($_SESSION['imce_directory']); + if ($info = imce_directory_info($dirname, $imce)) { + if (imce_check_directory($dirname, $imce)) { + return $info; + } + } + } + + //or the whole list. + foreach ($imce['directories'] as $dirname => $info) { + if (imce_check_directory($dirname, $imce)) { + if ($sess) { + $_SESSION['imce_directory'] = rawurlencode($dirname); + } + return $info; + } + } + + return FALSE; +} + +/** + * Create a writable directory(any level) under file system directory. + */ +function imce_check_directory($dirname, $imce = array()) { + + $root = file_directory_path(); + $dirpath = $root .'/'. $dirname; + + if (!file_check_directory($dirpath)) {//directory does not exist. try to create it. + $path = $root; + foreach (explode('/', $dirname) as $arg) { + $path .= '/'. $arg; + if (!file_check_location($path, $root) || !file_check_directory($path, FILE_CREATE_DIRECTORY)) { + return imce_inaccessible_directory($dirname, $imce); + } + } + } + elseif (!file_check_location($dirpath, $root)) {//directory exists outside of root. + return imce_inaccessible_directory($dirname, $imce); + } + + return TRUE; +} + +/** + * Generate and log a directory access error. + */ +function imce_inaccessible_directory($dirname, $imce = array()) { + if (is_string($dirname)) { + $dirname = utf8_encode($dirname); + drupal_set_message(t('Directory %dirname is not accessible.', array('%dirname' => $dirname)), 'error'); + watchdog('imce', 'Access to %directory was denied.', array('%directory' => $dirname), WATCHDOG_ERROR); + } + return FALSE; +} + +/** + * Return the permissions for a directory that is accessed directly or indirectly. + * A child of a predefined directory in the directory list takes its parent's properties. + * If it has multiple parents, it gets the properties of the latter in the list. + */ +function imce_directory_info($dirname, $imce) { + + if (isset($imce['directories'][$dirname])) { + return $imce['directories'][$dirname]; + } + + $info = FALSE; + $root = file_directory_path(); + $dirpath = $root .'/'. $dirname; + if (imce_reg_dir($dirname) && file_check_directory($dirpath)) { + foreach ($imce['directories'] as $name => $prop) { + if ($prop['subnav'] && file_check_location($dirpath, $root .'/'. $name)) { + $info = $prop; + $info['name'] = $dirname; + } + } + } + + return $info; +} + +/** + * Detect if the subdirectories are accessible through any directory(not just the current one) in the list. + */ +function imce_subdirectories_accessible(&$imce) { + + if (!empty($imce['subdirectories'])) { + $root = file_directory_path() .'/'; + //checking only the first one is sufficient. + $dirname = ($imce['dir'] == '.' ? '' : $imce['dir'] .'/') . $imce['subdirectories'][0]; + $dirpath = $root . $dirname; + + //check if any setting is applicable for this subdirectory through any directory in the list. + foreach ($imce['directories'] as $name => $info) { + if ($info['subnav'] && $dirname != $name && file_check_location($dirpath, $root . $name)) { + return TRUE; + } + } + } + + return FALSE; +} + +/** + * Check if a permission is given to at least one directory in the list. + */ +function imce_perm_exists(&$imce, $perm) { + static $perms = array(); + + if (isset($perms[$perm])) { + return $perms[$perm]; + } + + if (isset($imce['perm'][$perm]) && $imce['perm'][$perm]) { + return $perms[$perm] = TRUE; + } + + foreach ($imce['directories'] as $name => $info) { + if (isset($info[$perm]) && $info[$perm]) { + return $perms[$perm] = TRUE; + } + } + + return $perms[$perm] = FALSE; +} + +/** + * Scan directory and return file list, subdirectories, and total size. + */ +function imce_scan_directory($dirname, $imce = array()) { + + $directory = array('dirsize' => 0, 'files' => array(), 'subdirectories' => array(), 'error' => FALSE); + $dirpath = file_directory_path() .'/'. $dirname; + + if (!is_string($dirname) || $dirname == '' || !$handle = opendir($dirpath)) { + imce_inaccessible_directory($dirname, $imce); + $directory['error'] = TRUE; + return $directory; + } + + $exclude = array('.' => 1, '..' => 1, 'CVS' => 1, '.svn' => 1, '.htaccess' => 1); + while (($file = readdir($handle)) !== FALSE) { + if (isset($exclude[$file])) { + continue; + } + + $path = $dirpath .'/'. $file; + + if (is_dir($path)) { + $directory['subdirectories'][] = $file; + continue; + } + + $width = $height = 0; + if ($img = imce_image_info($path)) { + $width = $img['width']; + $height = $img['height']; + } + $size = filesize($path); + $date = filemtime($path); + $directory['files'][$file] = array( + 'name' => $file, + 'size' => $size, + 'width' => $width, + 'height' => $height, + 'date' => $date + ); + $directory['dirsize'] += $size; + } + + closedir($handle); + sort($directory['subdirectories']); + return $directory; +} + +/** + * Create directory tree. + */ +function imce_create_tree(&$imce) { + $paths = array(); + //rearrange paths as arg0=>arg1=>... + foreach ($imce['directories'] as $path => $arr) { + $tmp =& $paths; + if ($path != '.') { + $args = explode('/', $path); + foreach ($args as $arg) { + if (!isset($tmp[$arg])) { + $tmp[$arg] = array(); + } + $tmp =& $tmp[$arg]; + } + $tmp[':access:'] = TRUE; + } + if ("$path" == $imce['dir']) { + $tmp[':active:'] = TRUE; + foreach ($imce['subdirectories'] as $arg) { + $tmp[$arg][':access:'] = TRUE; + } + } + } + //set root branch + $root = theme('imce_root_text', array('imce' => &$imce)); + $q = $imce['clean'] ? '?' : '&'; + if (isset($imce['directories']['.'])) { + $root = ''. $root .''; + } + else { + $root = ''. $root .''; + } + + return $root . imce_tree_html($imce, $paths, $q); +} + +/** + * Return tree html. + * This is not themable because it is complex and needs to be in a proper format for js processing. + */ +function imce_tree_html(&$imce, $paths, $q = '?', $prefix = '', $eprefix = '') { + unset($paths[':access:'], $paths[':active:']); + $html = ''; + foreach ($paths as $arg => $children) { + $path = $prefix . $arg; + $earg = rawurlencode($arg); + $epath = $eprefix . $earg; + if (isset($children[':access:']) || imce_directory_info($path, $imce)) { + $a = ''. $earg .''; + } + else { + $a = ''. $earg .''; + } + $ul = imce_tree_html($imce, $children, $q, $path .'/', $epath .'/'); + $class = $ul ? ' class="expanded"' : (isset($children[':active:']) ? ' class="leaf"' : ''); + $html .= ''. $a . $ul .''; + } + if ($html) { + $html = ''; + } + return $html; +} + +/** + * Returns the text for the root directory in a directory tree. + */ +function theme_imce_root_text($imce_ref) { + //$imce = &$imce_ref['imce']; + return '<' . t('root') . '>'; +} + +/** + * Returns the html for user's file browser tab. + */ +function theme_imce_user_page($account) { + global $user; + $options = array(); + //switch to account's active folder + if ($user->uid == 1 && $account->uid != 1) { + $imce = imce_initiate_profile($account); + $options['query'] = array('dir' => $imce['dir']); + } + return ''; +} + +/** + * Registers the file as an IMCE file. + */ +function imce_file_register($file) { + return $file->fid && @db_query('INSERT INTO {imce_files} (fid) VALUES(%d)', $file->fid); +} --- js/imce.js 2010-11-01 09:23:27.000000000 -0400 +++ js/imce.js 2010-10-29 16:33:20.000000000 -0400 @@ -1,799 +1,830 @@ -// $Id: imce.js,v 1.2 2010/08/31 16:36:17 c0aslm1 Exp $ - -(function($) { -//Global container. -window.imce = {tree: {}, findex: [], fids: {}, selected: {}, selcount: 0, ops: {}, cache: {}, urlId: {}, -vars: {previewImages: 1, cache: 1}, -hooks: {load: [], list: [], navigate: [], cache: []}, - -//initiate imce. -initiate: function() { - imce.conf = Drupal.settings.imce || {}; - if (imce.conf.error != false) return; - imce.FLW = imce.el('file-list-wrapper'); - imce.SBW = imce.el('sub-browse-wrapper'); - imce.updateUI(); - imce.prepareMsgs();//process initial status messages - imce.initiateTree();//build directory tree - imce.hooks.list.unshift(imce.processRow);//set the default list-hook. - imce.initiateList();//process file list - imce.initiateOps();//prepare operation tabs - imce.refreshOps(); - imce.invoke('load', window);//run functions set by external applications. -}, - -/**************** DIRECTORIES ********************/ - -//process navigation tree -initiateTree: function() { - $('#navigation-tree li').each(function(i) { - var a = this.firstChild, txt = a.firstChild; - txt && (txt.data = imce.decode(txt.data)); - var branch = imce.tree[a.title] = {'a': a, li: this, ul: this.lastChild.tagName == 'UL' ? this.lastChild : null}; - if (a.href) imce.dirClickable(branch); - imce.dirCollapsible(branch); - }); -}, - -//Add a dir to the tree under parent -dirAdd: function(dir, parent, clickable) { - if (imce.tree[dir]) return clickable ? imce.dirClickable(imce.tree[dir]) : imce.tree[dir]; - var parent = parent || imce.tree['.']; - parent.ul = parent.ul ? parent.ul : parent.li.appendChild(imce.newEl('ul')); - var branch = imce.dirCreate(dir, imce.decode(dir.substr(dir.lastIndexOf('/')+1)), clickable); - parent.ul.appendChild(branch.li); - return branch; -}, - -//create list item for navigation tree -dirCreate: function(dir, text, clickable) { - if (imce.tree[dir]) return imce.tree[dir]; - var branch = imce.tree[dir] = {li: imce.newEl('li'), a: imce.newEl('a')}; - $(branch.a).addClass('folder').text(text).attr('title', dir).appendTo(branch.li); - imce.dirCollapsible(branch); - return clickable ? imce.dirClickable(branch) : branch; -}, - -//change currently active directory -dirActivate: function(dir) { - if (dir != imce.conf.dir) { - if (imce.tree[imce.conf.dir]){ - $(imce.tree[imce.conf.dir].a).removeClass('active'); - } - $(imce.tree[dir].a).addClass('active'); - imce.conf.dir = dir; - } - return imce.tree[imce.conf.dir]; -}, - -//make a dir accessible -dirClickable: function(branch) { - if (branch.clkbl) return branch; - $(branch.a).attr('href', '#').removeClass('disabled').click(function() {imce.navigate(this.title); return false;}); - branch.clkbl = true; - return branch; -}, - -//sub-directories expand-collapse ability -dirCollapsible: function (branch) { - if (branch.clpsbl) return branch; - $(imce.newEl('span')).addClass('expander').html(' ').click(function() { - if (branch.ul) { - $(branch.ul).toggle(); - $(branch.li).toggleClass('expanded'); - } - else if (branch.clkbl){ - $(branch.a).click(); - } - }).prependTo(branch.li); - branch.clpsbl = true; - return branch; -}, - -//update navigation tree after getting subdirectories. -dirSubdirs: function(dir, subdirs) { - var branch = imce.tree[dir]; - if (subdirs && subdirs.length) { - var prefix = dir == '.' ? '' : dir +'/'; - for (var i in subdirs) {//add subdirectories - imce.dirAdd(prefix + subdirs[i], branch, true); - } - $(branch.li).removeClass('leaf').addClass('expanded'); - $(branch.ul).show(); - } - else if (!branch.ul){//no subdirs->leaf - $(branch.li).removeClass('expanded').addClass('leaf'); - } -}, - -/**************** FILES ********************/ - -//process file list -initiateList: function(cached) { - var L = imce.hooks.list, dir = imce.conf.dir, token = {'%dir': dir == '.' ? $(imce.tree['.'].a).text() : imce.decode(dir)} - imce.findex = [], imce.fids = {}, imce.selected = {}, imce.selcount = 0, imce.vars.lastfid = null; - imce.tbody = imce.el('file-list').tBodies[0]; - if (imce.tbody.rows.length) { - for (var row, i = 0; row = imce.tbody.rows[i]; i++) { - var fid = row.id; - imce.findex[i] = imce.fids[fid] = row; - if (cached) { - if (imce.hasC(row, 'selected')) { - imce.selected[imce.vars.lastfid = fid] = row; - imce.selcount++; - } - } - else { - for (var func, j = 0; func = L[j]; j++) func(row);//invoke list-hook - } - } - } - if (!imce.conf.perm.browse) { - imce.setMessage(Drupal.t('File browsing is disabled in directory %dir.', token), 'error'); - } -}, - -//add a file to the list. (having properties name,size,formatted size,width,height,date,formatted date) -fileAdd: function(file) { - var row, fid = file.name, i = imce.findex.length, attr = ['name', 'size', 'width', 'height', 'date']; - if (!(row = imce.fids[fid])) { - row = imce.findex[i] = imce.fids[fid] = imce.tbody.insertRow(i); - for (var i in attr) row.insertCell(i).className = attr[i]; - } - row.cells[0].innerHTML = row.id = fid; - row.cells[1].innerHTML = file.fsize; row.cells[1].id = file.size; - row.cells[2].innerHTML = file.width; - row.cells[3].innerHTML = file.height; - row.cells[4].innerHTML = file.fdate; row.cells[4].id = file.date; - imce.invoke('list', row); - if (imce.vars.prvfid == fid) imce.setPreview(fid); - if (file.id) imce.urlId[imce.getURL(fid)] = file.id; -}, - -//remove a file from the list -fileRemove: function(fid) { - if (!(row = imce.fids[fid])) return; - imce.fileDeSelect(fid); - imce.findex.splice(row.rowIndex, 1); - $(row).remove(); - delete imce.fids[fid]; - if (imce.vars.prvfid == fid) imce.setPreview(); -}, - -//return a file object containing all properties. -fileGet: function (fid) { - var row = imce.fids[fid]; - var url = imce.getURL(fid); - return row ? { - name: imce.decode(fid), - url: url, - size: row.cells[1].innerHTML, - bytes: row.cells[1].id * 1, - width: row.cells[2].innerHTML * 1, - height: row.cells[3].innerHTML * 1, - date: row.cells[4].innerHTML, - time: row.cells[4].id * 1, - id: imce.urlId[url] || 0, //file id for newly uploaded files - relpath: (imce.conf.dir == '.' ? '' : imce.conf.dir +'/') + fid //rawurlencoded path relative to file directory path. - } : null; -}, - -//simulate row click. selection-highlighting -fileClick: function(row, ctrl, shft) { - if (!row) return; - var fid = typeof(row) == 'string' ? row : row.id; - if (ctrl || fid == imce.vars.prvfid) { - imce.fileToggleSelect(fid); - } - else if (shft) { - var last = imce.lastFid(); - var start = last ? imce.fids[last].rowIndex : -1; - var end = imce.fids[fid].rowIndex; - var step = start > end ? -1 : 1; - while (start != end) { - start += step; - imce.fileSelect(imce.findex[start].id); - } - } - else { - for (var fname in imce.selected) { - imce.fileDeSelect(fname); - } - imce.fileSelect(fid); - } - //set preview - imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); -}, - -//file select/deselect functions -fileSelect: function (fid) { - if (imce.selected[fid] || !imce.fids[fid]) return; - imce.selected[fid] = imce.fids[imce.vars.lastfid=fid]; - $(imce.selected[fid]).addClass('selected'); - imce.selcount++; -}, -fileDeSelect: function (fid) { - if (!imce.selected[fid] || !imce.fids[fid]) return; - if (imce.vars.lastfid == fid) imce.vars.lastfid = null; - $(imce.selected[fid]).removeClass('selected'); - delete imce.selected[fid]; - imce.selcount--; -}, -fileToggleSelect: function (fid) { - imce['file'+ (imce.selected[fid] ? 'De' : '') +'Select'](fid); -}, - -/**************** OPERATIONS ********************/ - -//process file operation form and create operation tabs. -initiateOps: function() { - imce.setHtmlOps(); - imce.setUploadOp();//upload - imce.setFileOps();//thumb, delete, resize -}, - -//process existing html ops. -setHtmlOps: function () { - $(imce.el('ops-list')).children('li').each(function() { - if (!this.firstChild) return $(this).remove(); - var name = this.id.substr(8); - var Op = imce.ops[name] = {div: imce.el('op-content-'+ name), li: imce.el('op-item-'+ name)}; - Op.a = Op.li.firstChild; - Op.title = Op.a.innerHTML; - $(Op.a).click(function() {imce.opClick(name); return false;}); - }); -}, - -//convert upload form to an op. -setUploadOp: function () { - var form = imce.el('imce-upload-form'); - if (!form) return; - $(form).ajaxForm(imce.uploadSettings()).find('fieldset').each(function() {//clean up fieldsets - this.removeChild(this.firstChild); - $(this).after(this.childNodes); - }).remove(); - imce.opAdd({name: 'upload', title: Drupal.t('Upload'), content: form});//add op -}, - -//convert fileop form submit buttons to ops. -setFileOps: function () { - var form = imce.el('imce-fileop-form'); - if (!form) return; - $(form.elements.filenames).parent().remove(); - $(form).find('fieldset').each(function() {//remove fieldsets - var $sbmt = $('input:submit', this); - if (!$sbmt.size()) return; - var Op = {name: $sbmt.attr('id').substr(5)}; - var func = function() {imce.fopSubmit(Op.name); return false;}; - $sbmt.click(func); - Op.title = $(this).children('legend').remove().text(); - Op.name == 'delete' ? (Op.func = func) : (Op.content = this.childNodes); - imce.opAdd(Op); - }).remove(); - imce.vars.opform = $(form).serialize();//serialize remaining parts. -}, - -//refresh ops states. enable/disable -refreshOps: function() { - for (var p in imce.conf.perm) { - if (imce.conf.perm[p]) imce.opEnable(p); - else imce.opDisable(p); - } -}, - -//add a new file operation -opAdd: function (op) { - var oplist = imce.el('ops-list'), opcons = imce.el('op-contents'); - var name = op.name || ('op-'+ $(oplist).children('li').size()); - var Op = imce.ops[name] = {title: op.title || 'Untitled'}; - if (op.content) { - Op.div = imce.newEl('div'); - $(Op.div).attr({id: 'op-content-'+ name, 'class': 'op-content'}).appendTo(opcons).append(op.content); - } - Op.a = imce.newEl('a'); - Op.li = imce.newEl('li'); - $(Op.a).attr({href: '#', 'name': name}).html('' + op.title +'').click(imce.opClickEvent); - $(Op.li).attr('id', 'op-item-'+ op.name).append(Op.a).appendTo(oplist); - Op.func = op.func || imce.opVoid; - return Op; -}, - -//click event for file operations -opClickEvent: function(e) { - imce.opClick(this.name); - return false; -}, - -//void operation function -opVoid: function() {}, - -//perform op click -opClick: function(name) { - var Op = imce.ops[name], oldop = imce.vars.op; - if (!Op || Op.disabled) { - return imce.setMessage(Drupal.t('You can not perform this operation.'), 'error'); - } - if (Op.div) { - if (oldop) { - var toggle = oldop == name; - imce.opShrink(oldop, toggle ? 'slideUp' : 'hide'); - if (toggle) return false; - } - var left = Op.li.offsetLeft; - var $opcon = $('#op-contents').css({left: 0}); - $(Op.div).slideDown('normal', function() { - setTimeout(function() { - if (imce.vars.op) { - var $inputs = $('input', imce.ops[imce.vars.op].div); - $inputs.eq(0).focus(); - //form inputs become invisible in IE. Solution is as stupid as the behavior. - $('html').is('.ie') && $inputs.addClass('dummyie').removeClass('dummyie'); - } - }); - }); - var diff = left + $opcon.width() - $('#imce-content').width(); - $opcon.css({left: diff > 0 ? left - diff : left}); - $(Op.li).addClass('active'); - $(imce.opCloseLink).css('visibility', 'visible'); - imce.vars.op = name; - } - Op.func(true); - return true; -}, - -//enable a file operation -opEnable: function(name) { - var Op = imce.ops[name]; - if (Op && Op.disabled) { - Op.disabled = false; - $(Op.li).show(); - } -}, - -//disable a file operation -opDisable: function(name) { - var Op = imce.ops[name]; - if (Op && !Op.disabled) { - Op.div && imce.opShrink(name); - $(Op.li).hide(); - Op.disabled = true; - } -}, - -//hide contents of a file operation -opShrink: function(name, effect) { - if (imce.vars.op != name) return; - var Op = imce.ops[name]; - $(Op.div).stop(true, true)[effect || 'hide'](); - $(Op.li).removeClass('active'); - $(imce.opCloseLink).css('visibility', 'hidden'); - Op.func(false); - imce.vars.op = null; -}, - -/**************** AJAX OPERATIONS ********************/ - -//navigate to dir -navigate: function(dir) { - if (imce.vars.navbusy || (dir == imce.conf.dir && !confirm(Drupal.t('Do you want to refresh the current directory?')))) return; - var cache = imce.vars.cache && dir != imce.conf.dir; - var set = imce.navSet(dir, cache); - if (cache && imce.cache[dir]) {//load from the cache - set.success({data: imce.cache[dir]}); - set.complete(); - } - else $.ajax(set);//live load -}, -//ajax navigation settings -navSet: function (dir, cache) { - $(imce.tree[dir].li).addClass('loading'); - imce.vars.navbusy = dir; - return {url: imce.ajaxURL('navigate', dir), - type: 'GET', - dataType: 'json', - success: function(response) { - if (response.data && !response.data.error) { - if (cache) imce.navCache(imce.conf.dir, dir);//cache the current dir - imce.navUpdate(response.data, dir); - } - imce.processResponse(response); - }, - complete: function () { - $(imce.tree[dir].li).removeClass('loading'); - imce.vars.navbusy = null; - } - }; -}, - -//update directory using the given data -navUpdate: function(data, dir) { - var cached = data == imce.cache[dir], olddir = imce.conf.dir; - if (cached) data.files.id = 'file-list'; - $(imce.FLW).html(data.files); - imce.dirActivate(dir); - imce.dirSubdirs(dir, data.subdirectories); - $.extend(imce.conf.perm, data.perm); - imce.refreshOps(); - imce.initiateList(cached); - imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); - imce.SBW.scrollTop = 0; - imce.invoke('navigate', data, olddir, cached); -}, - -//set cache -navCache: function (dir, newdir) { - var C = imce.cache[dir] = {'dir': dir, files: imce.el('file-list'), dirsize: imce.el('dir-size').innerHTML, perm: $.extend({}, imce.conf.perm)}; - C.files.id = 'cached-list-'+ dir; - imce.el('forms-wrapper').appendChild(C.files); - imce.invoke('cache', C, newdir); -}, - -/**************** UPLOAD ********************/ -//validate upload form -uploadValidate: function (data, form, options) { - var path = data[0].value; - if (!path) return false; - if (imce.conf.extensions != '*') { - var ext = path.substr(path.lastIndexOf('.') + 1); - if ((' '+ imce.conf.extensions +' ').indexOf(' '+ ext.toLowerCase() +' ') == -1) { - return imce.setMessage(Drupal.t('Only files with the following extensions are allowed: %files-allowed.', {'%files-allowed': imce.conf.extensions}), 'error'); - } - } - var sep = path.indexOf('/') == -1 ? '\\' : '/'; - options.url = imce.ajaxURL('upload');//make url contain current dir. - imce.fopLoading('upload', true); - return true; -}, - -//settings for upload -uploadSettings: function () { - return {beforeSubmit: imce.uploadValidate, success: function (response) {imce.processResponse(Drupal.parseJson(response));}, complete: function () {imce.fopLoading('upload', false);}, resetForm: true}; -}, - -/**************** FILE OPS ********************/ -//validate default ops(delete, thumb, resize) -fopValidate: function(fop) { - if (!imce.validateSelCount(1, imce.conf.filenum)) return false; - switch (fop) { - case 'delete': - return confirm(Drupal.t('Delete selected files?')); - case 'thumb': - if (!$('input:checked', imce.ops['thumb'].div).size()) { - return imce.setMessage(Drupal.t('Please select a thumbnail.'), 'error'); - } - return imce.validateImage(); - case 'resize': - var w = imce.el('edit-width').value, h = imce.el('edit-height').value; - var maxDim = imce.conf.dimensions.split('x'); - var maxW = maxDim[0]*1, maxH = maxW ? maxDim[1]*1 : 0; - if (!(/^[1-9][0-9]*$/).test(w) || !(/^[1-9][0-9]*$/).test(h) || (maxW && (maxW < w*1 || maxH < h*1))) { - return imce.setMessage(Drupal.t('Please specify dimensions within the allowed range that is from 1x1 to @dimensions.', {'@dimensions': maxW ? imce.conf.dimensions : Drupal.t('unlimited')}), 'error'); - } - return imce.validateImage(); - } - - var func = fop +'OpValidate'; - if (imce[func]) return imce[func](fop); - return true; -}, - -//submit wrapper for default ops -fopSubmit: function(fop) { - switch (fop) { - case 'thumb': case 'delete': case 'resize': return imce.commonSubmit(fop); - } - var func = fop +'OpSubmit'; - if (imce[func]) return imce[func](fop); -}, - -//common submit function shared by default ops -commonSubmit: function(fop) { - if (!imce.fopValidate(fop)) return false; - imce.fopLoading(fop, true); - $.ajax(imce.fopSettings(fop)); -}, - -//settings for default file operations -fopSettings: function (fop) { - return {url: imce.ajaxURL(fop), type: 'POST', dataType: 'json', success: imce.processResponse, complete: function (response) {imce.fopLoading(fop, false);}, data: imce.vars.opform +'&filenames='+ imce.serialNames() +'&jsop='+ fop + (imce.ops[fop].div ? '&'+ $('input, select, textarea', imce.ops[fop].div).serialize() : '')}; -}, - -//toggle loading state -fopLoading: function(fop, state) { - var el = imce.el('edit-'+ fop), func = state ? 'addClass' : 'removeClass' - if (el) { - $(el)[func]('loading').attr('disabled', state); - } - else { - $(imce.ops[fop].li)[func]('loading'); - imce.ops[fop].disabled = state; - } -}, - -/**************** PREVIEW & SEND TO ********************/ - -//preview a file. -setPreview: function (fid) { - var row, html = ''; - imce.vars.prvfid = fid; - if (fid && (row = imce.fids[fid])) { - var width = row.cells[2].innerHTML * 1; - html = imce.vars.previewImages && width ? imce.imgHtml(fid, width, row.cells[3].innerHTML) : imce.decode(fid); - html = ''+ html +''; - } - imce.el('file-preview').innerHTML = html; -}, - -//default file send function. sends the file to the new window. -send: function (fid) { - fid && window.open(imce.getURL(fid)); -}, - -//add an operation for an external application to which the files are send. -setSendTo: function (title, func) { - imce.send = function (fid) { fid && func(imce.fileGet(fid), window);}; - var opFunc = function () { - if (imce.selcount != 1) return imce.setMessage(Drupal.t('Please select a file.'), 'error'); - imce.send(imce.vars.prvfid); - }; - imce.vars.prvtitle = title; - return imce.opAdd({name: 'sendto', title: title, func: opFunc}); -}, - -/**************** LOG MESSAGES ********************/ - -//move initial page messages into log -prepareMsgs: function () { - var msgs; - if (msgs = imce.el('imce-messages')) { - $('>div', msgs).each(function (){ - var type = this.className.split(' ')[1]; - var li = $('>ul li', this); - if (li.size()) li.each(function () {imce.setMessage(this.innerHTML, type);}); - else imce.setMessage(this.innerHTML, type); - }); - $(msgs).remove(); - } -}, - -//insert log message -setMessage: function (msg, type) { - var $box = $(imce.msgBox); - var logs = imce.el('log-messages') || $(imce.newEl('div')).appendTo('#help-box-content').before('

'+ Drupal.t('Log messages') +':

').attr('id', 'log-messages')[0]; - var msg = '
'+ msg +'
'; - $box.queue(function() { - $box.css({opacity: 0, display: 'block'}).html(msg); - $box.dequeue(); - }); - $box.fadeTo(600, 1).fadeTo(1000, 1).fadeOut(400); - $(logs).append(msg); - return false; -}, - -/**************** OTHER HELPER FUNCTIONS ********************/ -//invoke hooks -invoke: function (hook) { - var i, args, func, funcs; - if ((funcs = imce.hooks[hook]) && funcs.length) { - (args = $.makeArray(arguments)).shift(); - for (i = 0; func = funcs[i]; i++) func.apply(this, args); - } -}, - -//process response -processResponse: function (response) { - if (response.data) imce.resData(response.data); - if (response.messages) imce.resMsgs(response.messages); -}, -//process response data -resData: function (data) { - var i, added, removed; - if (added = data.added) { - var cnt = imce.findex.length; - for (i in added) {//add new files or update existing - imce.fileAdd(added[i]); - } - if (added.length == 1) {//if it is a single file operation - imce.highlight(added[0].name);//highlight - } - if (imce.findex.length != cnt) {//if new files added, scroll to bottom. - $(imce.SBW).animate({scrollTop: imce.SBW.scrollHeight}).focus(); - } - } - if (removed = data.removed) for (i in removed) { - imce.fileRemove(removed[i]); - } - imce.conf.dirsize = data.dirsize; - imce.updateStat(); -}, -//set response messages -resMsgs: function (msgs) { - for (var type in msgs) for (var i in msgs[type]) { - imce.setMessage(msgs[type][i], type); - } -}, - -//return img markup -imgHtml: function (fid, width, height) { - return ''+ imce.decode(fid) +''; -}, -//check if the file is an image -isImage: function (fid) { - return imce.fids[fid].cells[2].innerHTML * 1; -}, -//find the first non-image in the selection -getNonImage: function (selected) { - for (var fid in selected) { - if (!imce.isImage(fid)) return fid; - } - return false; -}, -//validate current selection for images -validateImage: function () { - var nonImg = imce.getNonImage(imce.selected); - return nonImg ? imce.setMessage(Drupal.t('%filename is not an image.', {'%filename': imce.decode(nonImg)}), 'error') : true; -}, -//validate number of selected files -validateSelCount: function (Min, Max) { - if (Min && imce.selcount < Min) { - return imce.setMessage(Min == 1 ? Drupal.t('Please select a file.') : Drupal.t('You must select at least %num files.', {'%num': Min}), 'error'); - } - if (Max && Max < imce.selcount) { - return imce.setMessage(Drupal.t('You are not allowed to operate on more than %num files.', {'%num': Max}), 'error'); - } - return true; -}, - -//update file count and dir size -updateStat: function () { - imce.el('file-count').innerHTML = imce.findex.length; - imce.el('dir-size').innerHTML = imce.conf.dirsize; -}, -//serialize selected files. return fids with a colon between them -serialNames: function () { - var str = ''; - for (var fid in imce.selected) { - str += ':'+ fid; - } - return str.substr(1); -}, -//get file url. re-encode & and # for mod rewrite -getURL: function (fid) { - var path = (imce.conf.dir == '.' ? '' : imce.conf.dir +'/') + fid; - return imce.conf.furl + (imce.conf.modfix ? path.replace(/%(23|26)/g, '%25$1') : path); -}, -//el. by id -el: function (id) { - return document.getElementById(id); -}, -//find the latest selected fid -lastFid: function () { - if (imce.vars.lastfid) return imce.vars.lastfid; - for (var fid in imce.selected); - return fid; -}, -//create ajax url -ajaxURL: function (op, dir) { - return imce.conf.url + (imce.conf.clean ? '?' :'&') +'jsop='+ op +'&dir='+ (dir||imce.conf.dir); -}, -//fast class check -hasC: function (el, name) { - return el.className && (' '+ el.className +' ').indexOf(' '+ name +' ') != -1; -}, -//highlight a single file -highlight: function (fid) { - if (imce.vars.prvfid) imce.fileClick(imce.vars.prvfid); - imce.fileClick(fid); -}, -//process a row -processRow: function (row) { - row.cells[0].innerHTML = imce.decode(row.id); - row.onmousedown = function(e) { - var e = e||window.event; - imce.fileClick(this, e.ctrlKey, e.shiftKey); - return !(e.ctrlKey || e.shiftKey); - }; - row.ondblclick = function(e) { - imce.send(this.id); - return false; - }; -}, -//decode urls. uses unescape. can be overridden to use decodeURIComponent -decode: function (str) { - return unescape(str); -}, -//global ajax error function -ajaxError: function (e, response, settings, thrown) { - imce.setMessage(Drupal.ahahError(response, settings.url).replace(/\n/g, '
'), 'error'); -}, -//convert button elements to standard input buttons -convertButtons: function(form) { - $('button:submit', form).each(function(){ - $(this).replaceWith(''); - }); -}, -//create element -newEl: function(name) { - return document.createElement(name); -}, -//scroll syncronization for section headers -syncScroll: function(scrlEl, fixEl, bottom) { - var $fixEl = $(fixEl); - var prop = bottom ? 'bottom' : 'top'; - var factor = bottom ? -1 : 1; - var syncScrl = function(el) { - $fixEl.css(prop, factor * el.scrollTop); - } - $(scrlEl).scroll(function() { - var el = this; - syncScrl(el); - setTimeout(function() { - syncScrl(el); - }); - }); -}, -//get UI ready. provide backward compatibility. -updateUI: function() { - //file urls. - var furl = imce.conf.furl, isabs = furl.indexOf('://') > -1; - var absurls = imce.conf.absurls = imce.vars.absurls || imce.conf.absurls; - var host = location.host; - var baseurl = location.protocol + '//' + host; - if (furl.charAt(furl.length - 1) != '/') { - furl += '/'; - } - imce.conf.modfix = imce.conf.clean && furl.indexOf(host + '/system/') > -1; - if (absurls && !isabs) { - imce.conf.furl = baseurl + furl; - } - else if (!absurls && isabs && furl.indexOf(baseurl) == 0) { - imce.conf.furl = furl.substr(baseurl.length); - } - //convert button elements to input elements. - imce.convertButtons(imce.el('forms-wrapper')); - //ops-list - $('#ops-list').removeClass('tabs secondary').addClass('clear-block clearfix'); - imce.opCloseLink = $(imce.newEl('a')).attr({id: 'op-close-link', href: '#', title: Drupal.t('Close')}).click(function() { - imce.vars.op && imce.opClick(imce.vars.op); - return false; - }).appendTo('#op-contents')[0]; - //navigation-header - if (!$('#navigation-header').size()) { - $('#navigation-wrapper > .navigation-text').attr('id', 'navigation-header').wrapInner(''); - } - //log - $('#log-prv-wrapper').before($('#log-prv-wrapper > #preview-wrapper')).remove(); - $('#log-clearer').remove(); - //content resizer - $('#content-resizer').remove(); - //message-box - imce.msgBox = imce.el('message-box') || $('
').prependTo('#imce-content')[0]; - //help box & ie fix - var $hbox = $('#help-box'); - $hbox.is('a') && $hbox.replaceWith($(imce.newEl('div')).attr('id', 'help-box').append($hbox.children())); - var $htitle = $('#help-box-title'); - if ($.browser.msie) { - $('html').addClass('ie'); - if (parseFloat($.browser.version) < 8) { - var $hcontent = $('#help-box-content'); - $hcontent.add($htitle).hover(function() { - $hcontent.addClass('hover'); - }, function() { - $hcontent.removeClass('hover'); - }); - $('html').addClass('ie-7'); - } - } - !$htitle.children('span').size() && $htitle.wrapInner(''); - //scrolling file list - imce.syncScroll(imce.SBW, '#file-header-wrapper'); - imce.syncScroll(imce.SBW, '#dir-stat', true); - //scrolling directory tree - imce.syncScroll('#navigation-wrapper', '#navigation-header'); -} -}; - -//initiate -$(document).ready(imce.initiate).ajaxError(imce.ajaxError); - +// $Id: imce.js,v 1.2 2010/08/31 16:36:17 c0aslm1 Exp $ + +(function($) { +//Global container. +window.imce = {tree: {}, findex: [], fids: {}, selected: {}, selcount: 0, ops: {}, cache: {}, urlId: {}, +vars: {previewImages: 1, cache: 1}, +hooks: {load: [], list: [], navigate: [], cache: []}, + +//initiate imce. +initiate: function() { + imce.conf = Drupal.settings.imce || {}; + if (imce.conf.error != false) return; + imce.FLW = imce.el('file-list-wrapper'); + imce.SBW = imce.el('sub-browse-wrapper'); + imce.updateUI(); + imce.prepareMsgs();//process initial status messages + imce.initiateTree();//build directory tree + imce.hooks.list.unshift(imce.processRow);//set the default list-hook. + imce.initiateList();//process file list + imce.initiateOps();//prepare operation tabs + imce.refreshOps(); + imce.invoke('load', window);//run functions set by external applications. +}, + +/**************** DIRECTORIES ********************/ + +//process navigation tree +initiateTree: function() { + $('#navigation-tree li').each(function(i) { + var a = this.firstChild, txt = a.firstChild; + txt && (txt.data = imce.decode(txt.data)); + var branch = imce.tree[a.title] = {'a': a, li: this, ul: this.lastChild.tagName == 'UL' ? this.lastChild : null}; + if (a.href) imce.dirClickable(branch); + imce.dirCollapsible(branch); + }); +}, + +//Add a dir to the tree under parent +dirAdd: function(dir, parent, clickable) { + if (imce.tree[dir]) return clickable ? imce.dirClickable(imce.tree[dir]) : imce.tree[dir]; + var parent = parent || imce.tree['.']; + parent.ul = parent.ul ? parent.ul : parent.li.appendChild(imce.newEl('ul')); + var branch = imce.dirCreate(dir, imce.decode(dir.substr(dir.lastIndexOf('/')+1)), clickable); + parent.ul.appendChild(branch.li); + return branch; +}, + +//create list item for navigation tree +dirCreate: function(dir, text, clickable) { + if (imce.tree[dir]) return imce.tree[dir]; + var branch = imce.tree[dir] = {li: imce.newEl('li'), a: imce.newEl('a')}; + $(branch.a).addClass('folder').text(text).attr('title', dir).appendTo(branch.li); + imce.dirCollapsible(branch); + return clickable ? imce.dirClickable(branch) : branch; +}, + +//change currently active directory +dirActivate: function(dir) { + if (dir != imce.conf.dir) { + if (imce.tree[imce.conf.dir]){ + $(imce.tree[imce.conf.dir].a).removeClass('active'); + } + $(imce.tree[dir].a).addClass('active'); + imce.conf.dir = dir; + } + return imce.tree[imce.conf.dir]; +}, + +//make a dir accessible +dirClickable: function(branch) { + if (branch.clkbl) return branch; + $(branch.a).attr('href', '#').removeClass('disabled').click(function() {imce.navigate(this.title); return false;}); + branch.clkbl = true; + return branch; +}, + +//sub-directories expand-collapse ability +dirCollapsible: function (branch) { + if (branch.clpsbl) return branch; + $(imce.newEl('span')).addClass('expander').html(' ').click(function() { + if (branch.ul) { + $(branch.ul).toggle(); + $(branch.li).toggleClass('expanded'); + } + else if (branch.clkbl){ + $(branch.a).click(); + } + }).prependTo(branch.li); + branch.clpsbl = true; + return branch; +}, + +//update navigation tree after getting subdirectories. +dirSubdirs: function(dir, subdirs) { + var branch = imce.tree[dir]; + if (subdirs && subdirs.length) { + var prefix = dir == '.' ? '' : dir +'/'; + for (var i in subdirs) {//add subdirectories + imce.dirAdd(prefix + subdirs[i], branch, true); + } + $(branch.li).removeClass('leaf').addClass('expanded'); + $(branch.ul).show(); + } + else if (!branch.ul){//no subdirs->leaf + $(branch.li).removeClass('expanded').addClass('leaf'); + } +}, + +/**************** FILES ********************/ + +//process file list +initiateList: function(cached) { + var L = imce.hooks.list, dir = imce.conf.dir, token = {'%dir': dir == '.' ? $(imce.tree['.'].a).text() : imce.decode(dir)} + imce.findex = [], imce.fids = {}, imce.selected = {}, imce.selcount = 0, imce.vars.lastfid = null; + imce.tbody = imce.el('file-list').tBodies[0]; + if (imce.tbody.rows.length) { + for (var row, i = 0; row = imce.tbody.rows[i]; i++) { + var fid = row.id; + imce.findex[i] = imce.fids[fid] = row; + if (cached) { + if (imce.hasC(row, 'selected')) { + imce.selected[imce.vars.lastfid = fid] = row; + imce.selcount++; + } + } + else { + for (var func, j = 0; func = L[j]; j++) func(row);//invoke list-hook + } + } + } + if (!imce.conf.perm.browse) { + imce.setMessage(Drupal.t('File browsing is disabled in directory %dir.', token), 'error'); + } +}, + +//add a file to the list. (having properties name,size,formatted size,width,height,date,formatted date) +fileAdd: function(file) { + var row, fid = file.name, i = imce.findex.length, attr = ['name', 'size', 'width', 'height', 'date']; + if (!(row = imce.fids[fid])) { + row = imce.findex[i] = imce.fids[fid] = imce.tbody.insertRow(i); + for (var i in attr) row.insertCell(i).className = attr[i]; + } + row.cells[0].innerHTML = row.id = fid; + row.cells[1].innerHTML = file.fsize; row.cells[1].id = file.size; + row.cells[2].innerHTML = file.width; + row.cells[3].innerHTML = file.height; + row.cells[4].innerHTML = file.fdate; row.cells[4].id = file.date; + imce.invoke('list', row); + if (imce.vars.prvfid == fid) imce.setPreview(fid); + if (file.id) imce.urlId[imce.getURL(fid)] = file.id; +}, + +//remove a file from the list +fileRemove: function(fid) { + if (!(row = imce.fids[fid])) return; + imce.fileDeSelect(fid); + imce.findex.splice(row.rowIndex, 1); + $(row).remove(); + delete imce.fids[fid]; + if (imce.vars.prvfid == fid) imce.setPreview(); +}, + +//return a file object containing all properties. +fileGet: function (fid) { + var row = imce.fids[fid]; + var url = imce.getURL(fid); + return row ? { + name: imce.decode(fid), + url: url, + size: row.cells[1].innerHTML, + bytes: row.cells[1].id * 1, + width: row.cells[2].innerHTML * 1, + height: row.cells[3].innerHTML * 1, + date: row.cells[4].innerHTML, + time: row.cells[4].id * 1, + id: imce.urlId[url] || 0, //file id for newly uploaded files + relpath: (imce.conf.dir == '.' ? '' : imce.conf.dir +'/') + fid //rawurlencoded path relative to file directory path. + } : null; +}, + +//simulate row click. selection-highlighting +fileClick: function(row, ctrl, shft) { + if (!row) return; + var fid = typeof(row) == 'string' ? row : row.id; + if (ctrl || fid == imce.vars.prvfid) { + imce.fileToggleSelect(fid); + } + else if (shft) { + var last = imce.lastFid(); + var start = last ? imce.fids[last].rowIndex : -1; + var end = imce.fids[fid].rowIndex; + var step = start > end ? -1 : 1; + while (start != end) { + start += step; + imce.fileSelect(imce.findex[start].id); + } + } + else { + for (var fname in imce.selected) { + imce.fileDeSelect(fname); + } + imce.fileSelect(fid); + } + //set preview + imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); +}, + +//file select/deselect functions +fileSelect: function (fid) { + if (imce.selected[fid] || !imce.fids[fid]) return; + imce.selected[fid] = imce.fids[imce.vars.lastfid=fid]; + $(imce.selected[fid]).addClass('selected'); + imce.selcount++; +}, +fileDeSelect: function (fid) { + if (!imce.selected[fid] || !imce.fids[fid]) return; + if (imce.vars.lastfid == fid) imce.vars.lastfid = null; + $(imce.selected[fid]).removeClass('selected'); + delete imce.selected[fid]; + imce.selcount--; +}, +fileToggleSelect: function (fid) { + imce['file'+ (imce.selected[fid] ? 'De' : '') +'Select'](fid); +}, + +/**************** OPERATIONS ********************/ + +//process file operation form and create operation tabs. +initiateOps: function() { + imce.setHtmlOps(); + imce.setUploadOp();//upload + imce.setFileOps();//thumb, delete, resize +}, + +//process existing html ops. +setHtmlOps: function () { + $(imce.el('ops-list')).children('li').each(function() { + if (!this.firstChild) return $(this).remove(); + var name = this.id.substr(8); + var Op = imce.ops[name] = {div: imce.el('op-content-'+ name), li: imce.el('op-item-'+ name)}; + Op.a = Op.li.firstChild; + Op.title = Op.a.innerHTML; + $(Op.a).click(function() {imce.opClick(name); return false;}); + }); +}, + +//convert upload form to an op. +setUploadOp: function () { + var form = imce.el('imce-upload-form'); + if (!form) return; + $(form).ajaxForm(imce.uploadSettings()).find('fieldset').each(function() {//clean up fieldsets + this.removeChild(this.firstChild); + $(this).after(this.childNodes); + }).remove(); + imce.opAdd({name: 'upload', title: Drupal.t('Upload'), content: form});//add op +}, + +//convert fileop form submit buttons to ops. +setFileOps: function () { + var form = imce.el('imce-fileop-form'); + if (!form) return; + $(form.elements.filenames).parent().remove(); + $(form).find('fieldset').each(function() {//remove fieldsets + var $sbmt = $('input:submit', this); + if (!$sbmt.size()) return; + var Op = {name: $sbmt.attr('id').substr(5)}; + var func = function() {imce.fopSubmit(Op.name); return false;}; + $sbmt.click(func); + Op.title = $(this).children('legend').remove().text(); + Op.name == 'delete' ? (Op.func = func) : (Op.content = this.childNodes); + imce.opAdd(Op); + }).remove(); + imce.vars.opform = $(form).serialize();//serialize remaining parts. +}, + +//refresh ops states. enable/disable +refreshOps: function() { + for (var p in imce.conf.perm) { + if (imce.conf.perm[p]) imce.opEnable(p); + else imce.opDisable(p); + } +}, + +//add a new file operation +opAdd: function (op) { + var oplist = imce.el('ops-list'), opcons = imce.el('op-contents'); + var name = op.name || ('op-'+ $(oplist).children('li').size()); + var Op = imce.ops[name] = {title: op.title || 'Untitled'}; + if (op.content) { + Op.div = imce.newEl('div'); + $(Op.div).attr({id: 'op-content-'+ name, 'class': 'op-content'}).appendTo(opcons).append(op.content); + } + Op.a = imce.newEl('a'); + Op.li = imce.newEl('li'); + $(Op.a).attr({href: '#', 'name': name}).html('' + op.title +'').click(imce.opClickEvent); + $(Op.li).attr('id', 'op-item-'+ op.name).append(Op.a).appendTo(oplist); + Op.func = op.func || imce.opVoid; + return Op; +}, + +//click event for file operations +opClickEvent: function(e) { + imce.opClick(this.name); + return false; +}, + +//void operation function +opVoid: function() {}, + +//perform op click +opClick: function(name) { + var Op = imce.ops[name], oldop = imce.vars.op; + if (!Op || Op.disabled) { + return imce.setMessage(Drupal.t('You can not perform this operation.'), 'error'); + } + if (Op.div) { + if (oldop) { + var toggle = oldop == name; + imce.opShrink(oldop, toggle ? 'slideUp' : 'hide'); + if (toggle) return false; + } + var left = Op.li.offsetLeft; + var $opcon = $('#op-contents').css({left: 0}); + $(Op.div).slideDown('normal', function() { + setTimeout(function() { + if (imce.vars.op) { + var $inputs = $('input', imce.ops[imce.vars.op].div); + $inputs.eq(0).focus(); + //form inputs become invisible in IE. Solution is as stupid as the behavior. + $('html').is('.ie') && $inputs.addClass('dummyie').removeClass('dummyie'); + } + }); + }); + var diff = left + $opcon.width() - $('#imce-content').width(); + $opcon.css({left: diff > 0 ? left - diff : left}); + $(Op.li).addClass('active'); + $(imce.opCloseLink).css('visibility', 'visible'); + imce.vars.op = name; + } + Op.func(true); + return true; +}, + +//enable a file operation +opEnable: function(name) { + var Op = imce.ops[name]; + if (Op && Op.disabled) { + Op.disabled = false; + $(Op.li).show(); + } +}, + +//disable a file operation +opDisable: function(name) { + var Op = imce.ops[name]; + if (Op && !Op.disabled) { + Op.div && imce.opShrink(name); + $(Op.li).hide(); + Op.disabled = true; + } +}, + +//hide contents of a file operation +opShrink: function(name, effect) { + if (imce.vars.op != name) return; + var Op = imce.ops[name]; + $(Op.div).stop(true, true)[effect || 'hide'](); + $(Op.li).removeClass('active'); + $(imce.opCloseLink).css('visibility', 'hidden'); + Op.func(false); + imce.vars.op = null; +}, + +/**************** AJAX OPERATIONS ********************/ + +//navigate to dir +navigate: function(dir) { + if (imce.vars.navbusy || (dir == imce.conf.dir && !confirm(Drupal.t('Do you want to refresh the current directory?')))) return; + var cache = imce.vars.cache && dir != imce.conf.dir; + var set = imce.navSet(dir, cache); + if (cache && imce.cache[dir]) {//load from the cache + set.success({data: imce.cache[dir]}); + set.complete(); + } + else $.ajax(set);//live load +}, +//ajax navigation settings +navSet: function (dir, cache) { + $(imce.tree[dir].li).addClass('loading'); + imce.vars.navbusy = dir; + return {url: imce.ajaxURL('navigate', dir), + type: 'GET', + dataType: 'json', + success: function(response) { + if (response.data && !response.data.error) { + if (cache) imce.navCache(imce.conf.dir, dir);//cache the current dir + imce.navUpdate(response.data, dir); + } + imce.processResponse(response); + }, + complete: function () { + $(imce.tree[dir].li).removeClass('loading'); + imce.vars.navbusy = null; + } + }; +}, + +//update directory using the given data +navUpdate: function(data, dir) { + var cached = data == imce.cache[dir], olddir = imce.conf.dir; + if (cached) data.files.id = 'file-list'; + $(imce.FLW).html(data.files); + imce.dirActivate(dir); + imce.dirSubdirs(dir, data.subdirectories); + $.extend(imce.conf.perm, data.perm); + imce.refreshOps(); + imce.initiateList(cached); + imce.setPreview(imce.selcount == 1 ? imce.lastFid() : null); + imce.SBW.scrollTop = 0; + imce.invoke('navigate', data, olddir, cached); +}, + +//set cache +navCache: function (dir, newdir) { + var C = imce.cache[dir] = {'dir': dir, files: imce.el('file-list'), dirsize: imce.el('dir-size').innerHTML, perm: $.extend({}, imce.conf.perm)}; + C.files.id = 'cached-list-'+ dir; + imce.el('forms-wrapper').appendChild(C.files); + imce.invoke('cache', C, newdir); +}, + +/**************** UPLOAD ********************/ +//check to see if the file being uploaded exists +fileExistCheck: function(path) { + // check for slashes because IE includes entire filepath + if(path.lastIndexOf('\\') != -1){ + var path = path.substr(path.lastIndexOf('\\') + 1); + }else{ + var path = path; + } + var found = 0; + var file = $('#file-list tr td.name:contains(' + path + ')'); + if(file.length > 0){ + found = 1; + } + if(found == 1){ + var answer = confirm(path + ' already exists. Overwrite this file?'); + if(answer == false){ + return false; + } else{ + return true; + } + } + return; +}, + + +//validate upload form +uploadValidate: function (data, form, options) { + var path = data[0].value; + if (!path) return false; + if(imce.upload_method == 1){ + var exist = imce.fileExistCheck(path); + if (exist == false){ + return false; + } + } + if (imce.conf.extensions != '*') { + var ext = path.substr(path.lastIndexOf('.') + 1); + if ((' '+ imce.conf.extensions +' ').indexOf(' '+ ext.toLowerCase() +' ') == -1) { + return imce.setMessage(Drupal.t('Only files with the following extensions are allowed: %files-allowed.', {'%files-allowed': imce.conf.extensions}), 'error'); + } + } + var sep = path.indexOf('/') == -1 ? '\\' : '/'; + options.url = imce.ajaxURL('upload');//make url contain current dir. + imce.fopLoading('upload', true); + return true; +}, + +//settings for upload +uploadSettings: function () { + return {beforeSubmit: imce.uploadValidate, success: function (response) {imce.processResponse(Drupal.parseJson(response));}, complete: function () {imce.fopLoading('upload', false);}, resetForm: true}; +}, + +/**************** FILE OPS ********************/ +//validate default ops(delete, thumb, resize) +fopValidate: function(fop) { + if (!imce.validateSelCount(1, imce.conf.filenum)) return false; + switch (fop) { + case 'delete': + return confirm(Drupal.t('Delete selected files?')); + case 'thumb': + if (!$('input:checked', imce.ops['thumb'].div).size()) { + return imce.setMessage(Drupal.t('Please select a thumbnail.'), 'error'); + } + return imce.validateImage(); + case 'resize': + var w = imce.el('edit-width').value, h = imce.el('edit-height').value; + var maxDim = imce.conf.dimensions.split('x'); + var maxW = maxDim[0]*1, maxH = maxW ? maxDim[1]*1 : 0; + if (!(/^[1-9][0-9]*$/).test(w) || !(/^[1-9][0-9]*$/).test(h) || (maxW && (maxW < w*1 || maxH < h*1))) { + return imce.setMessage(Drupal.t('Please specify dimensions within the allowed range that is from 1x1 to @dimensions.', {'@dimensions': maxW ? imce.conf.dimensions : Drupal.t('unlimited')}), 'error'); + } + return imce.validateImage(); + } + + var func = fop +'OpValidate'; + if (imce[func]) return imce[func](fop); + return true; +}, + +//submit wrapper for default ops +fopSubmit: function(fop) { + switch (fop) { + case 'thumb': case 'delete': case 'resize': return imce.commonSubmit(fop); + } + var func = fop +'OpSubmit'; + if (imce[func]) return imce[func](fop); +}, + +//common submit function shared by default ops +commonSubmit: function(fop) { + if (!imce.fopValidate(fop)) return false; + imce.fopLoading(fop, true); + $.ajax(imce.fopSettings(fop)); +}, + +//settings for default file operations +fopSettings: function (fop) { + return {url: imce.ajaxURL(fop), type: 'POST', dataType: 'json', success: imce.processResponse, complete: function (response) {imce.fopLoading(fop, false);}, data: imce.vars.opform +'&filenames='+ imce.serialNames() +'&jsop='+ fop + (imce.ops[fop].div ? '&'+ $('input, select, textarea', imce.ops[fop].div).serialize() : '')}; +}, + +//toggle loading state +fopLoading: function(fop, state) { + var el = imce.el('edit-'+ fop), func = state ? 'addClass' : 'removeClass' + if (el) { + $(el)[func]('loading').attr('disabled', state); + } + else { + $(imce.ops[fop].li)[func]('loading'); + imce.ops[fop].disabled = state; + } +}, + +/**************** PREVIEW & SEND TO ********************/ + +//preview a file. +setPreview: function (fid) { + var row, html = ''; + imce.vars.prvfid = fid; + if (fid && (row = imce.fids[fid])) { + var width = row.cells[2].innerHTML * 1; + html = imce.vars.previewImages && width ? imce.imgHtml(fid, width, row.cells[3].innerHTML) : imce.decode(fid); + html = ''+ html +''; + } + imce.el('file-preview').innerHTML = html; +}, + +//default file send function. sends the file to the new window. +send: function (fid) { + fid && window.open(imce.getURL(fid)); +}, + +//add an operation for an external application to which the files are send. +setSendTo: function (title, func) { + imce.send = function (fid) { fid && func(imce.fileGet(fid), window);}; + var opFunc = function () { + if (imce.selcount != 1) return imce.setMessage(Drupal.t('Please select a file.'), 'error'); + imce.send(imce.vars.prvfid); + }; + imce.vars.prvtitle = title; + return imce.opAdd({name: 'sendto', title: title, func: opFunc}); +}, + +/**************** LOG MESSAGES ********************/ + +//move initial page messages into log +prepareMsgs: function () { + var msgs; + if (msgs = imce.el('imce-messages')) { + $('>div', msgs).each(function (){ + var type = this.className.split(' ')[1]; + var li = $('>ul li', this); + if (li.size()) li.each(function () {imce.setMessage(this.innerHTML, type);}); + else imce.setMessage(this.innerHTML, type); + }); + $(msgs).remove(); + } +}, + +//insert log message +setMessage: function (msg, type) { + var $box = $(imce.msgBox); + var logs = imce.el('log-messages') || $(imce.newEl('div')).appendTo('#help-box-content').before('

'+ Drupal.t('Log messages') +':

').attr('id', 'log-messages')[0]; + var msg = '
'+ msg +'
'; + $box.queue(function() { + $box.css({opacity: 0, display: 'block'}).html(msg); + $box.dequeue(); + }); + $box.fadeTo(600, 1).fadeTo(1000, 1).fadeOut(400); + $(logs).append(msg); + return false; +}, + +/**************** OTHER HELPER FUNCTIONS ********************/ +//invoke hooks +invoke: function (hook) { + var i, args, func, funcs; + if ((funcs = imce.hooks[hook]) && funcs.length) { + (args = $.makeArray(arguments)).shift(); + for (i = 0; func = funcs[i]; i++) func.apply(this, args); + } +}, + +//process response +processResponse: function (response) { + if (response.data) imce.resData(response.data); + if (response.messages) imce.resMsgs(response.messages); +}, +//process response data +resData: function (data) { + var i, added, removed; + if (added = data.added) { + var cnt = imce.findex.length; + for (i in added) {//add new files or update existing + imce.fileAdd(added[i]); + } + if (added.length == 1) {//if it is a single file operation + imce.highlight(added[0].name);//highlight + } + if (imce.findex.length != cnt) {//if new files added, scroll to bottom. + $(imce.SBW).animate({scrollTop: imce.SBW.scrollHeight}).focus(); + } + } + if (removed = data.removed) for (i in removed) { + imce.fileRemove(removed[i]); + } + imce.conf.dirsize = data.dirsize; + imce.updateStat(); +}, +//set response messages +resMsgs: function (msgs) { + for (var type in msgs) for (var i in msgs[type]) { + imce.setMessage(msgs[type][i], type); + } +}, + +//return img markup +imgHtml: function (fid, width, height) { + return ''+ imce.decode(fid) +''; +}, +//check if the file is an image +isImage: function (fid) { + return imce.fids[fid].cells[2].innerHTML * 1; +}, +//find the first non-image in the selection +getNonImage: function (selected) { + for (var fid in selected) { + if (!imce.isImage(fid)) return fid; + } + return false; +}, +//validate current selection for images +validateImage: function () { + var nonImg = imce.getNonImage(imce.selected); + return nonImg ? imce.setMessage(Drupal.t('%filename is not an image.', {'%filename': imce.decode(nonImg)}), 'error') : true; +}, +//validate number of selected files +validateSelCount: function (Min, Max) { + if (Min && imce.selcount < Min) { + return imce.setMessage(Min == 1 ? Drupal.t('Please select a file.') : Drupal.t('You must select at least %num files.', {'%num': Min}), 'error'); + } + if (Max && Max < imce.selcount) { + return imce.setMessage(Drupal.t('You are not allowed to operate on more than %num files.', {'%num': Max}), 'error'); + } + return true; +}, + +//update file count and dir size +updateStat: function () { + imce.el('file-count').innerHTML = imce.findex.length; + imce.el('dir-size').innerHTML = imce.conf.dirsize; +}, +//serialize selected files. return fids with a colon between them +serialNames: function () { + var str = ''; + for (var fid in imce.selected) { + str += ':'+ fid; + } + return str.substr(1); +}, +//get file url. re-encode & and # for mod rewrite +getURL: function (fid) { + var path = (imce.conf.dir == '.' ? '' : imce.conf.dir +'/') + fid; + return imce.conf.furl + (imce.conf.modfix ? path.replace(/%(23|26)/g, '%25$1') : path); +}, +//el. by id +el: function (id) { + return document.getElementById(id); +}, +//find the latest selected fid +lastFid: function () { + if (imce.vars.lastfid) return imce.vars.lastfid; + for (var fid in imce.selected); + return fid; +}, +//create ajax url +ajaxURL: function (op, dir) { + return imce.conf.url + (imce.conf.clean ? '?' :'&') +'jsop='+ op +'&dir='+ (dir||imce.conf.dir); +}, +//fast class check +hasC: function (el, name) { + return el.className && (' '+ el.className +' ').indexOf(' '+ name +' ') != -1; +}, +//highlight a single file +highlight: function (fid) { + if (imce.vars.prvfid) imce.fileClick(imce.vars.prvfid); + imce.fileClick(fid); +}, +//process a row +processRow: function (row) { + row.cells[0].innerHTML = imce.decode(row.id); + row.onmousedown = function(e) { + var e = e||window.event; + imce.fileClick(this, e.ctrlKey, e.shiftKey); + return !(e.ctrlKey || e.shiftKey); + }; + row.ondblclick = function(e) { + imce.send(this.id); + return false; + }; +}, +//decode urls. uses unescape. can be overridden to use decodeURIComponent +decode: function (str) { + return unescape(str); +}, +//global ajax error function +ajaxError: function (e, response, settings, thrown) { + imce.setMessage(Drupal.ahahError(response, settings.url).replace(/\n/g, '
'), 'error'); +}, +//convert button elements to standard input buttons +convertButtons: function(form) { + $('button:submit', form).each(function(){ + $(this).replaceWith(''); + }); +}, +//create element +newEl: function(name) { + return document.createElement(name); +}, +//scroll syncronization for section headers +syncScroll: function(scrlEl, fixEl, bottom) { + var $fixEl = $(fixEl); + var prop = bottom ? 'bottom' : 'top'; + var factor = bottom ? -1 : 1; + var syncScrl = function(el) { + $fixEl.css(prop, factor * el.scrollTop); + } + $(scrlEl).scroll(function() { + var el = this; + syncScrl(el); + setTimeout(function() { + syncScrl(el); + }); + }); +}, +//get UI ready. provide backward compatibility. +updateUI: function() { + //file urls. + var furl = imce.conf.furl, isabs = furl.indexOf('://') > -1; + var absurls = imce.conf.absurls = imce.vars.absurls || imce.conf.absurls; + var host = location.host; + var baseurl = location.protocol + '//' + host; + if (furl.charAt(furl.length - 1) != '/') { + furl += '/'; + } + imce.conf.modfix = imce.conf.clean && furl.indexOf(host + '/system/') > -1; + if (absurls && !isabs) { + imce.conf.furl = baseurl + furl; + } + else if (!absurls && isabs && furl.indexOf(baseurl) == 0) { + imce.conf.furl = furl.substr(baseurl.length); + } + //convert button elements to input elements. + imce.convertButtons(imce.el('forms-wrapper')); + //ops-list + $('#ops-list').removeClass('tabs secondary').addClass('clear-block clearfix'); + imce.opCloseLink = $(imce.newEl('a')).attr({id: 'op-close-link', href: '#', title: Drupal.t('Close')}).click(function() { + imce.vars.op && imce.opClick(imce.vars.op); + return false; + }).appendTo('#op-contents')[0]; + //navigation-header + if (!$('#navigation-header').size()) { + $('#navigation-wrapper > .navigation-text').attr('id', 'navigation-header').wrapInner(''); + } + //log + $('#log-prv-wrapper').before($('#log-prv-wrapper > #preview-wrapper')).remove(); + $('#log-clearer').remove(); + //content resizer + $('#content-resizer').remove(); + //message-box + imce.msgBox = imce.el('message-box') || $('
').prependTo('#imce-content')[0]; + //help box & ie fix + var $hbox = $('#help-box'); + $hbox.is('a') && $hbox.replaceWith($(imce.newEl('div')).attr('id', 'help-box').append($hbox.children())); + var $htitle = $('#help-box-title'); + if ($.browser.msie) { + $('html').addClass('ie'); + if (parseFloat($.browser.version) < 8) { + var $hcontent = $('#help-box-content'); + $hcontent.add($htitle).hover(function() { + $hcontent.addClass('hover'); + }, function() { + $hcontent.removeClass('hover'); + }); + $('html').addClass('ie-7'); + } + } + !$htitle.children('span').size() && $htitle.wrapInner(''); + //scrolling file list + imce.syncScroll(imce.SBW, '#file-header-wrapper'); + imce.syncScroll(imce.SBW, '#dir-stat', true); + //scrolling directory tree + imce.syncScroll('#navigation-wrapper', '#navigation-header'); +} +}; + +//initiate +$(document).ready(imce.initiate).ajaxError(imce.ajaxError); + })(jQuery); \ No newline at end of file