From 66079e28fdd2a359550cf9cb6bf2710603bb8a7f Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Thu, 7 Mar 2013 20:38:25 +0000 Subject: [PATCH 1/3] MDL-38367 course dndupload - various tweaks to the UI Switched to Moodle-style dialog boxes (thanks Andrew for the pointer) Enter button now submits the form (from within the 'name' field) Upload button is disabled when the name is empty (if the name is required for the selected handler) Dialog now has 'What do you want to do with this text?' and 'Name' for the text Entire course section now has a class added when you drag over it (to enable it to be styled in the future) --- course/dndupload.js | 208 +++++++++++++++++++++--------------- course/dnduploadlib.php | 17 +-- lang/en/moodle.php | 4 +- mod/label/lang/en/label.php | 2 +- mod/page/lang/en/page.php | 2 +- 5 files changed, 139 insertions(+), 94 deletions(-) diff --git a/course/dndupload.js b/course/dndupload.js index 35ded979e36..951af1c0f64 100644 --- a/course/dndupload.js +++ b/course/dndupload.js @@ -239,7 +239,7 @@ M.course_dndupload = { * Look through the event data, checking it against the registered data types * (in order of priority) and return details of the first matching data type * @param e the event details - * @return mixed false if not found or an object { + * @return object|false - false if not found or an object { * realtype: the type as given by the browser * addmessage: the message to show to the user during dragging * namemessage: the message for requesting a name for the resource from the user @@ -284,6 +284,7 @@ M.course_dndupload = { realtype: dttypes[j], addmessage: types[i].addmessage, namemessage: types[i].namemessage, + handlermessage: types[i].handlermessage, type: types[i].identifier, handlers: types[i].handlers }; @@ -417,7 +418,7 @@ M.course_dndupload = { var modsel = section.one(this.modslistselector); if (!modsel) { // Create the above 'ul' if it doesn't exist - var modsel = document.createElement('ul'); + modsel = document.createElement('ul'); modsel.className = 'section img-text'; var contentel = section.get('children').pop(); var brel = contentel.get('children').pop(); @@ -489,6 +490,7 @@ M.course_dndupload = { */ hide_preview_element: function() { this.Y.all('li.dndupload-preview').addClass('dndupload-hidden'); + this.Y.all('.dndupload-over').removeClass('dndupload-over'); }, /** @@ -500,6 +502,7 @@ M.course_dndupload = { show_preview_element: function(section, type) { this.hide_preview_element(); var preview = section.one('li.dndupload-preview').removeClass('dndupload-hidden'); + section.addClass('dndupload-over'); preview.one('span').setContent(type.addmessage); }, @@ -616,44 +619,16 @@ M.course_dndupload = { var Y = this.Y; var self = this; - var panel = new Y.Panel({ + var panel = new M.core.dialogue({ bodyContent: content, - width: 350, - zIndex: 5, - centered: true, + width: '350px', modal: true, visible: true, render: true, - buttons: [{ - value: M.util.get_string('upload', 'moodle'), - action: function(e) { - e.preventDefault(); - // Find out which module was selected - var module = false; - var div = Y.one('#dndupload_handlers'+uploadid); - div.all('input').each(function(input) { - if (input.get('checked')) { - module = input.get('value'); - } - }); - if (!module) { - return; - } - panel.hide(); - // Remember this selection for next time - self.lastselected[extension] = module; - // Do the upload - self.upload_file(file, section, sectionnumber, module); - }, - section: Y.WidgetStdMod.FOOTER - },{ - value: M.util.get_string('cancel', 'moodle'), - action: function(e) { - e.preventDefault(); - panel.hide(); - }, - section: Y.WidgetStdMod.FOOTER - }] + align: { + node: null, + points: [Y.WidgetPositionAlign.CC, Y.WidgetPositionAlign.CC] + } }); // When the panel is hidden - destroy it and then check for other pending uploads panel.after("visibleChange", function(e) { @@ -662,6 +637,39 @@ M.course_dndupload = { self.check_upload_queue(); } }); + + // Add the submit/cancel buttons to the bottom of the dialog. + panel.addButton({ + label: M.util.get_string('upload', 'moodle'), + action: function(e) { + e.preventDefault(); + // Find out which module was selected + var module = false; + var div = Y.one('#dndupload_handlers'+uploadid); + div.all('input').each(function(input) { + if (input.get('checked')) { + module = input.get('value'); + } + }); + if (!module) { + return; + } + panel.hide(); + // Remember this selection for next time + self.lastselected[extension] = module; + // Do the upload + self.upload_file(file, section, sectionnumber, module); + }, + section: Y.WidgetStdMod.FOOTER + }); + panel.addButton({ + label: M.util.get_string('cancel', 'moodle'), + action: function(e) { + e.preventDefault(); + panel.hide(); + }, + section: Y.WidgetStdMod.FOOTER + }); }, /** @@ -822,6 +830,7 @@ M.course_dndupload = { var nameid = 'dndupload_handler_name'+uploadid; var content = ''; if (type.handlers.length > 1) { + content += '

'+type.handlermessage+'

'; content += '
'; var sel = type.handlers[0].module; for (var i=0; i 1) { - // Find out which module was selected - var div = Y.one('#dndupload_handlers'+uploadid); - div.all('input').each(function(input) { - if (input.get('checked')) { - var idx = input.get('value'); - module = type.handlers[idx].module; - noname = type.handlers[idx].noname; - } - }); - if (!module) { - return; - } - } else { - module = type.handlers[0].module; - noname = type.handlers[0].noname; - } - if (name == '' && !noname) { - return; - } - panel.hide(); - // Do the upload - self.upload_item(name, type.type, contents, section, sectionnumber, module); - }, - section: Y.WidgetStdMod.FOOTER - },{ - value: M.util.get_string('cancel', 'moodle'), - action: function(e) { - e.preventDefault(); - panel.hide(); - }, - section: Y.WidgetStdMod.FOOTER - }] + align: { + node: null, + points: [Y.WidgetPositionAlign.CC, Y.WidgetPositionAlign.CC] + } }); + // When the panel is hidden - destroy it and then check for other pending uploads panel.after("visibleChange", function(e) { if (!panel.get('visible')) { @@ -897,19 +868,86 @@ M.course_dndupload = { self.check_upload_queue(); } }); - // Focus on the 'name' box - Y.one('#'+nameid).focus(); + + var namefield = Y.one('#'+nameid); + var submit = function(e) { + e.preventDefault(); + var name = Y.Lang.trim(namefield.get('value')); + var module = false; + var noname = false; + if (type.handlers.length > 1) { + // Find out which module was selected + var div = Y.one('#dndupload_handlers'+uploadid); + div.all('input').each(function(input) { + if (input.get('checked')) { + var idx = input.get('value'); + module = type.handlers[idx].module; + noname = type.handlers[idx].noname; + } + }); + if (!module) { + return; + } + } else { + module = type.handlers[0].module; + noname = type.handlers[0].noname; + } + if (name == '' && !noname) { + return; + } + if (noname) { + name = ''; + } + panel.hide(); + // Do the upload + self.upload_item(name, type.type, contents, section, sectionnumber, module); + }; + + // Add the submit/cancel buttons to the bottom of the dialog. + panel.addButton({ + label: M.util.get_string('upload', 'moodle'), + action: submit, + section: Y.WidgetStdMod.FOOTER, + name: 'submit' + }); + panel.addButton({ + label: M.util.get_string('cancel', 'moodle'), + action: function(e) { + e.preventDefault(); + panel.hide(); + }, + section: Y.WidgetStdMod.FOOTER + }); + var submitbutton = panel.getButton('submit').button; + namefield.on('key', submit, 'enter'); // Submit the form if 'enter' pressed + namefield.after('keyup', function() { + if (Y.Lang.trim(namefield.get('value')) == '') { + submitbutton.disable(); + } else { + submitbutton.enable(); + } + }); + + // Enable / disable the 'name' box, depending on the handler selected. for (i=0; i array('node', 'event', 'panel', 'json', 'anim') + 'requires' => array('node', 'event', 'json', 'anim') ); $vars = array( array('courseid' => $course->id, @@ -113,11 +113,11 @@ class dndupload_handler { // Note: 'Files' type is hard-coded into the Javascript as this needs to be ... // ... treated a little differently. $this->add_type('url', array('url', 'text/uri-list', 'text/x-moz-url'), get_string('addlinkhere', 'moodle'), - get_string('nameforlink', 'moodle'), 10); + get_string('nameforlink', 'moodle'), get_string('whatforlink', 'moodle'), 10); $this->add_type('text/html', array('text/html'), get_string('addpagehere', 'moodle'), - get_string('nameforpage', 'moodle'), 20); + get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 20); $this->add_type('text', array('text', 'text/plain'), get_string('addpagehere', 'moodle'), - get_string('nameforpage', 'moodle'), 30); + get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 30); // Loop through all modules to find handlers. $mods = get_plugin_list_with_function('mod', 'dndupload_register'); @@ -145,8 +145,11 @@ class dndupload_handler { } else { $priority = 100; } + if (!isset($type['handlermessage'])) { + $type['handlermessage'] = ''; + } $this->add_type($type['identifier'], $type['datatransfertypes'], - $type['addmessage'], $type['namemessage'], $priority); + $type['addmessage'], $type['namemessage'], $type['handlermessage'], $priority); } } if (isset($resp['types'])) { @@ -169,10 +172,11 @@ class dndupload_handler { * dragged onto the page * @param string $namemessage The message to pop up when asking for the name to give the * course module instance when it is created + * @param string $handlermessage The message to pop up when asking which module should handle this type * @param int $priority Controls the order in which types are checked by the browser (mainly * needed to check for 'text' last as that is usually given as fallback) */ - public function add_type($identifier, $datatransfertypes, $addmessage, $namemessage, $priority=100) { + public function add_type($identifier, $datatransfertypes, $addmessage, $namemessage, $handlermessage, $priority=100) { if ($this->is_known_type($identifier)) { throw new coding_exception("Type $identifier is already registered"); } @@ -182,6 +186,7 @@ class dndupload_handler { $add->datatransfertypes = $datatransfertypes; $add->addmessage = $addmessage; $add->namemessage = $namemessage; + $add->handlermessage = $handlermessage; $add->priority = $priority; $add->handlers = array(); diff --git a/lang/en/moodle.php b/lang/en/moodle.php index 28cc048428c..9d6b2e1673b 100644 --- a/lang/en/moodle.php +++ b/lang/en/moodle.php @@ -1097,7 +1097,7 @@ $string['mymoodledashboard'] = 'My Moodle dashboard'; $string['myprofile'] = 'My profile'; $string['name'] = 'Name'; $string['nameforlink'] = 'What do you want to call this link?'; -$string['nameforpage'] = 'What do you want to call this text?'; +$string['nameforpage'] = 'Name'; $string['navigation'] = 'Navigation'; $string['needed'] = 'Needed'; $string['never'] = 'Never'; @@ -1806,6 +1806,8 @@ $string['welcometocoursetext'] = 'Welcome to {$a->coursename}! If you have not done so already, you should edit your profile page so that we can learn more about you: {$a->profileurl}'; +$string['whatforlink'] = 'What do you want to do with the link?'; +$string['whatforpage'] = 'What do you want to do with the text?'; $string['whattocallzip'] = 'What do you want to call the zip file?'; $string['whattodo'] = 'What to do'; $string['windowclosing'] = 'This window should close automatically. If not, please close it now.'; diff --git a/mod/label/lang/en/label.php b/mod/label/lang/en/label.php index 55787fcadb5..5731413cea0 100644 --- a/mod/label/lang/en/label.php +++ b/mod/label/lang/en/label.php @@ -31,7 +31,7 @@ $string['dndmedia'] = 'Media drag and drop'; $string['dndresizeheight'] = 'Resize drag and drop height'; $string['dndresizewidth'] = 'Resize drag and drop width'; $string['dnduploadlabel'] = 'Add image to course page'; -$string['dnduploadlabeltext'] = 'Add text to course page'; +$string['dnduploadlabeltext'] = 'Add a label to the course page'; $string['label:addinstance'] = 'Add a new label'; $string['labeltext'] = 'Label text'; $string['modulename'] = 'Label'; diff --git a/mod/page/lang/en/page.php b/mod/page/lang/en/page.php index 3dd3d3c6fb5..d7fbf9a6495 100644 --- a/mod/page/lang/en/page.php +++ b/mod/page/lang/en/page.php @@ -26,7 +26,7 @@ $string['configdisplayoptions'] = 'Select all options that should be available, existing settings are not modified. Hold CTRL key to select multiple fields.'; $string['content'] = 'Page content'; $string['contentheader'] = 'Content'; -$string['createpage'] = 'Create a new page'; +$string['createpage'] = 'Create a new page resource'; $string['displayoptions'] = 'Available display options'; $string['displayselect'] = 'Display'; $string['displayselectexplain'] = 'Select display type.'; From 413bca9f765f358c279865e2e990fa792b3e9872 Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Fri, 8 Mar 2013 21:34:31 +0000 Subject: [PATCH 2/3] MDL-38367 course dndupload - workaround to allow 'add X here' text to be drop target in Firefox --- course/dndupload.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/course/dndupload.js b/course/dndupload.js index 951af1c0f64..ce0ca3298a1 100644 --- a/course/dndupload.js +++ b/course/dndupload.js @@ -503,7 +503,10 @@ M.course_dndupload = { this.hide_preview_element(); var preview = section.one('li.dndupload-preview').removeClass('dndupload-hidden'); section.addClass('dndupload-over'); - preview.one('span').setContent(type.addmessage); + + // Horrible work-around to allow the 'Add X here' text to be a drop target in Firefox. + var node = preview.one('span')._node; + node.firstChild.nodeValue = type.addmessage; }, /** From 09fd07fe0007ed629c2066ab8f81acd33d7d98d6 Mon Sep 17 00:00:00 2001 From: Davo Smith Date: Mon, 18 Mar 2013 18:47:04 +0000 Subject: [PATCH 3/3] MDL-38367 course dndupload - deprecate public 'add_type' function, remove non-YUI3 API call to _node --- course/dndupload.js | 2 +- course/dnduploadlib.php | 25 ++++++++++++++++++++----- 2 files changed, 21 insertions(+), 6 deletions(-) diff --git a/course/dndupload.js b/course/dndupload.js index ce0ca3298a1..b1dbc632f06 100644 --- a/course/dndupload.js +++ b/course/dndupload.js @@ -505,7 +505,7 @@ M.course_dndupload = { section.addClass('dndupload-over'); // Horrible work-around to allow the 'Add X here' text to be a drop target in Firefox. - var node = preview.one('span')._node; + var node = preview.one('span').getDOMNode(); node.firstChild.nodeValue = type.addmessage; }, diff --git a/course/dnduploadlib.php b/course/dnduploadlib.php index 8afa84196b0..a14ebb35f00 100644 --- a/course/dnduploadlib.php +++ b/course/dnduploadlib.php @@ -112,11 +112,11 @@ class dndupload_handler { // Add some default types to handle. // Note: 'Files' type is hard-coded into the Javascript as this needs to be ... // ... treated a little differently. - $this->add_type('url', array('url', 'text/uri-list', 'text/x-moz-url'), get_string('addlinkhere', 'moodle'), + $this->add_type_internal('url', array('url', 'text/uri-list', 'text/x-moz-url'), get_string('addlinkhere', 'moodle'), get_string('nameforlink', 'moodle'), get_string('whatforlink', 'moodle'), 10); - $this->add_type('text/html', array('text/html'), get_string('addpagehere', 'moodle'), + $this->add_type_internal('text/html', array('text/html'), get_string('addpagehere', 'moodle'), get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 20); - $this->add_type('text', array('text', 'text/plain'), get_string('addpagehere', 'moodle'), + $this->add_type_internal('text', array('text', 'text/plain'), get_string('addpagehere', 'moodle'), get_string('nameforpage', 'moodle'), get_string('whatforpage', 'moodle'), 30); // Loop through all modules to find handlers. @@ -148,7 +148,7 @@ class dndupload_handler { if (!isset($type['handlermessage'])) { $type['handlermessage'] = ''; } - $this->add_type($type['identifier'], $type['datatransfertypes'], + $this->add_type_internal($type['identifier'], $type['datatransfertypes'], $type['addmessage'], $type['namemessage'], $type['handlermessage'], $priority); } } @@ -161,6 +161,21 @@ class dndupload_handler { } } + /** + * No external code should be directly adding new types - they should be added via a 'addtypes' array, returned + * by MODNAME_dndupload_register. + * + * @deprecated deprecated since Moodle 2.5 + * @param string $identifier + * @param array $datatransfertypes + * @param string $addmessage + * @param string $namemessage + * @param int $priority + */ + public function add_type($identifier, $datatransfertypes, $addmessage, $namemessage, $priority=100) { + $this->add_type_internal($identifier, $datatransfertypes, $addmessage, $namemessage, '', $priority); + } + /** * Used to add a new mime type that can be drag and dropped onto a * course displayed in a browser window @@ -176,7 +191,7 @@ class dndupload_handler { * @param int $priority Controls the order in which types are checked by the browser (mainly * needed to check for 'text' last as that is usually given as fallback) */ - public function add_type($identifier, $datatransfertypes, $addmessage, $namemessage, $handlermessage, $priority=100) { + protected function add_type_internal($identifier, $datatransfertypes, $addmessage, $namemessage, $handlermessage, $priority=100) { if ($this->is_known_type($identifier)) { throw new coding_exception("Type $identifier is already registered"); }