View source
<?php
function filetree_theme() {
return array(
'filetree' => array(
'variables' => array(
'files' => array(),
'params' => array(),
),
),
);
}
function filetree_filter_info() {
$filters['filetree'] = array(
'title' => t('File Tree'),
'description' => t('Replaces [filetree dir="some-directory"] with an inline list of files.'),
'settings callback' => '_filetree_settings',
'default settings' => array(
'folders' => '*',
),
'tips callback' => '_filetree_tips',
'process callback' => '_filetree_process',
);
return $filters;
}
function filetree_token_info() {
$types['filetree'] = array(
'name' => t('File Tree Files'),
'description' => t('Tokens related to File Tree files.'),
);
$tokens['filename'] = array(
'name' => t('File name'),
'description' => t("The file's name and extension."),
);
$tokens['basename'] = array(
'name' => t('Base name'),
'description' => t("The file's name, without extension."),
);
$tokens['extension'] = array(
'name' => t('Extension'),
'description' => t("The file's extension."),
);
return compact('types', 'tokens');
}
function filetree_tokens($type, $tokens, array $data = array(), array $options = array()) {
$replacements = array();
if ($type == 'filetree') {
$pathinfo = pathinfo($data['file']);
foreach ($tokens as $name => $original) {
switch ($name) {
case 'filename':
$replacements[$original] = $pathinfo['basename'];
break;
case 'basename':
$replacements[$original] = $pathinfo['filename'];
break;
case 'extension':
$replacements[$original] = $pathinfo['extension'];
break;
}
}
}
return $replacements;
}
function _filetree_settings($form, &$form_state, $filter, $format, $defaults, $filters) {
$filter->settings += $defaults;
$elements['folders'] = array(
'#type' => 'textarea',
'#title' => t('Allowed folder paths'),
'#description' => t('Enter one folder per line as paths which are allowed to be rendered as a list of files (relative to your <a href="@url">file system path</a>). The "*" character is a wildcard. Example paths are "*", "some-folder", and "some-folder/*".', array(
'@url' => url('admin/config/media/file-system'),
)),
'#default_value' => $filter->settings['folders'],
);
return $elements;
}
function _filetree_tips($filter, $format, $long = FALSE) {
$output = t('You may use [filetree dir="some-directory"] to display a list of files inline.');
if ($long) {
$output = '<p>' . $output . '</p>';
$output .= '<p>' . t('Additional options include "multi", "controls", "absolute", "exclude", "dirname", "dirtitle", "filename", and "filetitle". For example:') . '</p>';
$output .= '<blockquote>[filetree dir="some-directory" multi="false" controls="false" absolute="false" exclude="CVS; directory1; directory2" dirname="%basename" dirtitle="Click to toggle this folder." filename="%basename" filetitle="Click to download this %extension file."]</blockquote>';
$output .= '<p>' . t('Available tokens for use within the "dirname", "dirtitle", "filename", and "filetitle" options include:') . '</p>';
$output .= theme('item_list', array(
'items' => array(
'%filename: ' . t("The file's name and extension."),
'%basename: ' . t("The file's name, without extension."),
'%extension: ' . t("The file's extension."),
),
));
$output .= '<p>' . t('You can also read a <a href="http://drupal.org/project/filetree">detailed explanation of these options</a>.') . '</p>';
}
return $output;
}
function _filetree_process($text, $filter, $format, $langcode, $cache, $cache_id) {
if (!preg_match_all('/(?:<p>)?\\[filetree\\s*(.*?)\\](?:<\\/p>)?/s', $text, $matches)) {
return $text;
}
$default_params = array(
'dir' => NULL,
'multi' => TRUE,
'controls' => TRUE,
'absolute' => TRUE,
'exclude' => array(
'CVS',
),
'dirname' => '%filename',
'dirtitle' => '%filename',
'filename' => '%filename',
'filetitle' => '%filename',
);
foreach ($matches[1] as $key => $passed_params) {
$params[$key] = $default_params;
preg_match_all('/(\\w*)=(?:\\"|")(.*?)(?:\\"|")/', $passed_params, $matches2[$key]);
foreach ($matches2[$key][1] as $param_key => $param_name) {
if (in_array($param_name, array_keys($default_params))) {
if (is_bool($default_params[$param_name])) {
$params[$key][$param_name] = $matches2[$key][2][$param_key] == "false" ? FALSE : (bool) $matches2[$key][2][$param_key];
}
else {
if ($param_name == 'exclude') {
$params[$key][$param_name] = array_filter(array_map('trim', explode(';', $matches2[$key][2][$param_key])));
}
else {
$params[$key][$param_name] = $matches2[$key][2][$param_key];
}
}
}
}
if (!$params[$key]['dir'] or !drupal_match_path($params[$key]['dir'], $filter->settings['folders']) or !($params[$key]['uri'] = file_build_uri($params[$key]['dir'])) or !file_prepare_directory($params[$key]['uri'])) {
continue;
}
$params[$key]['exclude'] = implode("\n", $params[$key]['exclude']);
foreach (array(
'dirname',
'dirtitle',
'filename',
'filetitle',
) as $token_param) {
$params[$key][$token_param] = preg_replace('/%(\\w+)/', '[filetree:$1]', $params[$key][$token_param]);
}
$files = _filetree_list_files($params[$key]['uri'], $params[$key]);
$rendered = theme('filetree', array(
'files' => $files,
'params' => $params[$key],
));
$text = str_replace($matches[0][$key], $rendered, $text);
}
return $text;
}
function _filetree_list_files($dir, $params) {
$list = array();
if (is_dir($dir) && ($handle = opendir($dir))) {
$folders = $files = array();
$descriptions = _filetree_parse_description($dir);
while (FALSE !== ($file = readdir($handle))) {
if ($file[0] != '.' and !drupal_match_path($file, $params['exclude'])) {
$filename = "{$dir}/{$file}";
if (is_dir($filename)) {
$folders[$file] = array(
'data' => isset($descriptions[$file]) ? $descriptions[$file] : token_replace($params['dirname'], array(
'file' => $file,
)),
'children' => _filetree_list_files($filename, $params),
'title' => token_replace($params['dirtitle'], array(
'file' => $file,
)),
'class' => array(
'folder',
),
);
}
else {
$name = isset($descriptions[$file]) ? $descriptions[$file] : token_replace($params['filename'], array(
'file' => $file,
));
$url = $params['absolute'] ? file_create_url($filename) : substr(file_create_url($filename), strlen($GLOBALS['base_url'] . '/'));
$files[$file] = array(
'data' => l($name, $url),
'title' => token_replace($params['filetitle'], array(
'file' => $file,
)),
'class' => array(
_filetree_icon(pathinfo($file, PATHINFO_EXTENSION)),
),
);
}
}
}
closedir($handle);
asort($folders);
asort($files);
$list += $folders;
$list += $files;
}
return $list;
}
function _filetree_parse_description($dir) {
$descriptions = array();
if (is_readable("{$dir}/.descript.ion") && ($file = file("{$dir}/.descript.ion"))) {
foreach ($file as $line) {
$line = trim($line);
if ($line == '' || strpos($line, '#') === 0) {
continue;
}
$matches = array();
if (strpos($line, '"') === 0) {
preg_match('/^"([^"]+)"\\s+(.*)$/', $line, $matches);
}
else {
preg_match('/^(\\S+)\\s+(.*)$/', $line, $matches);
}
list(, $name, $description) = $matches;
if (isset($descriptions[$name])) {
$descriptions[$name] .= ' ' . trim($description);
}
else {
$descriptions[$name] = trim($description);
}
}
}
return $descriptions;
}
function _filetree_icon($extension) {
$extension = strtolower($extension);
$icon = 'file';
$map = array(
'application' => array(
'exe',
),
'css' => array(
'css',
),
'db' => array(
'sql',
),
'doc' => array(
'doc',
'docx',
),
'film' => array(
'avi',
'mov',
),
'flash' => array(
'flv',
'swf',
),
'html' => array(
'htm',
'html',
),
'music' => array(
'mp3',
'aac',
),
'pdf' => array(
'pdf',
),
'php' => array(
'php',
),
'image' => array(
'jpg',
'jpeg',
'gif',
'png',
'bmp',
),
'ppt' => array(
'ppt',
),
'psd' => array(
'psd',
),
'script' => array(
'asp',
),
'txt' => array(
'txt',
),
'xls' => array(
'xls',
'xlsx',
),
'zip' => array(
'zip',
),
);
foreach ($map as $key => $values) {
foreach ($values as $value) {
if ($extension == $value) {
$icon = $key;
}
}
}
return $icon;
}
function theme_filetree($variables) {
$files = $variables['files'];
$params = $variables['params'];
$output = '';
if ($params['multi'] and $params['controls']) {
$has_folder = FALSE;
foreach ($files as $file) {
if (isset($file['children'])) {
$has_folder = TRUE;
break;
}
}
if ($has_folder) {
$controls = array(
'<a href="#" class="expand">' . t('expand all') . '</a>',
'<a href="#" class="collapse">' . t('collapse all') . '</a>',
);
$output .= theme('item_list', array(
'items' => $controls,
'title' => NULL,
'type' => 'ul',
'attributes' => array(
'class' => 'controls',
),
));
}
}
$output .= theme('item_list', array(
'items' => $files,
'title' => NULL,
'type' => 'ul',
'attributes' => array(
'class' => 'files',
),
));
$id = drupal_clean_css_identifier(uniqid('filetree-'));
$classes = array(
'filetree',
);
if ($params['multi']) {
$classes[] = 'multi';
}
return '<div id="' . $id . '" class="' . implode(' ', $classes) . '">' . $output . '</div>';
}