diff --git a/lang/en/moodle.php b/lang/en/moodle.php index eb14f766fb3..f9371e34bb8 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -464,6 +464,7 @@ $string['downloadfile'] = 'Download file'; $string['downloadods'] = 'Download in ODS format'; $string['downloadtext'] = 'Download in text format'; $string['doyouagree'] = 'Have you read these conditions and understood them?'; +$string['droptoupload'] = 'Drop files here to upload'; $string['duplicate'] = 'Duplicate'; $string['duplicateconfirm'] = 'Are you sure you want to duplicate {$a->modtype} \'{$a->modname}\' ?'; $string['duplicatecontcourse'] = 'Return to the course'; @@ -969,6 +970,7 @@ $string['manageroles'] = 'Roles and permissions'; $string['markedthistopic'] = 'This topic is highlighted as the current topic'; $string['markthistopic'] = 'Highlight this topic as the current topic'; $string['matchingsearchandrole'] = 'Matching \'{$a->search}\' and {$a->role}'; +$string['maxfilesreached'] = 'You are allowed to attach a maximum of {$a} file(s) to this item'; $string['maximumgrade'] = 'Maximum grade'; $string['maximumgradex'] = 'Maximum grade: {$a}'; $string['maximumchars'] = 'Maximum of {$a} characters'; diff --git a/lib/form/dndupload.js b/lib/form/dndupload.js index e29e3788a8c..b09e1a56ed0 100644 --- a/lib/form/dndupload.js +++ b/lib/form/dndupload.js @@ -51,7 +51,7 @@ M.form_dndupload.init = function(Y, options) { // Nasty hack to distinguish between dragenter(first entry), // dragenter+dragleave(moving between child elements) and dragleave (leaving element) entercount: 0, - + pageentercount: 0, /** * Initalise the drag and drop upload interface @@ -108,6 +108,7 @@ M.form_dndupload.init = function(Y, options) { } this.init_events(); + this.init_page_events(); this.Y.one('#dndenabled-'+this.clientid).setStyle('display', 'inline'); }, @@ -153,6 +154,51 @@ M.form_dndupload.init = function(Y, options) { this.Y.on('drop', this.drop, this.container, this); }, + /** + * Initialise whole-page events (to show / hide the 'drop files here' + * message) + */ + init_page_events: function() { + this.Y.on('dragenter', this.drag_enter_page, 'body', this); + this.Y.on('dragleave', this.drag_leave_page, 'body', this); + }, + + /** + * Show the 'drop files here' message when file(s) are dragged + * onto the page + */ + drag_enter_page: function(e) { + if (!this.has_files(e) || this.reached_maxfiles()) { + return false; + } + + this.pageentercount++; + if (this.pageentercount >= 2) { + this.pageentercount = 2; + return false; + } + + this.show_drop_target(); + + return false; + }, + + /** + * Hide the 'drop files here' message when file(s) are dragged off + * the page again + */ + drag_leave_page: function(e) { + this.pageentercount--; + if (this.pageentercount == 1) { + return false; + } + this.pageentercount = 0; + + this.hide_drop_target(); + + return false; + }, + /** * Check if the drag contents are valid and then call * preventdefault / stoppropagation to let the browser know @@ -161,7 +207,7 @@ M.form_dndupload.init = function(Y, options) { * @param e event object * @return boolean true if a valid file drag event */ - check_drag: function(e) { + check_drag: function(e, maxfilesalert) { if (!this.has_files(e)) { return false; } @@ -170,6 +216,9 @@ M.form_dndupload.init = function(Y, options) { e.stopPropagation(); if (this.reached_maxfiles()) { + if (typeof(maxfilesalert) != 'undefined' && maxfilesalert) { + alert(M.util.get_string('maxfilesreached', 'moodle', this.maxfiles)); + } return false; } @@ -191,6 +240,12 @@ M.form_dndupload.init = function(Y, options) { return false; } + // These lines are needed if the user has dragged something directly + // from application onto the 'fileupload' box, without crossing another + // part of the page first + this.pageentercount = 2; + this.show_drop_target(); + this.show_upload_ready(); return false; }, @@ -231,12 +286,14 @@ M.form_dndupload.init = function(Y, options) { * of the files (until we reach the file limit, or run out of files) */ drop: function(e) { - if (!this.check_drag(e)) { + if (!this.check_drag(e, true)) { return true; } this.entercount = 0; + this.pageentercount = 0; this.hide_upload_ready(); + this.hide_drop_target(); this.show_progress_spinner(); var files = e._event.dataTransfer.files; @@ -244,6 +301,7 @@ M.form_dndupload.init = function(Y, options) { var currentfilecount = this.filemanager.filecount; for (var i=0, f; f=files[i]; i++) { if (currentfilecount >= this.maxfiles && this.maxfiles != -1) { + alert(M.util.get_string('maxfilesreached', 'moodle', this.maxfiles)); break; } if (this.upload_file(f)) { @@ -290,7 +348,18 @@ M.form_dndupload.init = function(Y, options) { }, /** - * Highlight the destination node + * Highlight the area where files could be dropped + */ + show_drop_target: function() { + this.Y.one('#filemanager-uploadmessage'+this.clientid).setStyle('display', 'block'); + }, + + hide_drop_target: function() { + this.Y.one('#filemanager-uploadmessage'+this.clientid).setStyle('display', 'none'); + }, + + /** + * Highlight the destination node (ready to drop) */ show_upload_ready: function() { this.container.addClass('dndupload-over'); @@ -317,7 +386,10 @@ M.form_dndupload.init = function(Y, options) { * Remove progress spinner in the destination node */ hide_progress_spinner: function() { - this.Y.one('#dndprogresspinner-'+this.clientid).remove(); + var spinner = this.Y.one('#dndprogresspinner-'+this.clientid); + if (spinner) { + spinner.remove(); + } }, /** diff --git a/lib/form/filemanager.js b/lib/form/filemanager.js index d3d237b0533..de89ff33ff8 100644 --- a/lib/form/filemanager.js +++ b/lib/form/filemanager.js @@ -264,7 +264,13 @@ M.form_filemanager.init = function(Y, options) { }, this); }, empty_filelist: function(container) { - container.set('innerHTML', '
'+M.str.repository.nofilesattached+'
'); + container.set('innerHTML', '
'+M.str.repository.nofilesattached+'
'+this.upload_message()); + }, + upload_message: function() { + var div = ''; + return div; }, render: function() { var options = this.options; @@ -415,6 +421,7 @@ M.form_filemanager.init = function(Y, options) { var filelist = Y.Node.create(''); container.appendChild(filelist); } + listhtml += this.upload_message(); Y.one('#draftfiles-'+this.client_id).set('innerHTML', listhtml); // click normal file menu diff --git a/lib/form/filemanager.php b/lib/form/filemanager.php index 1d9358590ef..7d42d81c483 100644 --- a/lib/form/filemanager.php +++ b/lib/form/filemanager.php @@ -288,7 +288,7 @@ $icon_progress $maxsize -
+
diff --git a/lib/form/filepicker.js b/lib/form/filepicker.js index 51d8ef6f911..4c99ea8d468 100644 --- a/lib/form/filepicker.js +++ b/lib/form/filepicker.js @@ -6,6 +6,7 @@ M.form_filepicker.instances = []; M.form_filepicker.callback = function(params) { var html = ''+params['file']+''; document.getElementById('file_info_'+params['client_id']).innerHTML = html; + M.form_filepicker.add_upload_message(params['client_id']); //When file is added then set status of global variable to true var elementname = M.core_filepicker.instances[params['client_id']].options.elementname; M.form_filepicker.instances[elementname].fileadded = true; @@ -13,6 +14,15 @@ M.form_filepicker.callback = function(params) { M.form_filepicker.Y.one('#id_'+elementname).simulate('change'); }; +M.form_filepicker.add_upload_message = function(client_id) { + var div = ''; + var iteminfo = document.getElementById('file_info_'+client_id); + iteminfo.innerHTML += div; + iteminfo.style.position = 'relative'; +} + /** * This fucntion is called for each file picker on page. */ @@ -42,6 +52,7 @@ M.form_filepicker.init = function(Y, options) { item = document.getElementById('filepicker-wrapper-'+options.client_id); if (item) { item.style.display = ''; + this.add_upload_message(options.client_id); } var dndoptions = { diff --git a/lib/outputrequirementslib.php b/lib/outputrequirementslib.php index 56fbe201187..2737fe5063b 100644 --- a/lib/outputrequirementslib.php +++ b/lib/outputrequirementslib.php @@ -468,7 +468,7 @@ class page_requirements_manager { $module = array('name' => 'core_dndupload', 'fullpath' => '/lib/form/dndupload.js', 'requires' => array('node', 'event', 'json'), - 'strings' => array(array('uploadformlimit', 'moodle'))); + 'strings' => array(array('uploadformlimit', 'moodle'), array('droptoupload', 'moodle'), array('maxfilesreached', 'moodle'))); break; } diff --git a/theme/base/style/core.css b/theme/base/style/core.css index d7c95c8d288..c7fed783488 100644 --- a/theme/base/style/core.css +++ b/theme/base/style/core.css @@ -532,8 +532,12 @@ body.tag .managelink {padding: 5px;} .fm-file-entry{border: 1px solid red;} .fm-operation {font-weight: bold;} -.filemanager-container.dndupload-over, -.filepicker-filelist.dndupload-over {background: #8EF947;} +.filemanager-container, +.filepicker-filelist {overflow:hidden;} +.filemanager-container .dndupload-target, +.filepicker-filelist .dndupload-target {background:#f7f998;position:absolute;height:100%;width:100%;top:0;left:0;text-align:center;padding:5px;z-index:1000} +.filemanager-container.dndupload-over .dndupload-target, +.filepicker-filelist.dndupload-over .dndupload-target {background:#8EF947;font-weight:bold} /* * Backup and Restore CSS