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', '