MDL-29766 Add drag and drop upload to filemanager / filepicker elements
[moodle.git] / lib / form / filemanager.php
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
17 /**
18  * File manager
19  *
20  * @package    moodlecore
21  * @subpackage file
22  * @copyright  1999 onwards Dongsheng Cai <dongsheng@moodle.com>
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
26 global $CFG;
28 require_once('HTML/QuickForm/element.php');
29 require_once($CFG->dirroot.'/lib/filelib.php');
30 require_once($CFG->dirroot.'/repository/lib.php');
32 class MoodleQuickForm_filemanager extends HTML_QuickForm_element {
33     public $_helpbutton = '';
34     protected $_options    = array('mainfile'=>'', 'subdirs'=>1, 'maxbytes'=>-1, 'maxfiles'=>-1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
36     function MoodleQuickForm_filemanager($elementName=null, $elementLabel=null, $attributes=null, $options=null) {
37         global $CFG, $PAGE;
39         $options = (array)$options;
40         foreach ($options as $name=>$value) {
41             if (array_key_exists($name, $this->_options)) {
42                 $this->_options[$name] = $value;
43             }
44         }
45         if (!empty($options['maxbytes'])) {
46             $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $options['maxbytes']);
47         }
48         $this->_type = 'filemanager';
49         parent::HTML_QuickForm_element($elementName, $elementLabel, $attributes);
50     }
52     function setName($name) {
53         $this->updateAttributes(array('name'=>$name));
54     }
56     function getName() {
57         return $this->getAttribute('name');
58     }
60     function setValue($value) {
61         $this->updateAttributes(array('value'=>$value));
62     }
64     function getValue() {
65         return $this->getAttribute('value');
66     }
68     function getMaxbytes() {
69         return $this->_options['maxbytes'];
70     }
72     function setMaxbytes($maxbytes) {
73         global $CFG;
74         $this->_options['maxbytes'] = get_max_upload_file_size($CFG->maxbytes, $maxbytes);
75     }
77     function getSubdirs() {
78         return $this->_options['subdirs'];
79     }
81     function setSubdirs($allow) {
82         $this->_options['subdirs'] = $allow;
83     }
85     function getMaxfiles() {
86         return $this->_options['maxfiles'];
87     }
89     function setMaxfiles($num) {
90         $this->_options['maxfiles'] = $num;
91     }
93     function setHelpButton($helpbuttonargs, $function='helpbutton'){
94         debugging('component setHelpButton() is not used any more, please use $mform->setHelpButton() instead');
95     }
97     function getHelpButton() {
98         return $this->_helpbutton;
99     }
101     function getElementTemplateType() {
102         if ($this->_flagFrozen){
103             return 'nodisplay';
104         } else {
105             return 'default';
106         }
107     }
109     function toHtml() {
110         global $CFG, $USER, $COURSE, $PAGE, $OUTPUT;
111         require_once("$CFG->dirroot/repository/lib.php");
113         // security - never ever allow guest/not logged in user to upload anything or use this element!
114         if (isguestuser() or !isloggedin()) {
115             print_error('noguest');
116         }
118         if ($this->_flagFrozen) {
119             return $this->getFrozenHtml();
120         }
122         $id          = $this->_attributes['id'];
123         $elname      = $this->_attributes['name'];
124         $subdirs     = $this->_options['subdirs'];
125         $maxbytes    = $this->_options['maxbytes'];
126         $draftitemid = $this->getValue();
127         $accepted_types = $this->_options['accepted_types'];
129         if (empty($draftitemid)) {
130             // no existing area info provided - let's use fresh new draft area
131             require_once("$CFG->libdir/filelib.php");
132             $this->setValue(file_get_unused_draft_itemid());
133             $draftitemid = $this->getValue();
134         }
136         $client_id = uniqid();
138         // filemanager options
139         $options = new stdClass();
140         $options->mainfile  = $this->_options['mainfile'];
141         $options->maxbytes  = $this->_options['maxbytes'];
142         $options->maxfiles  = $this->getMaxfiles();
143         $options->client_id = $client_id;
144         $options->itemid    = $draftitemid;
145         $options->subdirs   = $this->_options['subdirs'];
146         $options->target    = $id;
147         $options->accepted_types = $accepted_types;
148         $options->return_types = FILE_INTERNAL;
149         $options->context = $PAGE->context;
151         $html = $this->_getTabs();
152         $html .= form_filemanager_render($options);
154         $html .= '<input value="'.$draftitemid.'" name="'.$elname.'" type="hidden" />';
155         // label element needs 'for' attribute work
156         $html .= '<input value="" id="id_'.$elname.'" type="hidden" />';
158         return $html;
159     }
164 /**
165  * Data structure representing a file manager.
166  *
167  * @copyright 2010 Dongsheng Cai
168  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
169  * @since     Moodle 2.0
170  */
171 class form_filemanaer_x {
172     //TODO: do not use this abstraction (skodak)
174     public $options;
175     public function __construct(stdClass $options) {
176         global $CFG, $USER, $PAGE;
177         require_once($CFG->dirroot. '/repository/lib.php');
178         $defaults = array(
179             'maxbytes'=>-1,
180             'maxfiles'=>-1,
181             'itemid'=>0,
182             'subdirs'=>0,
183             'client_id'=>uniqid(),
184             'accepted_types'=>'*',
185             'return_types'=>FILE_INTERNAL,
186             'context'=>$PAGE->context
187             );
188         foreach ($defaults as $key=>$value) {
189             if (empty($options->$key)) {
190                 $options->$key = $value;
191             }
192         }
194         $fs = get_file_storage();
196         // initilise options, getting files in root path
197         $this->options = file_get_drafarea_files($options->itemid, '/');
199         // calculate file count
200         $usercontext = get_context_instance(CONTEXT_USER, $USER->id);
201         $files = $fs->get_area_files($usercontext->id, 'user', 'draft', $options->itemid, 'id', false);
202         $filecount = count($files);
203         $this->options->filecount = $filecount;
205         // copying other options
206         foreach ($options as $name=>$value) {
207             $this->options->$name = $value;
208         }
210         // building file picker options
211         $params = new stdClass();
212         $params->accepted_types = $options->accepted_types;
213         $params->return_types = $options->return_types;
214         $params->context = $options->context;
215         $params->env = 'filemanager';
216         $params->disable_types = !empty($options->disable_types)?$options->disable_types:array();
217         $filepicker_options = initialise_filepicker($params);
218         $this->options->filepicker = $filepicker_options;
219     }
222 /**
223  * Print the file manager
224  *
225  * <pre>
226  * $OUTPUT->file_manager($options);
227  * </pre>
228  *
229  * @param array $options associative array with file manager options
230  *   options are:
231  *       maxbytes=>-1,
232  *       maxfiles=>-1,
233  *       itemid=>0,
234  *       subdirs=>false,
235  *       client_id=>uniqid(),
236  *       acepted_types=>'*',
237  *       return_types=>FILE_INTERNAL,
238  *       context=>$PAGE->context
239  * @return string HTML fragment
240  */
241 function form_filemanager_render($options) {
242     global $CFG, $OUTPUT, $PAGE;
244     $fm = new form_filemanaer_x($options); //TODO: this is unnecessary here, the nested options are getting too complex
246     static $filemanagertemplateloaded;
248     $html = '';
249     $options = $fm->options;
250     $straddfile  = get_string('addfile', 'repository');
251     $strmakedir  = get_string('makeafolder', 'moodle');
252     $strdownload = get_string('downloadfolder', 'repository');
253     $strloading  = get_string('loading', 'repository');
255     $icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).'';
257     $client_id = $options->client_id;
258     $itemid    = $options->itemid;
259     list($context, $course, $cm) = get_context_info_array($options->context->id);
260     if (is_object($course)) {
261         $course_maxbytes = $course->maxbytes;
262     } else {
263         $course_maxbytes = $CFG->maxbytes;
264     }
266     if ($options->maxbytes == -1 || empty($options->maxbytes)) {
267         $options->maxbytes = $CFG->maxbytes;
268     }
270     if (empty($options->filecount)) {
271         $extra = ' style="display:none"';
272     } else {
273         $extra = '';
274     }
276     $maxsize = get_string('maxfilesize', 'moodle', display_size(get_max_upload_file_size($CFG->maxbytes, $course_maxbytes, $options->maxbytes)));
277     $strdndenabled = get_string('dndenabled', 'moodle').$OUTPUT->help_icon('dndenabled');
278     $html .= <<<FMHTML
279 <div class="filemanager-loading mdl-align" id='filemanager-loading-{$client_id}'>
280 $icon_progress
281 </div>
282 <div id="filemanager-wrapper-{$client_id}" style="display:none">
283     <div class="fm-breadcrumb" id="fm-path-{$client_id}"></div>
284     <div class="filemanager-toolbar">
285         <input type="button" class="fm-btn-add" id="btnadd-{$client_id}" onclick="return false" value="{$straddfile}" />
286         <input type="button" class="fm-btn-mkdir" id="btncrt-{$client_id}" onclick="return false" value="{$strmakedir}" />
287         <input type="button" class="fm-btn-download" id="btndwn-{$client_id}" onclick="return false" {$extra} value="{$strdownload}" />
288         <span> $maxsize </span>
289         <span id="dndenabled-{$client_id}" style="display: none"> - $strdndenabled </span>
290     </div>
291     <div class="filemanager-container" id="filemanager-{$client_id}">
292         <ul id="draftfiles-{$client_id}" class="fm-filelist">
293             <li>Loading...</li>
294         </ul>
295     </div>
296 </div>
297 <div class='clearer'></div>
298 FMHTML;
299     if (empty($filemanagertemplateloaded)) {
300         $filemanagertemplateloaded = true;
301         $html .= <<<FMHTML
302 <div id="fm-template" style="display:none">___fullname___ ___action___</div>
303 FMHTML;
304     }
306     $module = array(
307         'name'=>'form_filemanager',
308         'fullpath'=>'/lib/form/filemanager.js',
309         'requires' => array('core_filepicker', 'base', 'io-base', 'node', 'json', 'yui2-button', 'yui2-container', 'yui2-layout', 'yui2-menu', 'yui2-treeview', 'core_dndupload'),
310         'strings' => array(array('loading', 'repository'), array('nomorefiles', 'repository'), array('confirmdeletefile', 'repository'),
311              array('add', 'repository'), array('accessiblefilepicker', 'repository'), array('move', 'moodle'),
312              array('cancel', 'moodle'), array('download', 'moodle'), array('ok', 'moodle'),
313              array('emptylist', 'repository'), array('nofilesattached', 'repository'), array('entername', 'repository'), array('enternewname', 'repository'),
314              array('zip', 'editor'), array('unzip', 'moodle'), array('rename', 'moodle'), array('delete', 'moodle'),
315              array('cannotdeletefile', 'error'), array('confirmdeletefile', 'repository'),
316              array('nopathselected', 'repository'), array('popupblockeddownload', 'repository'),
317              array('draftareanofiles', 'repository'), array('path', 'moodle'), array('setmainfile', 'repository'),
318              array('moving', 'repository'), array('files', 'moodle')
319         )
320     );
321     $PAGE->requires->js_module($module);
322     $PAGE->requires->js_init_call('M.form_filemanager.init', array($options), true, $module);
324     // non javascript file manager
325     $filemanagerurl = new moodle_url('/repository/draftfiles_manager.php', array(
326         'env'=>'filemanager',
327         'action'=>'browse',
328         'itemid'=>$itemid,
329         'subdirs'=>$options->subdirs,
330         'maxbytes'=>$options->maxbytes,
331         'maxfiles'=>$options->maxfiles,
332         'ctx_id'=>$PAGE->context->id,
333         'course'=>$PAGE->course->id,
334         'sesskey'=>sesskey(),
335         ));
337     $html .= '<noscript>';
338     $html .= "<div><object type='text/html' data='$filemanagerurl' height='160' width='600' style='border:1px solid #000'></object></div>";
339     $html .= '</noscript>';
342     return $html;