You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
596 lines
22 KiB
596 lines
22 KiB
<?php
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// //
|
|
// This file is part of Moodle - http://moodle.org/ //
|
|
// Moodle - Modular Object-Oriented Dynamic Learning Environment //
|
|
// //
|
|
// Moodle is free software: you can redistribute it and/or modify //
|
|
// it under the terms of the GNU General Public License as published by //
|
|
// the Free Software Foundation, either version 3 of the License, or //
|
|
// (at your option) any later version. //
|
|
// //
|
|
// Moodle is distributed in the hope that it will be useful, //
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of //
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
|
|
// GNU General Public License for more details. //
|
|
// //
|
|
// You should have received a copy of the GNU General Public License //
|
|
// along with Moodle. If not, see <http://www.gnu.org/licenses/>. //
|
|
// //
|
|
///////////////////////////////////////////////////////////////////////////
|
|
|
|
defined('MOODLE_INTERNAL') || die();
|
|
|
|
/**
|
|
* Rendering of files viewer related widgets.
|
|
* @package core
|
|
* @subpackage file
|
|
* @copyright 2010 Dongsheng Cai
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
* @since Moodle 2.0
|
|
*/
|
|
|
|
/**
|
|
* File browser render
|
|
*
|
|
* @copyright 2010 Dongsheng Cai
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
* @since Moodle 2.0
|
|
*/
|
|
class core_files_renderer extends plugin_renderer_base {
|
|
|
|
public function files_tree_viewer(file_info $file_info, array $options = null) {
|
|
$tree = new files_tree_viewer($file_info, $options);
|
|
return $this->render($tree);
|
|
}
|
|
|
|
public function render_files_tree_viewer(files_tree_viewer $tree) {
|
|
$html = $this->output->heading_with_help(get_string('coursefiles'), 'courselegacyfiles', 'moodle');
|
|
|
|
$html .= $this->output->container_start('coursefilesbreadcrumb');
|
|
foreach($tree->path as $path) {
|
|
$html .= $path;
|
|
$html .= ' / ';
|
|
}
|
|
$html .= $this->output->container_end();
|
|
|
|
$html .= $this->output->box_start();
|
|
$table = new html_table();
|
|
$table->head = array(get_string('name'), get_string('lastmodified'), get_string('size', 'repository'), get_string('type', 'repository'));
|
|
$table->align = array('left', 'left', 'left', 'left');
|
|
$table->width = '100%';
|
|
$table->data = array();
|
|
|
|
foreach ($tree->tree as $file) {
|
|
$filedate = $filesize = $filetype = '';
|
|
if ($file['filedate']) {
|
|
$filedate = userdate($file['filedate'], get_string('strftimedatetimeshort', 'langconfig'));
|
|
}
|
|
if (empty($file['isdir'])) {
|
|
if ($file['filesize']) {
|
|
$filesize = display_size($file['filesize']);
|
|
}
|
|
$fileicon = file_file_icon($file, 24);
|
|
$filetype = get_mimetype_description($file);
|
|
} else {
|
|
$fileicon = file_folder_icon(24);
|
|
}
|
|
$table->data[] = array(
|
|
html_writer::link($file['url'], $this->output->pix_icon($fileicon, get_string('icon')) . ' ' . $file['filename']),
|
|
$filedate,
|
|
$filesize,
|
|
$filetype
|
|
);
|
|
}
|
|
|
|
$html .= html_writer::table($table);
|
|
$html .= $this->output->single_button(new moodle_url('/files/coursefilesedit.php', array('contextid'=>$tree->context->id)), get_string('coursefilesedit'), 'get');
|
|
$html .= $this->output->box_end();
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Prints the file manager and initializes all necessary libraries
|
|
*
|
|
* <pre>
|
|
* $fm = new form_filemanager($options);
|
|
* $output = get_renderer('core', 'files');
|
|
* echo $output->render($fm);
|
|
* </pre>
|
|
*
|
|
* @param form_filemanager $fm File manager to render
|
|
* @return string HTML fragment
|
|
*/
|
|
public function render_form_filemanager($fm) {
|
|
$html = $this->fm_print_generallayout($fm);
|
|
$module = array(
|
|
'name'=>'form_filemanager',
|
|
'fullpath'=>'/lib/form/filemanager.js',
|
|
'requires' => array('moodle-core-notification-dialogue', 'core_filepicker', 'base', 'io-base', 'node', 'json', 'core_dndupload', 'panel', 'resize-plugin', 'dd-plugin'),
|
|
'strings' => array(
|
|
array('error', 'moodle'), array('info', 'moodle'), array('confirmdeletefile', 'repository'),
|
|
array('draftareanofiles', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
|
|
array('invalidjson', 'repository'), array('popupblockeddownload', 'repository'),
|
|
array('unknownoriginal', 'repository'), array('confirmdeletefolder', 'repository'),
|
|
array('confirmdeletefilewithhref', 'repository'), array('confirmrenamefolder', 'repository'),
|
|
array('confirmrenamefile', 'repository'), array('newfolder', 'repository'), array('edit', 'moodle')
|
|
)
|
|
);
|
|
if ($this->page->requires->should_create_one_time_item_now('core_file_managertemplate')) {
|
|
$this->page->requires->js_init_call('M.form_filemanager.set_templates',
|
|
array($this->filemanager_js_templates()), true, $module);
|
|
}
|
|
$this->page->requires->js_init_call('M.form_filemanager.init', array($fm->options), true, $module);
|
|
|
|
// non javascript file manager
|
|
$html .= '<noscript>';
|
|
$html .= "<div><object type='text/html' data='".$fm->get_nonjsurl()."' height='160' width='600' style='border:1px solid #000'></object></div>";
|
|
$html .= '</noscript>';
|
|
|
|
|
|
return $html;
|
|
}
|
|
|
|
/**
|
|
* Returns html for displaying one file manager
|
|
*
|
|
* @param form_filemanager $fm
|
|
* @return string
|
|
*/
|
|
protected function fm_print_generallayout($fm) {
|
|
$context = [
|
|
'client_id' => $fm->options->client_id,
|
|
'helpicon' => $this->help_icon('setmainfile', 'repository'),
|
|
'restrictions' => $this->fm_print_restrictions($fm)
|
|
];
|
|
return $this->render_from_template('core/filemanager_page_generallayout', $context);
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for displaying one file in 'icon view' mode.
|
|
*
|
|
* Except for elements described in fp_js_template_iconfilename, this template may also
|
|
* contain element with class 'fp-contextmenu'. If context menu is available for this
|
|
* file, the top element will receive the additional class 'fp-hascontextmenu' and
|
|
* the element with class 'fp-contextmenu' will hold onclick event for displaying
|
|
* the context menu.
|
|
*
|
|
* @see fp_js_template_iconfilename()
|
|
* @return string
|
|
*/
|
|
protected function fm_js_template_iconfilename() {
|
|
$rv = '
|
|
<div class="fp-file">
|
|
<a href="#">
|
|
<div style="position:relative;">
|
|
<div class="fp-thumbnail"></div>
|
|
<div class="fp-reficons1"></div>
|
|
<div class="fp-reficons2"></div>
|
|
</div>
|
|
<div class="fp-filename-field">
|
|
<div class="fp-filename text-truncate"></div>
|
|
</div>
|
|
</a>
|
|
<a class="fp-contextmenu" href="#">'.$this->pix_icon('i/menu', '▶').'</a>
|
|
</div>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for displaying file name in 'table view' and 'tree view' modes.
|
|
*
|
|
* Except for elements described in fp_js_template_listfilename, this template may also
|
|
* contain element with class 'fp-contextmenu'. If context menu is available for this
|
|
* file, the top element will receive the additional class 'fp-hascontextmenu' and
|
|
* the element with class 'fp-contextmenu' will hold onclick event for displaying
|
|
* the context menu.
|
|
*
|
|
* @todo MDL-32736 remove onclick="return false;"
|
|
* @see fp_js_template_listfilename()
|
|
* @return string
|
|
*/
|
|
protected function fm_js_template_listfilename() {
|
|
$rv = '
|
|
<span class="fp-filename-icon">
|
|
<a href="#">
|
|
<span class="fp-icon"></span>
|
|
<span class="fp-reficons1"></span>
|
|
<span class="fp-reficons2"></span>
|
|
<span class="fp-filename"></span>
|
|
</a>
|
|
<a class="fp-contextmenu" href="#" onclick="return false;">'.$this->pix_icon('i/menu', '▶').'</a>
|
|
</span>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for displaying 'Make new folder' dialog.
|
|
*
|
|
* Must be wrapped in an element, CSS for this element must define width and height of the window;
|
|
*
|
|
* Must have one input element with type="text" (for users to enter the new folder name);
|
|
*
|
|
* content of element with class 'fp-dlg-curpath' will be replaced with current path where
|
|
* new folder is about to be created;
|
|
* elements with classes 'fp-dlg-butcreate' and 'fp-dlg-butcancel' will hold onclick events;
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fm_js_template_mkdir() {
|
|
$rv = '
|
|
<div class="filemanager fp-mkdir-dlg" role="dialog" aria-live="assertive" aria-labelledby="fp-mkdir-dlg-title">
|
|
<div class="fp-mkdir-dlg-text">
|
|
<label id="fp-mkdir-dlg-title">' . get_string('newfoldername', 'repository') . '</label><br/>
|
|
<input type="text" />
|
|
</div>
|
|
<button class="fp-dlg-butcreate btn-primary btn">'.get_string('makeafolder').'</button>
|
|
<button class="fp-dlg-butcancel btn-cancel btn">'.get_string('cancel').'</button>
|
|
</div>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for error/info message displayed as a separate popup window.
|
|
*
|
|
* @see fp_js_template_message()
|
|
* @return string
|
|
*/
|
|
protected function fm_js_template_message() {
|
|
return $this->fp_js_template_message();
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for window with file information/actions.
|
|
*
|
|
*/
|
|
protected function fm_js_template_fileselectlayout() {
|
|
$context = [
|
|
'helpicon' => $this->help_icon('setmainfile', 'repository')
|
|
];
|
|
return $this->render_from_template('core/filemanager_fileselect', $context);
|
|
}
|
|
|
|
/**
|
|
* FileManager JS template for popup confirm dialogue window.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fm_js_template_confirmdialog() {
|
|
return $this->render_from_template('core/filemanager_confirmdialog', []);
|
|
}
|
|
|
|
/**
|
|
* Returns all FileManager JavaScript templates as an array.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function filemanager_js_templates() {
|
|
$class_methods = get_class_methods($this);
|
|
$templates = array();
|
|
foreach ($class_methods as $method_name) {
|
|
if (preg_match('/^fm_js_template_(.*)$/', $method_name, $matches))
|
|
$templates[$matches[1]] = $this->$method_name();
|
|
}
|
|
return $templates;
|
|
}
|
|
|
|
/**
|
|
* Displays restrictions for the file manager
|
|
*
|
|
* @param form_filemanager $fm
|
|
* @return string
|
|
*/
|
|
protected function fm_print_restrictions($fm) {
|
|
$maxbytes = display_size($fm->options->maxbytes);
|
|
$strparam = (object) array('size' => $maxbytes, 'attachments' => $fm->options->maxfiles,
|
|
'areasize' => display_size($fm->options->areamaxbytes));
|
|
$hasmaxfiles = !empty($fm->options->maxfiles) && $fm->options->maxfiles > 0;
|
|
$hasarealimit = !empty($fm->options->areamaxbytes) && $fm->options->areamaxbytes != -1;
|
|
if ($hasmaxfiles && $hasarealimit) {
|
|
$maxsize = get_string('maxsizeandattachmentsandareasize', 'moodle', $strparam);
|
|
} else if ($hasmaxfiles) {
|
|
$maxsize = get_string('maxsizeandattachments', 'moodle', $strparam);
|
|
} else if ($hasarealimit) {
|
|
$maxsize = get_string('maxsizeandareasize', 'moodle', $strparam);
|
|
} else {
|
|
$maxsize = get_string('maxfilesize', 'moodle', $maxbytes);
|
|
}
|
|
// TODO MDL-32020 also should say about 'File types accepted'
|
|
return '<span>'. $maxsize . '</span>';
|
|
}
|
|
|
|
/**
|
|
* Template for FilePicker with general layout (not QuickUpload).
|
|
*
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_generallayout() {
|
|
return $this->render_from_template('core/filemanager_modal_generallayout', []);
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for displaying one file in 'icon view' mode.
|
|
*
|
|
* the element with class 'fp-thumbnail' will be resized to the repository thumbnail size
|
|
* (both width and height, unless min-width and/or min-height is set in CSS) and the content of
|
|
* an element will be replaced with an appropriate img;
|
|
*
|
|
* the width of element with class 'fp-filename' will be set to the repository thumbnail width
|
|
* (unless min-width is set in css) and the content of an element will be replaced with filename
|
|
* supplied by repository;
|
|
*
|
|
* top element(s) will have class fp-folder if the element is a folder;
|
|
*
|
|
* List of files will have parent <div> element with class 'fp-iconview'
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_iconfilename() {
|
|
$rv = '
|
|
<a class="fp-file" href="#" >
|
|
<div style="position:relative;">
|
|
<div class="fp-thumbnail"></div>
|
|
<div class="fp-reficons1"></div>
|
|
<div class="fp-reficons2"></div>
|
|
</div>
|
|
<div class="fp-filename-field">
|
|
<p class="fp-filename text-truncate"></p>
|
|
</div>
|
|
</a>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for displaying file name in 'table view' and 'tree view' modes.
|
|
*
|
|
* content of the element with class 'fp-icon' will be replaced with an appropriate img;
|
|
*
|
|
* content of element with class 'fp-filename' will be replaced with filename supplied by
|
|
* repository;
|
|
*
|
|
* top element(s) will have class fp-folder if the element is a folder;
|
|
*
|
|
* Note that tree view and table view are the YUI widgets and therefore there are no
|
|
* other templates. The widgets will be wrapped in <div> with class fp-treeview or
|
|
* fp-tableview (respectfully).
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_listfilename() {
|
|
$rv = '
|
|
<span class="fp-filename-icon">
|
|
<a href="#">
|
|
<span class="fp-icon"></span>
|
|
<span class="fp-filename"></span>
|
|
</a>
|
|
</span>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for displaying link/loading progress for fetching of the next page
|
|
*
|
|
* This text is added to .fp-content AFTER .fp-iconview/.fp-treeview/.fp-tableview
|
|
*
|
|
* Must have one parent element with class 'fp-nextpage'. It will be assigned additional
|
|
* class 'loading' during loading of the next page (it is recommended that in this case the link
|
|
* becomes unavailable). Also must contain one element <a> or <button> that will hold
|
|
* onclick event for displaying of the next page. The event will be triggered automatically
|
|
* when user scrolls to this link.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_nextpage() {
|
|
$rv = '
|
|
<div class="fp-nextpage">
|
|
<div class="fp-nextpage-link"><a href="#">'.get_string('more').'</a></div>
|
|
<div class="fp-nextpage-loading">
|
|
' . $this->pix_icon('i/loading_small', '') . '
|
|
</div>
|
|
</div>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for window appearing to select a file.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_selectlayout() {
|
|
return $this->render_from_template('core/filemanager_selectlayout', []);
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for 'Upload file' repository
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_uploadform() {
|
|
return $this->render_from_template('core/filemanager_uploadform', []);
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template to display during loading process (inside element with class 'fp-content').
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_loading() {
|
|
return '
|
|
<div class="fp-content-loading">
|
|
<div class="fp-content-center">
|
|
' . $this->pix_icon('i/loading_small', '') . '
|
|
</div>
|
|
</div>';
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for error (inside element with class 'fp-content').
|
|
*
|
|
* must have element with class 'fp-error', its content will be replaced with error text
|
|
* and the error code will be assigned as additional class to this element
|
|
* used errors: invalidjson, nofilesavailable, norepositoriesavailable
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_error() {
|
|
$rv = '
|
|
<div class="fp-content-error" ><div class="fp-error"></div></div>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for error/info message displayed as a separate popup window.
|
|
*
|
|
* Must be wrapped in one element, CSS for this element must define
|
|
* width and height of the window. It will be assigned with an additional class 'fp-msg-error'
|
|
* or 'fp-msg-info' depending on message type;
|
|
*
|
|
* content of element with class 'fp-msg-text' will be replaced with error/info text;
|
|
*
|
|
* element with class 'fp-msg-butok' will hold onclick event
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_message() {
|
|
$rv = '
|
|
<div class="file-picker fp-msg" role="alertdialog" aria-live="assertive" aria-labelledby="fp-msg-labelledby">
|
|
<p class="fp-msg-text" id="fp-msg-labelledby"></p>
|
|
<button class="fp-msg-butok btn-primary btn">'.get_string('ok').'</button>
|
|
</div>';
|
|
return $rv;
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for popup dialogue window asking for action when file with the same name already exists.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_processexistingfile() {
|
|
return $this->render_from_template('core/filemanager_processexistingfile', []);
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for popup dialogue window asking for action when file with the same name already exists
|
|
* (multiple-file version).
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_processexistingfilemultiple() {
|
|
return $this->render_from_template('core/filemanager_processexistingfilemultiple', []);
|
|
}
|
|
|
|
/**
|
|
* FilePicker JS template for repository login form including templates for each element type
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function fp_js_template_loginform() {
|
|
return $this->render_from_template('core/filemanager_loginform', []);
|
|
}
|
|
|
|
/**
|
|
* Returns all FilePicker JavaScript templates as an array.
|
|
*
|
|
* @return array
|
|
*/
|
|
public function filepicker_js_templates() {
|
|
$class_methods = get_class_methods($this);
|
|
$templates = array();
|
|
foreach ($class_methods as $method_name) {
|
|
if (preg_match('/^fp_js_template_(.*)$/', $method_name, $matches))
|
|
$templates[$matches[1]] = $this->$method_name();
|
|
}
|
|
return $templates;
|
|
}
|
|
|
|
/**
|
|
* Returns HTML for default repository searchform to be passed to Filepicker
|
|
*
|
|
* This will be used as contents for search form defined in generallayout template
|
|
* (form with id {TOOLSEARCHID}).
|
|
* Default contents is one text input field with name="s"
|
|
*/
|
|
public function repository_default_searchform() {
|
|
return $this->render_from_template('core/filemanager_default_searchform', []);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Data structure representing a general moodle file tree viewer
|
|
*
|
|
* @copyright 2010 Dongsheng Cai
|
|
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
|
* @since Moodle 2.0
|
|
*/
|
|
class files_tree_viewer implements renderable {
|
|
public $tree;
|
|
public $path;
|
|
public $context;
|
|
|
|
/**
|
|
* Constructor of moodle_file_tree_viewer class
|
|
* @param file_info $file_info
|
|
* @param array $options
|
|
*/
|
|
public function __construct(file_info $file_info, array $options = null) {
|
|
global $CFG;
|
|
|
|
//note: this MUST NOT use get_file_storage() !!!!!!!!!!!!!!!!!!!!!!!!!!!!
|
|
$this->options = (array)$options;
|
|
$this->context = $options['context'];
|
|
|
|
$this->tree = array();
|
|
$children = $file_info->get_children();
|
|
$current_file_params = $file_info->get_params();
|
|
$parent_info = $file_info->get_parent();
|
|
$level = $parent_info;
|
|
$this->path = array();
|
|
while ($level) {
|
|
$params = $level->get_params();
|
|
$context = context::instance_by_id($params['contextid']);
|
|
// $this->context is current context
|
|
if ($context->id != $this->context->id or empty($params['filearea'])) {
|
|
break;
|
|
}
|
|
// unset unused parameters
|
|
unset($params['component']);
|
|
unset($params['filearea']);
|
|
unset($params['filename']);
|
|
unset($params['itemid']);
|
|
$url = new moodle_url('/files/index.php', $params);
|
|
$this->path[] = html_writer::link($url, $level->get_visible_name());
|
|
$level = $level->get_parent();
|
|
}
|
|
$this->path = array_reverse($this->path);
|
|
if ($current_file_params['filepath'] != '/') {
|
|
$this->path[] = $file_info->get_visible_name();
|
|
}
|
|
|
|
foreach ($children as $child) {
|
|
$filedate = $child->get_timemodified();
|
|
$filesize = $child->get_filesize();
|
|
$mimetype = $child->get_mimetype();
|
|
$params = $child->get_params();
|
|
unset($params['component']);
|
|
unset($params['filearea']);
|
|
unset($params['filename']);
|
|
unset($params['itemid']);
|
|
$fileitem = array(
|
|
'params' => $params,
|
|
'filename' => $child->get_visible_name(),
|
|
'mimetype' => $child->get_mimetype(),
|
|
'filedate' => $filedate ? $filedate : '',
|
|
'filesize' => $filesize ? $filesize : ''
|
|
);
|
|
$url = new moodle_url('/files/index.php', $params);
|
|
if ($child->is_directory()) {
|
|
$fileitem['isdir'] = true;
|
|
$fileitem['url'] = $url->out(false);
|
|
} else {
|
|
$fileitem['url'] = $child->get_url();
|
|
}
|
|
$this->tree[] = $fileitem;
|
|
}
|
|
}
|
|
}
|
|
|