diff --git a/admin/repository.php b/admin/repository.php index c3409a5b5a0..a3af2ddc588 100644 --- a/admin/repository.php +++ b/admin/repository.php @@ -1,12 +1,27 @@ . require_once(dirname(dirname(__FILE__)) . '/config.php'); require_once($CFG->dirroot . '/repository/lib.php'); require_once($CFG->libdir . '/adminlib.php'); -$repository = optional_param('repos', '', PARAM_FORMAT); -$action = optional_param('action', '', PARAM_ALPHA); -$sure = optional_param('sure', '', PARAM_ALPHA); +$repository = optional_param('repos', '', PARAM_ALPHANUMEXT); +$action = optional_param('action', '', PARAM_ACTION); +$sure = optional_param('sure', '', PARAM_ALPHA); +$downloadcontents = optional_param('downloadcontents', '', PARAM_ALPHA); $display = true; // fall through to normal display @@ -42,6 +57,10 @@ $configstr = get_string('manage', 'repository'); $return = true; +if (!empty($action)) { + require_sesskey(); +} + /** * Helper function that generates a moodle_url object * relevant to the repository @@ -152,10 +171,10 @@ if (($action == 'edit') || ($action == 'new')) { // Display instances list and creation form if ($action == 'edit') { - $instanceoptionnames = repository::static_function($repository, 'get_instance_option_names'); - if (!empty($instanceoptionnames)) { - repository::display_instances_list(get_context_instance(CONTEXT_SYSTEM), $repository); - } + $instanceoptionnames = repository::static_function($repository, 'get_instance_option_names'); + if (!empty($instanceoptionnames)) { + repository::display_instances_list(context_system::instance(), $repository); + } } } } else if ($action == 'show') { @@ -185,7 +204,14 @@ if (($action == 'edit') || ($action == 'new')) { if (!confirm_sesskey()) { print_error('confirmsesskeybad', '', $baseurl); } - if ($repositorytype->delete()) { + + if (!empty($downloadcontents) and $downloadcontents == 'yes') { + $downloadcontents = true; + } else { + $downloadcontents = false; + } + + if ($repositorytype->delete($downloadcontents)) { redirect($baseurl); } else { print_error('instancenotdeleted', 'repository', $baseurl); @@ -193,7 +219,34 @@ if (($action == 'edit') || ($action == 'new')) { exit; } else { echo $OUTPUT->header(); - echo $OUTPUT->confirm(get_string('confirmremove', 'repository', $repositorytype->get_readablename()), $sesskeyurl . '&action=delete&repos=' . $repository . '&sure=yes', $baseurl); + + $message = get_string('confirmremove', 'repository', $repositorytype->get_readablename()); + + $output = $OUTPUT->box_start('generalbox', 'notice'); + $output .= html_writer::tag('p', $message); + + $removeurl = new moodle_url($sesskeyurl); + $removeurl->params(array( + 'action' =>'delete', + 'repos' => $repository, + 'sure' => 'yes', + )); + + $removeanddownloadurl = new moodle_url($sesskeyurl); + $removeanddownloadurl->params(array( + 'action' =>'delete', + 'repos'=> $repository, + 'sure' => 'yes', + 'downloadcontents' => 'yes', + )); + + $output .= $OUTPUT->single_button($removeurl, get_string('continueuninstall', 'repository')); + $output .= $OUTPUT->single_button($removeanddownloadurl, get_string('continueuninstallanddownload', 'repository')); + $output .= $OUTPUT->single_button($baseurl, get_string('cancel')); + $output .= $OUTPUT->box_end(); + + echo $output; + $return = false; } } else if ($action == 'moveup') { @@ -255,7 +308,7 @@ if (($action == 'edit') || ($action == 'new')) { // Calculate number of instances in order to display them for the Moodle administrator if (!empty($instanceoptionnames)) { $params = array(); - $params['context'] = array(get_system_context()); + $params['context'] = array(context_system::instance()); $params['onlyvisible'] = false; $params['type'] = $typename; $admininstancenumber = count(repository::static_function($typename, 'get_instances', $params)); diff --git a/admin/repositoryinstance.php b/admin/repositoryinstance.php index e75193d0be4..f2b6e7f8e4f 100644 --- a/admin/repositoryinstance.php +++ b/admin/repositoryinstance.php @@ -1,18 +1,35 @@ . require_once(dirname(dirname(__FILE__)) . '/config.php'); require_once($CFG->dirroot . '/repository/lib.php'); require_once($CFG->libdir . '/adminlib.php'); +require_sesskey(); + // id of repository $edit = optional_param('edit', 0, PARAM_INT); -$new = optional_param('new', '', PARAM_FORMAT); +$new = optional_param('new', '', PARAM_PLUGIN); $hide = optional_param('hide', 0, PARAM_INT); $delete = optional_param('delete', 0, PARAM_INT); $sure = optional_param('sure', '', PARAM_ALPHA); $type = optional_param('type', '', PARAM_PLUGIN); +$downloadcontents = optional_param('downloadcontents', '', PARAM_ALPHA); -$context = get_context_instance(CONTEXT_SYSTEM); +$context = context_system::instance(); $pagename = 'repositorycontroller'; @@ -24,16 +41,20 @@ if ($edit){ $pagename = 'repositoryinstancenew'; } -admin_externalpage_setup($pagename); -require_capability('moodle/site:config', get_context_instance(CONTEXT_SYSTEM)); +admin_externalpage_setup($pagename, '', null, new moodle_url('/admin/repositoryinstances.php')); +require_capability('moodle/site:config', $context); + +$baseurl = new moodle_url("/$CFG->admin/repositoryinstance.php", array('sesskey'=>sesskey())); + +$parenturl = new moodle_url("/$CFG->admin/repository.php", array( + 'sesskey'=>sesskey(), + 'action'=>'edit', +)); -$sesskeyurl = "$CFG->wwwroot/$CFG->admin/repositoryinstance.php?sesskey=" . sesskey(); -$baseurl = "$CFG->wwwroot/$CFG->admin/repository.php?session=". sesskey() .'&action=edit&repos='; if ($new) { - $baseurl .= $new; -} -else { - $baseurl .= $type; + $parenturl->param('repos', $new); +} else { + $parenturl->param('repos', $type); } $return = true; @@ -48,7 +69,7 @@ if (!empty($edit) || !empty($new)) { $typeid = $instance->options['typeid']; } else { $plugin = $new; - $typeid = $new; + $typeid = null; $instance = null; } @@ -57,12 +78,9 @@ if (!empty($edit) || !empty($new)) { // end setup, begin output if ($mform->is_cancelled()){ - redirect($baseurl); + redirect($parenturl); exit; } else if ($fromform = $mform->get_data()){ - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', '', $baseurl); - } if ($edit) { $settings = array(); $settings['name'] = $fromform->name; @@ -77,13 +95,13 @@ if (!empty($edit) || !empty($new)) { } $success = $instance->set_option($settings); } else { - $success = repository::static_function($plugin, 'create', $plugin, 0, get_system_context(), $fromform); + $success = repository::static_function($plugin, 'create', $plugin, 0, $context, $fromform); $data = data_submitted(); } if ($success) { - redirect($baseurl); + redirect($parenturl); } else { - print_error('instancenotsaved', 'repository', $baseurl); + print_error('instancenotsaved', 'repository', $parenturl); } exit; } else { @@ -95,9 +113,6 @@ if (!empty($edit) || !empty($new)) { $return = false; } } else if (!empty($hide)) { - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', '', $baseurl); - } $instance = repository::get_type_by_typename($hide); $instance->hide(); $return = true; @@ -108,25 +123,43 @@ if (!empty($edit) || !empty($new)) { throw new repository_exception('readonlyinstance', 'repository'); } if ($sure) { - if (!confirm_sesskey()) { - print_error('confirmsesskeybad', '', $baseurl); - } - if ($instance->delete()) { - $deletedstr = get_string('instancedeleted', 'repository'); - redirect($baseurl, $deletedstr, 3); + if (!empty($downloadcontents) and $downloadcontents == 'yes') { + $downloadcontents = true; } else { - print_error('instancenotdeleted', 'repository', $baseurl); + $downloadcontents = false; + } + if ($instance->delete($downloadcontents)) { + $deletedstr = get_string('instancedeleted', 'repository'); + redirect($parenturl, $deletedstr, 3); + } else { + print_error('instancenotdeleted', 'repository', $parenturl); } exit; } echo $OUTPUT->header(); - echo $OUTPUT->confirm(get_string('confirmdelete', 'repository', $instance->name), "$sesskeyurl&type=$type'&delete=$delete'&sure=yes", "$CFG->wwwroot/$CFG->admin/repositoryinstance.php?session=". sesskey()); + echo $OUTPUT->box_start('generalbox', 'notice'); + $continueurl = new moodle_url($baseurl, array( + 'type' => $type, + 'delete' => $delete, + 'sure' => 'yes', + )); + $continueanddownloadurl = new moodle_url($continueurl, array( + 'downloadcontents' => 'yes' + )); + $message = get_string('confirmdelete', 'repository', $instance->name); + echo html_writer::tag('p', $message); + + echo $OUTPUT->single_button($continueurl, get_string('continueuninstall', 'repository')); + echo $OUTPUT->single_button($continueanddownloadurl, get_string('continueuninstallanddownload', 'repository')); + echo $OUTPUT->single_button($parenturl, get_string('cancel')); + + echo $OUTPUT->box_end(); + $return = false; } if (!empty($return)) { - - redirect($baseurl); + redirect($parenturl); } echo $OUTPUT->footer(); diff --git a/admin/tool/unittest/coveragefile.php b/admin/tool/unittest/coveragefile.php index 8c17b60e3eb..d3c8737a4e8 100644 --- a/admin/tool/unittest/coveragefile.php +++ b/admin/tool/unittest/coveragefile.php @@ -60,9 +60,8 @@ if (!isset($args[0]) || !in_array($args[0], $alloweddirs)) { print_error('invalidarguments'); } -// only serve some controlled extensions -$allowedextensions = array('text/html', 'text/css', 'image/gif', 'application/x-javascript'); -if (!in_array(mimeinfo('type', $filepath), $allowedextensions)) { +// only serve some controlled extensions/mimetypes +if (!file_extension_in_typegroup($filepath, array('web_file', 'web_image'), true)) { print_error('invalidarguments'); } diff --git a/backup/backupfilesedit_form.php b/backup/backupfilesedit_form.php index 7906a080d1a..36a4030da07 100644 --- a/backup/backupfilesedit_form.php +++ b/backup/backupfilesedit_form.php @@ -27,7 +27,7 @@ class backup_files_edit_form extends moodleform { function definition() { $mform =& $this->_form; $contextid = $this->_customdata['contextid']; - $options = array('subdirs'=>0, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL); + $options = array('subdirs'=>0, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL | FILE_REFERENCE); $mform->addElement('filemanager', 'files_filemanager', get_string('files'), null, $options); $mform->addElement('hidden', 'contextid', $this->_customdata['contextid']); $mform->addElement('hidden', 'currentcontext', $this->_customdata['currentcontext']); diff --git a/backup/moodle2/backup_stepslib.php b/backup/moodle2/backup_stepslib.php index e7b6018cdf3..d1be602bc8f 100644 --- a/backup/moodle2/backup_stepslib.php +++ b/backup/moodle2/backup_stepslib.php @@ -1404,7 +1404,7 @@ class backup_final_files_structure_step extends backup_structure_step { 'contenthash', 'contextid', 'component', 'filearea', 'itemid', 'filepath', 'filename', 'userid', 'filesize', 'mimetype', 'status', 'timecreated', 'timemodified', - 'source', 'author', 'license', 'sortorder')); + 'source', 'author', 'license', 'sortorder', 'reference', 'repositoryid')); // Build the tree @@ -1412,9 +1412,12 @@ class backup_final_files_structure_step extends backup_structure_step { // Define sources - $file->set_source_sql("SELECT f.* + $file->set_source_sql("SELECT f.*, r.repositoryid, r.reference FROM {files} f - JOIN {backup_ids_temp} bi ON f.id = bi.itemid + JOIN {files_reference} r + ON r.id = f.referencefileid + JOIN {backup_ids_temp} bi + ON f.id = bi.itemid WHERE bi.backupid = ? AND bi.itemname = 'filefinal'", array(backup::VAR_BACKUPID)); @@ -1442,6 +1445,8 @@ class backup_main_structure_step extends backup_structure_step { $info['backup_date'] = time(); $info['backup_uniqueid']= $this->get_backupid(); $info['mnet_remoteusers']=backup_controller_dbops::backup_includes_mnet_remote_users($this->get_backupid()); + $info['include_file_references_to_external_content'] = + backup_controller_dbops::backup_includes_file_references($this->get_backupid()); $info['original_wwwroot']=$CFG->wwwroot; $info['original_site_identifier_hash'] = md5(get_site_identifier()); $info['original_course_id'] = $this->get_courseid(); @@ -1461,7 +1466,7 @@ class backup_main_structure_step extends backup_structure_step { $information = new backup_nested_element('information', null, array( 'name', 'moodle_version', 'moodle_release', 'backup_version', - 'backup_release', 'backup_date', 'mnet_remoteusers', 'original_wwwroot', + 'backup_release', 'backup_date', 'mnet_remoteusers', 'include_file_references_to_external_content', 'original_wwwroot', 'original_site_identifier_hash', 'original_course_id', 'original_course_fullname', 'original_course_shortname', 'original_course_startdate', 'original_course_contextid', 'original_system_contextid')); @@ -1584,8 +1589,12 @@ class backup_store_backup_file extends backup_execution_step { // Calculate the zip fullpath (in OS temp area it's always backup.mbz) $zipfile = $basepath . '/backup.mbz'; + $has_file_references = backup_controller_dbops::backup_includes_file_references($this->get_backupid()); // Perform storage and return it (TODO: shouldn't be array but proper result object) - return array('backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile)); + return array( + 'backup_destination' => backup_helper::store_backup_file($this->get_backupid(), $zipfile), + 'include_file_references_to_external_content' => $has_file_references + ); } } diff --git a/backup/moodle2/restore_stepslib.php b/backup/moodle2/restore_stepslib.php index fda860c9cf1..4d610e5cafb 100644 --- a/backup/moodle2/restore_stepslib.php +++ b/backup/moodle2/restore_stepslib.php @@ -586,11 +586,23 @@ class restore_load_included_files extends restore_structure_step { return array($file); } - // Processing functions go here + /** + * Processing functions go here + * + * @param array $data one file record including repositoryid and reference + */ public function process_file($data) { $data = (object)$data; // handy + $isreference = !empty($data->repositoryid); + $issamesite = $this->task->is_samesite(); + + // If it's not samesite, we skip file refernces + if (!$issamesite && $isreference) { + return; + } + // load it if needed: // - it it is one of the annotated inforef files (course/section/activity/block) // - it is one "user", "group", "grouping", "grade", "question" or "qtype_xxxx" component file (that aren't sent to inforef ever) @@ -601,6 +613,7 @@ class restore_load_included_files extends restore_structure_step { $data->component == 'grouping' || $data->component == 'grade' || $data->component == 'question' || substr($data->component, 0, 5) == 'qtype'); if ($isfileref || $iscomponent) { + // Process files restore_dbops::set_backup_files_record($this->get_restoreid(), $data); } } diff --git a/backup/util/dbops/backup_controller_dbops.class.php b/backup/util/dbops/backup_controller_dbops.class.php index c77aeb6e4c4..ee98987a41d 100644 --- a/backup/util/dbops/backup_controller_dbops.class.php +++ b/backup/util/dbops/backup_controller_dbops.class.php @@ -409,6 +409,27 @@ abstract class backup_controller_dbops extends backup_dbops { return (int)(bool)$count; } + /** + * Given the backupid, detect if the backup contains references to external contents + * + * @copyright 2012 Dongsheng Cai {@link http://dongsheng.org} + * @return int + */ + public static function backup_includes_file_references($backupid) { + global $CFG, $DB; + + $sql = "SELECT count(r.repositoryid) + FROM {files} f + JOIN {files_reference} r + ON r.id = f.referencefileid + JOIN {backup_ids_temp} bi + ON f.id = bi.itemid + WHERE bi.backupid = ? + AND bi.itemname = 'filefinal'"; + $count = $DB->count_records_sql($sql, array($backupid)); + return (int)(bool)$count; + } + /** * Given the courseid, return some course related information we want to transport * diff --git a/backup/util/dbops/restore_dbops.class.php b/backup/util/dbops/restore_dbops.class.php index 25f2e533d1c..e50c6e607df 100644 --- a/backup/util/dbops/restore_dbops.class.php +++ b/backup/util/dbops/restore_dbops.class.php @@ -685,6 +685,9 @@ abstract class restore_dbops { $rs = $DB->get_recordset_sql($sql, $params); foreach ($rs as $rec) { $file = (object)unserialize(base64_decode($rec->info)); + + $isreference = !empty($file->repositoryid); + // ignore root dirs (they are created automatically) if ($file->filepath == '/' && $file->filename == '.') { continue; @@ -697,10 +700,12 @@ abstract class restore_dbops { $fs->create_directory($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->userid); continue; } + // arrived here, file found // Find file in backup pool $backuppath = $basepath . backup_file_manager::get_backup_content_file_location($file->contenthash); - if (!file_exists($backuppath)) { + + if (!file_exists($backuppath) && !$isreference) { throw new restore_dbops_exception('file_not_found_in_pool', $file); } if (!$fs->file_exists($newcontextid, $component, $filearea, $rec->newitemid, $file->filepath, $file->filename)) { @@ -717,7 +722,11 @@ abstract class restore_dbops { 'author' => $file->author, 'license' => $file->license, 'sortorder' => $file->sortorder); - $fs->create_file_from_pathname($file_record, $backuppath); + if ($isreference) { + $fs->create_file_from_reference($file_record, $file->repositoryid, $file->reference); + } else { + $fs->create_file_from_pathname($file_record, $backuppath); + } } } $rs->close(); @@ -1204,6 +1213,7 @@ abstract class restore_dbops { public static function set_backup_files_record($restoreid, $filerec) { global $DB; + // Store external files info in `info` field $filerec->info = base64_encode(serialize($filerec)); // Serialize the whole rec in info $filerec->backupid = $restoreid; $DB->insert_record('backup_files_temp', $filerec); diff --git a/backup/util/helper/backup_file_manager.class.php b/backup/util/helper/backup_file_manager.class.php index fb6477a6996..9941af7f4b6 100644 --- a/backup/util/helper/backup_file_manager.class.php +++ b/backup/util/helper/backup_file_manager.class.php @@ -73,6 +73,10 @@ class backup_file_manager { $fs = get_file_storage(); $file = $fs->get_file_instance($filerecorid); + // If the file is external file, skip copying. + if ($file->is_external_file()) { + return; + } // Calculate source and target paths (use same subdirs strategy for both) $targetfilepath = self::get_backup_storage_base_dir($backupid) . '/' . diff --git a/backup/util/helper/backup_general_helper.class.php b/backup/util/helper/backup_general_helper.class.php index 73b5d3b4014..b0eb2e237d2 100644 --- a/backup/util/helper/backup_general_helper.class.php +++ b/backup/util/helper/backup_general_helper.class.php @@ -145,6 +145,7 @@ abstract class backup_general_helper extends backup_helper { $info->original_course_startdate= $infoarr['original_course_startdate']; $info->original_course_contextid= $infoarr['original_course_contextid']; $info->original_system_contextid= $infoarr['original_system_contextid']; + $info->include_file_references_to_external_content = $infoarr['include_file_references_to_external_content']; $info->type = $infoarr['details']['detail'][0]['type']; $info->format = $infoarr['details']['detail'][0]['format']; $info->mode = $infoarr['details']['detail'][0]['mode']; diff --git a/backup/util/ui/backup_ui_stage.class.php b/backup/util/ui/backup_ui_stage.class.php index 2cc20455259..1ce9053dd52 100644 --- a/backup/util/ui/backup_ui_stage.class.php +++ b/backup/util/ui/backup_ui_stage.class.php @@ -470,6 +470,9 @@ class backup_ui_stage_complete extends backup_ui_stage_final { $output = ''; $output .= $renderer->box_start(); + if (!empty($this->results['include_file_references_to_external_content'])) { + $output .= $renderer->notification(get_string('filereferencesincluded', 'backup'), 'notifyproblem'); + } $output .= $renderer->notification(get_string('executionsuccess', 'backup'), 'notifysuccess'); $output .= $renderer->continue_button($restorerul); $output .= $renderer->box_end(); diff --git a/backup/util/ui/renderer.php b/backup/util/ui/renderer.php index 7afcdfd368a..9e0ab9dd4f9 100644 --- a/backup/util/ui/renderer.php +++ b/backup/util/ui/renderer.php @@ -92,6 +92,16 @@ class core_backup_renderer extends plugin_renderer_base { $html .= $this->backup_detail_pair(get_string('originalwwwroot', 'backup'), html_writer::tag('span', $details->original_wwwroot, array('class'=>'originalwwwroot')). html_writer::tag('span', '['.$details->original_site_identifier_hash.']', array('class'=>'sitehash sub-detail'))); + if (!empty($details->include_file_references_to_external_content)) { + $message = ''; + if (backup_general_helper::backup_is_samesite($details)) { + $message = $yestick . ' ' . get_string('filereferencessamesite', 'backup'); + } else { + $message = $notick . ' ' . get_string('filereferencesnotsamesite', 'backup'); + } + $html .= $this->backup_detail_pair(get_string('includefilereferences', 'backup'), $message); + } + $html .= html_writer::end_tag('div'); $html .= html_writer::start_tag('div', array('class'=>'backup-section settings-section')); diff --git a/blocks/activity_modules/block_activity_modules.php b/blocks/activity_modules/block_activity_modules.php index c290b2444f4..2aa257865c9 100644 --- a/blocks/activity_modules/block_activity_modules.php +++ b/blocks/activity_modules/block_activity_modules.php @@ -1,5 +1,8 @@ libdir . '/filelib.php'); + class block_activity_modules extends block_list { function init() { $this->title = get_string('pluginname', 'block_activity_modules'); @@ -50,7 +53,7 @@ class block_activity_modules extends block_list { foreach ($modfullnames as $modname => $modfullname) { if ($modname === 'resources') { - $icon = ' '; + $icon = $OUTPUT->pix_icon(file_extension_icon('.htm'), '', 'moodle', array('class' => 'icon')). ' '; $this->content->items[] = ''.$icon.$modfullname.''; } else { $icon = ' '; diff --git a/blocks/private_files/edit.php b/blocks/private_files/edit.php index 5a7667bbd76..67b1e70d5bc 100644 --- a/blocks/private_files/edit.php +++ b/blocks/private_files/edit.php @@ -45,7 +45,7 @@ $PAGE->set_pagelayout('mydashboard'); $PAGE->set_pagetype('user-private-files'); $data = new stdClass(); -$options = array('subdirs'=>1, 'maxbytes'=>$CFG->userquota, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL); +$options = array('subdirs'=>1, 'maxbytes'=>$CFG->userquota, 'maxfiles'=>-1, 'accepted_types'=>'*'); file_prepare_standard_filemanager($data, 'files', $options, $context, 'user', 'private', 0); $mform = new block_private_files_form(null, array('data'=>$data, 'options'=>$options)); diff --git a/blocks/private_files/renderer.php b/blocks/private_files/renderer.php index 5c27971e55a..eb109faa1b8 100644 --- a/blocks/private_files/renderer.php +++ b/blocks/private_files/renderer.php @@ -65,14 +65,13 @@ class block_private_files_renderer extends plugin_renderer_base { } $result = '
+ * $fm = new form_filemanager($options); + * $output = get_renderer('core', 'files'); + * echo $output->render($fm); + *+ * + * @param form_filemanager $fm File manager to render + * @return string HTML fragment + */ + public function render_form_filemanager($fm) { + static $filemanagertemplateloaded; + $html = $this->fm_print_generallayout($fm); + $module = array( + 'name'=>'form_filemanager', + 'fullpath'=>'/lib/form/filemanager.js', + 'requires' => array('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') + ) + ); + if (empty($filemanagertemplateloaded)) { + $filemanagertemplateloaded = true; + $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 .= ''; + + + return $html; + } + + /** + * Returns html for displaying one file manager + * + * The main element in HTML must have id="filemanager-{$client_id}" and + * class="filemanager fm-loading"; + * After all necessary code on the page (both html and javascript) is loaded, + * the class fm-loading will be removed and added class fm-loaded; + * The main element (class=filemanager) will be assigned the following classes: + * 'fm-maxfiles' - when filemanager has maximum allowed number of files; + * 'fm-nofiles' - when filemanager has no files at all (although there might be folders); + * 'fm-noitems' - when current view (folder) has no items - neither files nor folders; + * 'fm-updating' - when current view is being updated (usually means that loading icon is to be displayed); + * 'fm-nomkdir' - when 'Make folder' action is unavailable (empty($fm->options->subdirs) == true) + * + * Element with class 'filemanager-container' will be holding evens for dnd upload (dragover, etc.). + * It will have class: + * 'dndupload-ready' - when a file is being dragged over the browser + * 'dndupload-over' - when file is being dragged over this filepicker (additional to 'dndupload-ready') + * 'dndupload-uploading' - during the upload process (note that after dnd upload process is + * over, the file manager will refresh the files list and therefore will have for a while class + * fm-updating. Both waiting processes should look similar so the images don't jump for user) + * + * If browser supports Drag-and-drop, the body element will have class 'dndsupported', + * otherwise - 'dndnotsupported'; + * + * Element with class 'fp-content' will be populated with files list; + * Element with class 'fp-btn-add' will hold onclick event for adding a file (opening filepicker); + * Element with class 'fp-btn-mkdir' will hold onclick event for adding new folder; + * Element with class 'fp-btn-download' will hold onclick event for download action; + * + * Element with class 'fp-path-folder' is a template for one folder in path toolbar. + * It will hold mouse click event and will be assigned classes first/last/even/odd respectfully. + * Parent element will receive class 'empty' when there are no folders to be displayed; + * The content of subelement with class 'fp-path-folder-name' will be substituted with folder name; + * + * Element with class 'fp-viewbar' will have the class 'enabled' or 'disabled' when view mode + * can be changed or not; + * Inside element with class 'fp-viewbar' there are expected elements with classes + * 'fp-vb-icons', 'fp-vb-tree' and 'fp-vb-details'. They will handle onclick events to switch + * between the view modes, the last clicked element will have the class 'checked'; + * + * @param form_filemanager $fm + * @return string + */ + private function fm_print_generallayout($fm) { + global $OUTPUT; + $options = $fm->options; + $client_id = $options->client_id; + $straddfile = get_string('addfile', 'repository'); + $strmakedir = get_string('makeafolder', 'moodle'); + $strdownload = get_string('downloadfolder', 'repository'); + $strloading = get_string('loading', 'repository'); + $strnofilesattached = get_string('nofilesattached', 'repository'); + $strdroptoupload = get_string('droptoupload', 'moodle'); + $icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).''; + $restrictions = $this->fm_print_restrictions($fm); + $strdndenabled = get_string('dndenabled_insentence', 'moodle').$OUTPUT->help_icon('dndenabled'); + $strdndenabledinbox = get_string('dndenabled_inbox', 'moodle'); + $loading = get_string('loading', 'repository'); + + $html = ' +
'.get_string('loading', 'repository').'
+