diff --git a/lib/amd/src/form-autocomplete.js b/lib/amd/src/form-autocomplete.js index 90275cbdb95..60204fbe7ab 100644 --- a/lib/amd/src/form-autocomplete.js +++ b/lib/amd/src/form-autocomplete.js @@ -24,7 +24,9 @@ * @since 3.0 */ /* globals require: false */ -define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification'], function($, log, str, templates, notification) { +define( + ['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification', 'core/loadingicon'], +function($, log, str, templates, notification, LoadingIcon) { // Private functions and variables. /** @var {Object} KEYS - List of keycode constants. */ @@ -555,6 +557,7 @@ define(['jquery', 'core/log', 'core/str', 'core/templates', 'core/notification'] */ var updateAjax = function(e, options, state, originalSelect, ajaxHandler) { var pendingPromise = addPendingJSPromise('updateAjax'); + LoadingIcon.addIconToContainerRemoveOnCompletion($(document.getElementById(state.downArrowId)), pendingPromise); // Get the query to pass to the ajax function. var query = $(e.currentTarget).val(); diff --git a/lib/amd/src/loadingicon.js b/lib/amd/src/loadingicon.js new file mode 100644 index 00000000000..33da54a9213 --- /dev/null +++ b/lib/amd/src/loadingicon.js @@ -0,0 +1,110 @@ +// 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 save/cancel modal. + * + * @module core/loading_icon + * @class loading_icon + * @package core + * @copyright 2019 Andrew Nicols + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later + */ +define(['jquery', 'core/templates'], function($, Templates) { + var TEMPLATES = { + LOADING: 'core/loading', + }; + + var getIcon = function() { + return Templates.render(TEMPLATES.LOADING, {}); + }; + + /** + * Add a loading icon to the end of the specified container and return an unresolved promise. + * + * Resolution of the returned promise causes the icon to be faded out and removed. + * + * @method addIconToContainer + * @param {jQuery} container The element to add the spinner to + * @return {jQuery} The Promise used to create the icon. + */ + var addIconToContainer = function(container) { + return getIcon() + .then(function(html) { + var loadingIcon = $(html).hide(); + container.append(loadingIcon); + loadingIcon.fadeIn(150); + + return loadingIcon; + }); + }; + + /** + * Add a loading icon to the end of the specified container and return an unresolved promise. + * + * Resolution of the returned promise causes the icon to be faded out and removed. + * + * @method addIconToContainerWithPromise + * @param {jQuery} container The element to add the spinner to + * @param {jQuery} loadingIconPromise The jQuery Promise which determines the removal of the icon + * @return {jQuery} The Promise used to create and then remove the icon. + */ + var addIconToContainerRemoveOnCompletion = function(container, loadingIconPromise) { + return getIcon() + .then(function(html) { + var loadingIcon = $(html).hide(); + container.append(loadingIcon); + loadingIcon.fadeIn(150); + + return $.when(loadingIcon.promise(), loadingIconPromise); + }) + .then(function(loadingIcon) { + // Once the content has finished loading and + // the loading icon has been shown then we can + // fade the icon away to reveal the content. + return loadingIcon.fadeOut(100).promise(); + }) + .then(function(loadingIcon) { + loadingIcon.remove(); + + return; + }); + }; + + /** + * Add a loading icon to the end of the specified container and return an unresolved promise. + * + * Resolution of the returned promise causes the icon to be faded out and removed. + * + * @method addIconToContainerWithPromise + * @param {jQuery} container The element to add the spinner to + * @return {jQuery} A jQuery Promise to resolve when ready + */ + var addIconToContainerWithPromise = function(container) { + var loadingIconPromise = $.Deferred(); + + addIconToContainerRemoveOnCompletion(container, loadingIconPromise); + + return loadingIconPromise; + }; + + return { + getIcon: getIcon, + addIconToContainer: addIconToContainer, + addIconToContainerWithPromise: addIconToContainerWithPromise, + addIconToContainerRemoveOnCompletion: addIconToContainerRemoveOnCompletion, + }; + +}); diff --git a/theme/boost/scss/moodle/forms.scss b/theme/boost/scss/moodle/forms.scss index 469e034a3f1..96b59be01ee 100644 --- a/theme/boost/scss/moodle/forms.scss +++ b/theme/boost/scss/moodle/forms.scss @@ -322,6 +322,13 @@ fieldset.coursesearchbox label { top: 0.2em; left: -1.5em; cursor: pointer; + + .loading-icon { + position: absolute; + top: 0; + left: 0; + background-color: $white; + } } .form-autocomplete-selection:focus { diff --git a/theme/boost/style/moodle.css b/theme/boost/style/moodle.css index a083d608c85..772d07196b7 100644 --- a/theme/boost/style/moodle.css +++ b/theme/boost/style/moodle.css @@ -15248,6 +15248,11 @@ fieldset.coursesearchbox label { top: 0.2em; left: -1.5em; cursor: pointer; } + .form-autocomplete-downarrow .loading-icon { + position: absolute; + top: 0; + left: 0; + background-color: #fff; } .form-autocomplete-selection:focus { outline: none; }