diff --git a/lib/amd/build/addblockmodal.min.js b/lib/amd/build/addblockmodal.min.js new file mode 100644 index 00000000000..7cf5cb8a2be --- /dev/null +++ b/lib/amd/build/addblockmodal.min.js @@ -0,0 +1 @@ +define(["jquery","core/modal_factory","core/templates","core/str","core/notification"],function(a,b,c,d,e){return{init:function(f){var g=a("[data-key=addblock]");d.get_string("addblock").done(function(e){var h=[];a.each(f.blocks,function(a,b){h[h.length]={key:"pluginname",component:"block_"+b}});var i=[];d.get_strings(h).done(function(d){a.each(d,function(a,b){i[i.length]={name:f.blocks[a],title:b}}),f.blocks=i,b.create({title:e,body:c.render("core/add_block_body",f),type:"CANCEL"},g)})}).fail(e.exception)}}}); \ No newline at end of file diff --git a/lib/amd/build/modal_cancel.min.js b/lib/amd/build/modal_cancel.min.js new file mode 100644 index 00000000000..b74ca27c031 --- /dev/null +++ b/lib/amd/build/modal_cancel.min.js @@ -0,0 +1 @@ +define(["jquery","core/notification","core/custom_interaction_events","core/modal","core/modal_events"],function(a,b,c,d,e){var f={CANCEL_BUTTON:'[data-action="cancel"]'},g=function(a){d.call(this,a),this.getFooter().find(f.CANCEL_BUTTON).length||b.exception({message:"No cancel button found"})};return g.prototype=Object.create(d.prototype),g.prototype.constructor=g,g.prototype.setFooter=function(){b.exception({message:"Can not change the footer of a cancel modal"})},g.prototype.registerEventListeners=function(){d.prototype.registerEventListeners.call(this),this.getModal().on(c.events.activate,f.CANCEL_BUTTON,function(b,c){var d=a.Event(e.cancel);this.getRoot().trigger(d,this),d.isDefaultPrevented()||(this.hide(),c.originalEvent.preventDefault())}.bind(this))},g}); \ No newline at end of file diff --git a/lib/amd/build/modal_factory.min.js b/lib/amd/build/modal_factory.min.js index 6c9d80af856..fb5a544cc95 100644 --- a/lib/amd/build/modal_factory.min.js +++ b/lib/amd/build/modal_factory.min.js @@ -1 +1 @@ -define(["jquery","core/modal_events","core/modal","core/modal_save_cancel","core/modal_confirm","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h){var i={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_confirm"},j={DEFAULT:c,SAVE_CANCEL:d,CONFIRM:e},k={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM"},l=function(a,c){"undefined"!=typeof c&&(h.define(c,[h.events.activate]),c.on(h.events.activate,function(){a.show()}),a.getRoot().on(b.hidden,function(){c.focus()}))},m=function(b,c,d){c=a(c);var e=j[b],f=new e(c);return l(f,d),f},n=function(b,c){var d=i[b];return f.render(d,{}).then(function(d){var e=a(d);return m(b,e,c)}).fail(g.exception)},o=function(a,b){var c=a.type||k.DEFAULT,d=!!a.large;return k[c]||(c=k.DEFAULT),n(c,b).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),d&&b.setLarge(),b})};return{create:o,types:k}}); \ No newline at end of file +define(["jquery","core/modal_events","core/modal","core/modal_save_cancel","core/modal_confirm","core/modal_cancel","core/templates","core/notification","core/custom_interaction_events"],function(a,b,c,d,e,f,g,h,i){var j={DEFAULT:"core/modal",SAVE_CANCEL:"core/modal_save_cancel",CONFIRM:"core/modal_confirm",CANCEL:"core/modal_cancel"},k={DEFAULT:c,SAVE_CANCEL:d,CONFIRM:e,CANCEL:f},l={DEFAULT:"DEFAULT",SAVE_CANCEL:"SAVE_CANCEL",CONFIRM:"CONFIRM",CANCEL:"CANCEL"},m=function(a,c){"undefined"!=typeof c&&(i.define(c,[i.events.activate]),c.on(i.events.activate,function(b,c){a.show(),c.originalEvent.preventDefault()}),a.getRoot().on(b.hidden,function(){c.focus()}))},n=function(b,c,d){c=a(c);var e=k[b],f=new e(c);return m(f,d),f},o=function(b,c){var d=j[b];return g.render(d,{}).then(function(d){var e=a(d);return n(b,e,c)}).fail(h.exception)},p=function(a,b){var c=a.type||l.DEFAULT,d=!!a.large;return l[c]||(c=l.DEFAULT),o(c,b).then(function(b){return"undefined"!=typeof a.title&&b.setTitle(a.title),"undefined"!=typeof a.body&&b.setBody(a.body),"undefined"!=typeof a.footer&&b.setFooter(a.footer),d&&b.setLarge(),b})};return{create:p,types:l}}); \ No newline at end of file diff --git a/lib/amd/src/addblockmodal.js b/lib/amd/src/addblockmodal.js new file mode 100644 index 00000000000..5da0bdec872 --- /dev/null +++ b/lib/amd/src/addblockmodal.js @@ -0,0 +1,64 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Show an add block modal instead of doing it on a separate page. + * + * @module core/addblockmodal + * @class addblockmodal + * @package core + * @copyright 2016 Damyon Wiese + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/modal_factory', 'core/templates', 'core/str', 'core/notification'], + function($, ModalFactory, Templates, Str, Notification) { + + + return /** @alias module:core/addblockmodal */ { + /** + * Global init function for this module. + * + * @method init + * @param {Object} context The template context for rendering this modal body. + */ + init: function(context) { + var addblocklink = $('[data-key=addblock]'); + + // We need the fetch the names of the blocks. It was too much to send in the page. + Str.get_string('addblock').done(function(title) { + + var titlerequests = []; + $.each(context.blocks, function(index, key) { + titlerequests[titlerequests.length] = {key: 'pluginname', component: 'block_' + key}; + }); + + var blocks = []; + Str.get_strings(titlerequests).done(function(titles) { + $.each(titles, function(index, title) { + blocks[blocks.length] = {name: context.blocks[index], title: title}; + }); + + context.blocks = blocks; + + ModalFactory.create({ + title: title, + body: Templates.render('core/add_block_body', context), + type: 'CANCEL', + }, addblocklink); + }); + }).fail(Notification.exception); + } + }; +}); diff --git a/lib/amd/src/modal_cancel.js b/lib/amd/src/modal_cancel.js new file mode 100644 index 00000000000..2e182c1e2d2 --- /dev/null +++ b/lib/amd/src/modal_cancel.js @@ -0,0 +1,77 @@ +// This file is part of Moodle - http://moodle.org/ +// +// Moodle is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// Moodle is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with Moodle. If not, see . + +/** + * Contain the logic for the cancel modal. + * + * @module core/modal_cancel + * @class modal_cancel + * @package core + * @copyright 2016 Ryan Wyllie + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/notification', 'core/custom_interaction_events', 'core/modal', 'core/modal_events'], + function($, Notification, CustomEvents, Modal, ModalEvents) { + + var SELECTORS = { + CANCEL_BUTTON: '[data-action="cancel"]', + }; + + /** + * Constructor for the Modal. + * + * @param {object} root The root jQuery element for the modal + */ + var ModalCancel = function(root) { + Modal.call(this, root); + + if (!this.getFooter().find(SELECTORS.CANCEL_BUTTON).length) { + Notification.exception({message: 'No cancel button found'}); + } + }; + + ModalCancel.prototype = Object.create(Modal.prototype); + ModalCancel.prototype.constructor = ModalCancel; + + /** + * Override parent implementation to prevent changing the footer content. + */ + ModalCancel.prototype.setFooter = function() { + Notification.exception({message: 'Can not change the footer of a cancel modal'}); + return; + }; + + /** + * Set up all of the event handling for the modal. + * + * @method registerEventListeners + */ + ModalCancel.prototype.registerEventListeners = function() { + // Apply parent event listeners. + Modal.prototype.registerEventListeners.call(this); + + this.getModal().on(CustomEvents.events.activate, SELECTORS.CANCEL_BUTTON, function(e, data) { + var cancelEvent = $.Event(ModalEvents.cancel); + this.getRoot().trigger(cancelEvent, this); + + if (!cancelEvent.isDefaultPrevented()) { + this.hide(); + data.originalEvent.preventDefault(); + } + }.bind(this)); + }; + + return ModalCancel; +}); diff --git a/lib/amd/src/modal_factory.js b/lib/amd/src/modal_factory.js index 3622573904c..ffcb16dedfc 100644 --- a/lib/amd/src/modal_factory.js +++ b/lib/amd/src/modal_factory.js @@ -22,15 +22,16 @@ * @copyright 2016 Ryan Wyllie * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', 'core/modal_confirm', +define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', 'core/modal_confirm', 'core/modal_cancel', 'core/templates', 'core/notification', 'core/custom_interaction_events'], - function($, ModalEvents, Modal, ModalSaveCancel, ModalConfirm, Templates, Notification, CustomEvents) { + function($, ModalEvents, Modal, ModalSaveCancel, ModalConfirm, ModalCancel, Templates, Notification, CustomEvents) { // The templates for each type of modal. var TEMPLATES = { DEFAULT: 'core/modal', SAVE_CANCEL: 'core/modal_save_cancel', CONFIRM: 'core/modal_confirm', + CANCEL: 'core/modal_cancel', }; // The JS classes for each type of modal. @@ -38,6 +39,7 @@ define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', ' DEFAULT: Modal, SAVE_CANCEL: ModalSaveCancel, CONFIRM: ModalConfirm, + CANCEL: ModalCancel, }; // The available types of modals. @@ -45,6 +47,7 @@ define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', ' DEFAULT: 'DEFAULT', SAVE_CANCEL: 'SAVE_CANCEL', CONFIRM: 'CONFIRM', + CANCEL: 'CANCEL', }; /** @@ -58,8 +61,9 @@ define(['jquery', 'core/modal_events', 'core/modal', 'core/modal_save_cancel', ' var setUpTrigger = function(modal, triggerElement) { if (typeof triggerElement != 'undefined') { CustomEvents.define(triggerElement, [CustomEvents.events.activate]); - triggerElement.on(CustomEvents.events.activate, function() { + triggerElement.on(CustomEvents.events.activate, function(e, data) { modal.show(); + data.originalEvent.preventDefault(); }); modal.getRoot().on(ModalEvents.hidden, function() { diff --git a/lib/navigationlib.php b/lib/navigationlib.php index 1517456005f..3cedc3a30e6 100644 --- a/lib/navigationlib.php +++ b/lib/navigationlib.php @@ -3769,13 +3769,19 @@ class flat_navigation extends navigation_node_collection { if (isset($this->page->theme->addblockposition) && $this->page->theme->addblockposition == BLOCK_ADDBLOCK_POSITION_FLATNAV && $PAGE->user_is_editing() && $PAGE->user_can_edit_blocks() && - $PAGE->blocks->get_addable_blocks()) { + ($addable = $PAGE->blocks->get_addable_blocks())) { $url = new moodle_url($PAGE->url, ['bui_addblock' => '', 'sesskey' => sesskey()]); $addablock = navigation_node::create(get_string('addblock'), $url); $flat = new flat_navigation_node($addablock, 0); $flat->set_showdivider(true); $flat->key = 'addblock'; $this->add($flat); + $blocks = []; + foreach ($addable as $block) { + $blocks[] = $block->name; + } + $params = array('blocks' => $blocks, 'url' => '?' . $url->get_query_string(false)); + $PAGE->requires->js_call_amd('core/addblockmodal', 'init', array($params)); } } diff --git a/lib/templates/add_block_body.mustache b/lib/templates/add_block_body.mustache new file mode 100644 index 00000000000..21dbe125c76 --- /dev/null +++ b/lib/templates/add_block_body.mustache @@ -0,0 +1,37 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template core/add_block_body + + Template for the body of the add block modal. + + Context variables required for this template: + * blocks - list of blocks containing name and title + * url - base url for links back to same page. + + Example context (json): + { + "blocks" : [ { "name": "test", "title": "Test block" } ], + "url" : "?a=b" + } + +}} +
+{{#blocks}} + {{title}} +{{/blocks}} +
diff --git a/lib/templates/modal_cancel.mustache b/lib/templates/modal_cancel.mustache new file mode 100644 index 00000000000..14884c0c5fb --- /dev/null +++ b/lib/templates/modal_cancel.mustache @@ -0,0 +1,45 @@ +{{! + This file is part of Moodle - http://moodle.org/ + + Moodle is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + Moodle is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with Moodle. If not, see . +}} +{{! + @template core/modal_save_cancel + + Moodle modal template with one cancel button. + + The purpose of this template is to render a modal. + + Classes required for JS: + * none + + Data attributes required for JS: + * none + + Context variables required for this template: + * title A cleaned string (use clean_text()) to display. + * body HTML content for the boday + + Example context (json): + { + "title": "Example cancel modal", + "body": "Some example content for the body" + } +}} + +{{< core/modal }} + {{$footer}} + + {{/footer}} +{{/ core/modal }} diff --git a/lib/templates/modal_confirm.mustache b/lib/templates/modal_confirm.mustache index f2398860ec0..549a3c657a9 100644 --- a/lib/templates/modal_confirm.mustache +++ b/lib/templates/modal_confirm.mustache @@ -40,6 +40,6 @@ {{$body}}{{#str}} areyousure {{/str}}{{/body}} {{$footer}} - + {{/footer}} {{/ core/modal }} diff --git a/lib/templates/modal_save_cancel.mustache b/lib/templates/modal_save_cancel.mustache index f58e402f6cd..4e6326069f4 100644 --- a/lib/templates/modal_save_cancel.mustache +++ b/lib/templates/modal_save_cancel.mustache @@ -41,6 +41,6 @@ {{< core/modal }} {{$footer}} - + {{/footer}} {{/ core/modal }} diff --git a/theme/boost/templates/flat_navigation.mustache b/theme/boost/templates/flat_navigation.mustache index fa3b35ab26e..e1aab0208f9 100644 --- a/theme/boost/templates/flat_navigation.mustache +++ b/theme/boost/templates/flat_navigation.mustache @@ -62,7 +62,7 @@