Merge branch 'MDL-60489-master' of git://github.com/ryanwyllie/moodle

This commit is contained in:
Andrew Nicols 2017-10-23 20:07:33 +08:00
commit 44317628a7
6 changed files with 148 additions and 16 deletions

File diff suppressed because one or more lines are too long

View File

@ -50,6 +50,12 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
*/
var backdropPromise;
/**
* A counter that gets incremented for each modal created. This can be
* used to generate unique values for the modals.
*/
var modalCounter = 0;
/**
* Constructor for the Modal.
*
@ -66,6 +72,7 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
this.isAttached = false;
this.bodyJS = null;
this.footerJS = null;
this.modalCount = modalCounter++;
if (!this.root.is(SELECTORS.CONTAINER)) {
Notification.exception({message: 'Element is not a modal container'});
@ -212,6 +219,16 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
return this.footer;
};
/**
* Get the unique modal count.
*
* @method getModalCount
* @return {int}
*/
Modal.prototype.getModalCount = function() {
return this.modalCount;
};
/**
* Set the modal title element.
*
@ -245,27 +262,97 @@ define(['jquery', 'core/templates', 'core/notification', 'core/key_codes',
Event.notifyFilterContentUpdated(body);
this.getRoot().trigger(ModalEvents.bodyRendered, this);
} else {
var jsPendingId = 'amd-modal-js-pending-id-' + this.getModalCount();
M.util.js_pending(jsPendingId);
// Otherwise we assume it's a promise to be resolved with
// html and javascript.
Templates.render(TEMPLATES.LOADING, {}).done(function(html) {
body.html(html);
var contentPromise = null;
body.css('overflow', 'hidden');
value.done(function(html, js) {
if (value.state() == 'pending') {
// We're still waiting for the body promise to resolve so
// let's show a loading icon.
body.animate({height: '100px'}, 150);
body.html('');
contentPromise = Templates.render(TEMPLATES.LOADING, {})
.then(function(html) {
var loadingIcon = $(html).hide();
body.html(loadingIcon);
loadingIcon.fadeIn(150);
// We only want the loading icon to fade out
// when the content for the body has finished
// loading.
return $.when(loadingIcon.promise(), value);
})
.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() {
return value;
});
} else {
// The content is already loaded so let's just display
// it to the user. No need for a loading icon.
contentPromise = value;
}
// Now we can actually display the content.
contentPromise.then(function(html, js) {
var result = null;
if (this.isVisible()) {
// If the modal is visible then we should display
// the content gracefully for the user.
body.css('opacity', 0);
var currentHeight = body.innerHeight();
body.html(html);
// We need to clear any height values we've set here
// in order to measure the height of the content being
// added. This then allows us to animate the height
// transition.
body.css('height', '');
var newHeight = body.innerHeight();
body.css('height', currentHeight + 'px');
result = body.animate(
{height: newHeight + 'px', opacity: 1},
{duration: 150, queue: false}
).promise();
} else {
// Since the modal isn't visible we can just immediately
// set the content. No need to animate it.
body.html(html);
}
if (js) {
if (this.isAttached) {
// If we're in the DOM then run the JS immediately.
Templates.runTemplateJS(js);
} else {
// Otherwise cache it to be run when we're attached.
this.bodyJS = js;
}
if (js) {
if (this.isAttached) {
// If we're in the DOM then run the JS immediately.
Templates.runTemplateJS(js);
} else {
// Otherwise cache it to be run when we're attached.
this.bodyJS = js;
}
Event.notifyFilterContentUpdated(body);
this.getRoot().trigger(ModalEvents.bodyRendered, this);
}.bind(this));
}.bind(this));
}
Event.notifyFilterContentUpdated(body);
this.getRoot().trigger(ModalEvents.bodyRendered, this);
return result;
}.bind(this))
.fail(Notification.exception)
.always(function() {
// When we're done displaying all of the content we need
// to clear the custom values we've set here.
body.css('height', '');
body.css('overflow', '');
body.css('opacity', '');
M.util.js_complete(jsPendingId);
return;
});
}
};

View File

@ -46,3 +46,4 @@ $breadcrumb-divider-rtl: "◀" !default;
@import "moodle/responsive-tabs";
@import "moodle/bs2-compat";
@import "moodle/print";
@import "moodle/modal";

View File

@ -0,0 +1,16 @@
.modal-body {
& > .loading-icon {
display: block;
position: relative;
width: 100%;
height: 100%;
.icon {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
transform: translate(-50%, -50%);
}
}
}

View File

@ -91,6 +91,21 @@ body {
.modal-body {
max-height: none;
& > .loading-icon {
display: block;
position: relative;
width: 100%;
height: 100%;
.icon {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
transform: translate(-50%, -50%);
}
}
}
.modal-footer {

View File

@ -17177,6 +17177,19 @@ body.modal-open {
.modal-container .modal .modal-body {
max-height: none;
}
.modal-container .modal .modal-body > .loading-icon {
display: block;
position: relative;
width: 100%;
height: 100%;
}
.modal-container .modal .modal-body > .loading-icon .icon {
position: absolute;
top: 50%;
/*rtl:ignore*/
left: 50%;
transform: translate(-50%, -50%);
}
.modal-container .modal .modal-footer {
border-top: 1px solid #bbb;
text-align: center;