@openui5/sap.ui.core
Version:
OpenUI5 Core Library sap.ui.core
383 lines (329 loc) • 12.8 kB
JavaScript
/*!
* OpenUI5
* (c) Copyright 2009-2021 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
/* globals Map */
// Provides class sap.ui.core.ResizeHandler
sap.ui.define([
'sap/ui/base/Object',
"sap/base/Log",
"sap/ui/util/ActivityDetection",
"sap/ui/core/IntervalTrigger",
"sap/ui/thirdparty/jquery"
],
function(BaseObject, Log, ActivityDetection, IntervalTrigger, jQuery) {
"use strict";
// local logger, by default only logging errors
var log = Log.getLogger("sap.ui.core.ResizeHandler", Log.Level.ERROR);
/**
* Reference to the Core (implementation view, not facade)
* @type {sap.ui.core.Core}
*/
var oCoreRef = null;
/**
* The resize handling API provides firing of resize events on all browsers by regularly
* checking the width and height of registered DOM elements or controls and firing events accordingly.
*
* @namespace
* @alias sap.ui.core.ResizeHandler
* @extends sap.ui.base.Object
* @author SAP SE
* @version 1.87.1
* @public
*/
var ResizeHandler = BaseObject.extend("sap.ui.core.ResizeHandler", /** @lends sap.ui.core.ResizeHandler.prototype */ {
constructor : function(oCore) {
BaseObject.apply(this);
oCoreRef = oCore;
this.aResizeListeners = [];
this.aSuspendedDomRefs = [];
this.bRegistered = false;
this.mCallbacks = new Map();
this.iIdCounter = 0;
this.fDestroyHandler = this.destroy.bind(this);
jQuery(window).on("unload", this.fDestroyHandler);
ActivityDetection.attachActivate(initListener, this);
}
});
function clearListener(){
if (this.bRegistered) {
this.bRegistered = false;
IntervalTrigger.removeListener(this.checkSizes, this);
}
}
function initListener(){
if (!this.bRegistered && this.aResizeListeners.length > 0) {
this.bRegistered = true;
IntervalTrigger.addListener(this.checkSizes, this);
}
}
/**
* Destroy method of the Resize Handler.
* It unregisters the event handlers.
*
* @param {jQuery.Event} oEvent the event that initiated the destruction of the ResizeHandler
* @private
*/
ResizeHandler.prototype.destroy = function(oEvent) {
ActivityDetection.detachActivate(initListener, this);
jQuery(window).off("unload", this.fDestroyHandler);
oCoreRef = null;
this.aResizeListeners = [];
this.aSuspendedDomRefs = [];
clearListener.call(this);
};
/**
* Attaches listener to resize event.
*
* @param {Element|sap.ui.core.Control} oRef the DOM reference or a control
* @param {function} fHandler the event handler function
* @return {string} Registration-ID for later detaching.
* @private
*/
ResizeHandler.prototype.attachListener = function(oRef, fHandler){
var bIsControl = BaseObject.isA(oRef, 'sap.ui.core.Control'),
bIsJQuery = oRef instanceof jQuery, // actually, jQuery objects are not allowed as oRef, as per the API documentation. But this happens in the wild.
oDom = bIsControl ? oRef.getDomRef() : oRef,
iWidth = oDom ? oDom.offsetWidth : 0,
iHeight = oDom ? oDom.offsetHeight : 0,
sId = "rs-" + Date.now() + "-" + this.iIdCounter++,
dbg;
if (bIsControl) {
dbg = ("Control " + oRef.getId());
} else if (oRef.id) {
dbg = oRef.id;
} else {
dbg = String(oRef);
}
this.aResizeListeners.push({sId: sId, oDomRef: bIsControl ? null : oRef, oControl: bIsControl ? oRef : null, bIsJQuery: bIsJQuery, fHandler: fHandler, iWidth: iWidth, iHeight: iHeight, dbg: dbg});
log.debug("registered " + dbg);
initListener.call(this);
return sId;
};
/**
* Detaches listener from resize event.
*
* @param {string} sId Registration-ID returned from attachListener
* @private
*/
ResizeHandler.prototype.detachListener = function(sId){
var aResizeListeners = this.aResizeListeners;
for ( var i = 0; i < aResizeListeners.length; i++ ) {
if (aResizeListeners[i].sId === sId) {
aResizeListeners.splice(i, 1);
log.debug("deregistered " + sId);
break;
}
}
// if list is empty now, stop interval
if (aResizeListeners.length === 0) {
clearListener.call(this);
}
};
/**
* Check sizes of resize elements.
* @private
*/
ResizeHandler.prototype.checkSizes = function() {
var bDebug = log.isLoggable();
if ( bDebug ) {
log.debug("checkSizes:");
}
this.aResizeListeners.forEach(function(oResizeListener){
if (oResizeListener) {
var bCtrl = !!oResizeListener.oControl,
oDomRef = bCtrl ? oResizeListener.oControl.getDomRef() : oResizeListener.oDomRef;
oDomRef = oResizeListener.bIsJQuery ? oDomRef[0] : oDomRef;
if (oDomRef && document.documentElement.contains(oDomRef) && !this._isSuspended(oDomRef)) { //check that domref is still active and not suspended
var iOldWidth = oResizeListener.iWidth,
iOldHeight = oResizeListener.iHeight,
iNewWidth = oDomRef.offsetWidth,
iNewHeight = oDomRef.offsetHeight;
if (iOldWidth != iNewWidth || iOldHeight != iNewHeight) {
oResizeListener.iWidth = iNewWidth;
oResizeListener.iHeight = iNewHeight;
var oEvent = jQuery.Event("resize");
oEvent.target = oDomRef;
oEvent.currentTarget = oDomRef;
oEvent.size = {width: iNewWidth, height: iNewHeight};
oEvent.oldSize = {width: iOldWidth, height: iOldHeight};
oEvent.control = bCtrl ? oResizeListener.oControl : null;
if ( bDebug ) {
log.debug("resize detected for '" + oResizeListener.dbg + "': " + oEvent.oldSize.width + "x" + oEvent.oldSize.height + " -> " + oEvent.size.width + "x" + oEvent.size.height);
}
oResizeListener.fHandler(oEvent);
}
}
}
}, this);
if (ResizeHandler._keepActive != true && ResizeHandler._keepActive != false) {
//initialize default
ResizeHandler._keepActive = false;
}
if (!ActivityDetection.isActive() && !ResizeHandler._keepActive) {
clearListener.call(this);
}
};
/**
* Registers the given event handler for resize events on the given DOM element or control.
*
* <b>Note:</b> This function must not be used before the UI5 framework is initialized.
* Please use the {@link sap.ui.core.Core#attachInit init event} of UI5 if you are not sure whether this is the case.
*
* The resize handler periodically checks the dimensions of the registered reference. Whenever it detects changes, an event is fired.
* Be careful when changing dimensions within the event handler which might cause another resize event and so on.
*
* The available parameters of the resize event are:
* <ul>
* <li><code>oEvent.target</code>: The DOM element of which the dimensions were checked</li>
* <li><code>oEvent.size.width</code>: The current width of the DOM element in pixels</li>
* <li><code>oEvent.size.height</code>: The current height of the DOM element in pixels</li>
* <li><code>oEvent.oldSize.width</code>: The previous width of the DOM element in pixels</li>
* <li><code>oEvent.oldSize.height</code>: The previous height of the DOM element in pixels</li>
* <li><code>oEvent.control</code>: The control which was given during registration of the event handler (if present)</li>
* </ul>
*
* @param {Element|sap.ui.core.Control} oRef The control or the DOM reference for which the given event handler should be registered (beside the window)
* @param {function} fHandler
* The event handler which should be called whenever the size of the given reference is changed.
* The event object is passed as first argument to the event handler. See the description of this function for more details about the available parameters of this event.
* @return {string}
* A registration ID which can be used for deregistering the event handler, see {@link sap.ui.core.ResizeHandler.deregister}.
* If the UI5 framework is not yet initialized <code>null</code> is returned.
* @public
*/
ResizeHandler.register = function(oRef, fHandler) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return null;
}
return oCoreRef.oResizeHandler.attachListener(oRef, fHandler);
};
/**
* Deregisters a previously registered handler for resize events with the given registration ID.
*
* @param {string} sId
* The registration ID of the handler to deregister. The ID was provided by function {@link sap.ui.core.ResizeHandler.register}
* when the handler was registered.
* @public
*/
ResizeHandler.deregister = function(sId) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return;
}
oCoreRef.oResizeHandler.detachListener(sId);
};
/**
* Deregisters all registered handler for resize events for the given control.
*
* @param {string} sControlId The Id of the control.
* @private
*/
ResizeHandler.deregisterAllForControl = function(sControlId) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return;
}
oCoreRef.oResizeHandler.aResizeListeners.filter(function(oResizeListener){
return oResizeListener && oResizeListener.oControl && oResizeListener.oControl.getId() === sControlId;
}).forEach(function(oResizeListener) {
ResizeHandler.deregister(oResizeListener.sId);
});
};
/**
* Suspends indefinitely the execution of ResizeHandler listeners for the given DOM reference and its children
* @param {Element} oDomRef the DOM reference to suspend
* @return {boolean} Whether the <code>oDomRef</code> was successfully marked as suspended
* @private
*/
ResizeHandler.suspend = function(oDomRef) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return false;
}
// Check if the dom ref is valid within the document
if (!document.documentElement.contains(oDomRef)) {
return false;
}
// Check if the dom ref is already suspended
var oResizeHandler = oCoreRef.oResizeHandler;
if (oResizeHandler.aSuspendedDomRefs.indexOf(oDomRef) === -1) {
oResizeHandler.aSuspendedDomRefs.push(oDomRef);
}
return true;
};
/**
* Resumes the execution of ResizeHandler listeners for the given DOM reference
* @param {Element} oDomRef the DOM reference to resume
* @return {boolean} Whether resume for <code>oDomRef</code> was successful
* @private
*/
ResizeHandler.resume = function(oDomRef) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return false;
}
var oResizeHandler = oCoreRef.oResizeHandler,
iIndex = oResizeHandler.aSuspendedDomRefs.indexOf(oDomRef);
// If the dom ref is not registered, nothing to do
if (iIndex === -1) {
return false;
}
// Remove the dom ref and execute listeners again
oResizeHandler.aSuspendedDomRefs.splice(iIndex, 1);
oResizeHandler.checkSizes();
// inform interested parties
var aCallbacks = oResizeHandler.mCallbacks.get(oDomRef);
if (aCallbacks) {
for (var i = 0; i < aCallbacks.length; i++) {
aCallbacks[i]();
}
oResizeHandler.mCallbacks.delete(oDomRef);
}
return true;
};
/**
* Checks if the given DOM reference is a child (or exact match) of a DOM area that is suspended from observation for size changes.
* This instance method is an internal shortcut.
* @param {Element} oDomRef the DOM reference
* @return {boolean} Whether the <code>oDomRef</code> is suspended
* @private
*/
ResizeHandler.prototype._isSuspended = function(oDomRef) {
var aSuspendedDomRefs = this.aSuspendedDomRefs,
oNextSuspendedDomRef;
for (var i = 0; i < aSuspendedDomRefs.length; i++) {
oNextSuspendedDomRef = aSuspendedDomRefs[i];
if (oNextSuspendedDomRef.contains(oDomRef)) {
return oNextSuspendedDomRef;
}
}
return false;
};
/**
* Checks if the given DOM reference is a child (or exact match) of a DOM area that is suspended from observation for size changes
*
* @param {Element} oDomRef the DOM reference.
* @param {function} [fnCallback] a callback function to be called once the DOM node is resumed which was found to be the primary
* reason for oDomRef to be suspended. Note that isSuspended() may still be true when other DOM nodes are still suspended.
* Also note that each isSuspended() call registers the callback, but only if it was not found to be already registered.
* @return {boolean} Whether the <code>oDomRef</code> is suspended
* @private
*/
ResizeHandler.isSuspended = function(oDomRef, fnCallback) {
if (!oCoreRef || !oCoreRef.oResizeHandler) {
return false;
}
var oHandler = oCoreRef.oResizeHandler;
var vSuspended = oHandler._isSuspended(oDomRef);
if (fnCallback && vSuspended) { // DOM node causing the suspension
var aCallbacks = oHandler.mCallbacks.get(vSuspended);
if (!aCallbacks) {
aCallbacks = [];
oHandler.mCallbacks.set(vSuspended, aCallbacks);
}
if (aCallbacks.indexOf(fnCallback) === -1) {
aCallbacks.push(fnCallback);
}
}
return !!vSuspended;
};
return ResizeHandler;
});