You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

184 lines
6.1 KiB

YUI.add('moodle-core-lockscroll', function (Y, NAME) {
/**
* Provides the ability to lock the scroll for a page, allowing nested
* locking.
*
* @module moodle-core-lockscroll
*/
/**
* Provides the ability to lock the scroll for a page.
*
* This is achieved by applying the class 'lockscroll' to the body Node.
*
* Nested widgets are also supported and the scroll lock is only removed
* when the final plugin instance is disabled.
*
* @class M.core.LockScroll
* @extends Plugin.Base
*/
Y.namespace('M.core').LockScroll = Y.Base.create('lockScroll', Y.Plugin.Base, [], {
/**
* Whether the LockScroll has been activated.
*
* @property _enabled
* @type Boolean
* @protected
*/
_enabled: false,
/**
* Handle destruction of the lockScroll instance, including disabling
* of the current instance.
*
* @method destructor
*/
destructor: function() {
this.disableScrollLock();
},
/**
* Start locking the page scroll.
*
* This is achieved by applying the lockscroll class to the body Node.
*
* A count of the total number of active, and enabled, lockscroll instances is also kept on
* the body to ensure that premature disabling does not occur.
*
* @method enableScrollLock
* @param {Boolean} forceOnSmallWindow Whether to enable the scroll lock, even for small window sizes.
* @chainable
*/
enableScrollLock: function(forceOnSmallWindow) {
if (this.isActive()) {
Y.log('LockScroll already active. Ignoring enable request', 'warn', 'moodle-core-lockscroll');
return;
}
if (!this.shouldLockScroll(forceOnSmallWindow)) {
Y.log('Dialogue height greater than window height. Ignoring enable request.', 'warn', 'moodle-core-lockscroll');
return;
}
Y.log('Enabling LockScroll.', 'debug', 'moodle-core-lockscroll');
this._enabled = true;
var body = Y.one(Y.config.doc.body);
// Get width of body before turning on lockscroll.
var widthBefore = body.getComputedStyle('width');
// We use a CSS class on the body to handle the actual locking.
body.addClass('lockscroll');
// Increase the count of active instances - this is used to ensure that we do not
// remove the locking when parent windows are still open.
// Note: We cannot use getData here because data attributes are sandboxed to the instance that created them.
var currentCount = parseInt(body.getAttribute('data-activeScrollLocks'), 10) || 0,
newCount = currentCount + 1;
body.setAttribute('data-activeScrollLocks', newCount);
Y.log("Setting the activeScrollLocks count from " + currentCount + " to " + newCount,
'debug', 'moodle-core-lockscroll');
// When initially enabled, set the body max-width to its current width. This
// avoids centered elements jumping because the width changes when scrollbars
// disappear.
if (currentCount === 0) {
body.setStyle('maxWidth', widthBefore);
}
return this;
},
/**
* Recalculate whether lock scrolling should be on or off.
*
* @method shouldLockScroll
* @param {Boolean} forceOnSmallWindow Whether to enable the scroll lock, even for small window sizes.
* @return boolean
*/
shouldLockScroll: function(forceOnSmallWindow) {
var dialogueHeight = this.get('host').get('boundingBox').get('region').height,
// Most modern browsers use win.innerHeight, but some older versions of IE use documentElement.clientHeight.
// We fall back to 0 if neither can be found which has the effect of disabling scroll locking.
windowHeight = Y.config.win.innerHeight || Y.config.doc.documentElement.clientHeight || 0;
if (!forceOnSmallWindow && dialogueHeight > (windowHeight - 10)) {
return false;
} else {
return true;
}
},
/**
* Recalculate whether lock scrolling should be on or off because the size of the dialogue changed.
*
* @method updateScrollLock
* @param {Boolean} forceOnSmallWindow Whether to enable the scroll lock, even for small window sizes.
* @chainable
*/
updateScrollLock: function(forceOnSmallWindow) {
// Both these functions already check if scroll lock is active and do the right thing.
if (this.shouldLockScroll(forceOnSmallWindow)) {
this.enableScrollLock(forceOnSmallWindow);
} else {
this.disableScrollLock(true);
}
return this;
},
/**
* Stop locking the page scroll.
*
* The instance may be disabled but the scroll lock not removed if other instances of the
* plugin are also active.
*
* @method disableScrollLock
* @chainable
*/
disableScrollLock: function(force) {
if (this.isActive()) {
Y.log('Disabling LockScroll.', 'debug', 'moodle-core-lockscroll');
this._enabled = false;
var body = Y.one(Y.config.doc.body);
// Decrease the count of active instances.
// Note: We cannot use getData here because data attributes are sandboxed to the instance that created them.
var currentCount = parseInt(body.getAttribute('data-activeScrollLocks'), 10) || 1,
newCount = currentCount - 1;
if (force || currentCount === 1) {
body.removeClass('lockscroll');
body.setStyle('maxWidth', null);
}
body.setAttribute('data-activeScrollLocks', currentCount - 1);
Y.log("Setting the activeScrollLocks count from " + currentCount + " to " + newCount,
'debug', 'moodle-core-lockscroll');
}
return this;
},
/**
* Return whether scroll locking is active.
*
* @method isActive
* @return Boolean
*/
isActive: function() {
return this._enabled;
}
}, {
NS: 'lockScroll',
ATTRS: {
}
});
}, '@VERSION@', {"requires": ["plugin", "base-build"]});