/*!
* UI development toolkit for HTML5 (OpenUI5)
* (c) Copyright 2009-2018 SAP SE or an SAP affiliate company.
* Licensed under the Apache License, Version 2.0 - see LICENSE.txt.
*/
// Provides control sap.m.PullToRefresh.
sap.ui.define([
'jquery.sap.global',
'./library',
'sap/ui/core/Control',
'sap/ui/Device',
'./PullToRefreshRenderer',
"sap/ui/events/KeyCodes",
"sap/base/security/encodeXML"
],
function(jQuery, library, Control, Device, PullToRefreshRenderer, KeyCodes, encodeXML) {
"use strict";
// shortcut for sap.m.ImageHelper
var ImageHelper = library.ImageHelper;
/**
* Constructor for a new PullToRefresh.
*
* @param {string} [sId] id for the new control, generated automatically if no id is given
* @param {object} [mSettings] initial settings for the new control
*
* @class
* PullToRefresh control. Put it as the first control in contents of a scroll container or a scrollable page. Do not place it into a page with disabled scrolling.
* On touch devices it gets hidden by default and when the user pulls down the page far enough, it gets visible and triggers the "refresh" event.
* In non-touch browsers where scrollbars are used for scrolling, it is always visible and triggers the "refresh" event when clicked.
*
* @see {@link topic:fde40159afce478eb488ee4d0f9ebb99 Pull to Refresh}
*
* @extends sap.ui.core.Control
*
* @author SAP SE
* @version 1.60.23
*
* @constructor
* @public
* @since 1.9.2
* @alias sap.m.PullToRefresh
* @ui5-metamodel This control/element also will be described in the UI5 (legacy) designtime metamodel
*/
var PullToRefresh = Control.extend("sap.m.PullToRefresh", /** @lends sap.m.PullToRefresh.prototype */ { metadata : {
library : "sap.m",
properties : {
/**
* Optional description. May be used to inform a user, for example, when the list has been updated last time.
*/
description : {type : "string", group : "Misc", defaultValue : null},
/**
* Set to true to display an icon/logo. Icon must be set either in the customIcon property or in the CSS theme for the PullToRefresh control.
*/
showIcon : {type : "boolean", group : "Appearance", defaultValue : false},
/**
* Provide a URI to a custom icon image to replace the SAP logo. Large images are scaled down to max 50px height.
*/
customIcon : {type : "sap.ui.core.URI", group : "Appearance", defaultValue : null},
/**
* By default, this is set to true but then one or more requests are sent trying to get the density perfect version of image if this version of image doesn't exist on the server.
*
* If bandwidth is the key for the application, set this value to false.
*/
iconDensityAware : {type : "boolean", group : "Appearance", defaultValue : true}
},
events : {
/**
* Event indicates that the user has requested new data
*/
refresh : {}
}
}});
PullToRefresh.prototype.init = function(){
//TODO: global jquery call found
this._bTouchMode = Device.support.touch && !Device.system.combi || jQuery.sap.simulateMobileOnDesktop;
this._iState = 0; // 0 - normal; 1 - release to refresh; 2 - loading
};
PullToRefresh.prototype._loadBI = function(){
// lazy create a Busy indicator to avoid overhead when invisible at start
if (this.getVisible() && !this._oBusyIndicator) {
var BusyIndicator = sap.ui.requireSync("sap/m/BusyIndicator");
this._oBusyIndicator = new BusyIndicator({
size: "1.7rem",
design: "auto"
});
this._oBusyIndicator.setParent(this);
}
};
PullToRefresh.prototype.onBeforeRendering = function(){
// Check Busy indicator at later point to avoid overhead when initially invisible
this._loadBI();
if (this._bTouchMode) {
jQuery(window).off("resize.sapMP2R", this.calculateTopTrigger);
var oParent = this.getParent();
this._oScroller = oParent && oParent.getScrollDelegate ? oParent.getScrollDelegate() : null;
if (this._oScroller) {
this._oScroller.setBounce(true);
this._oScroller.setPullDown(this.getVisible() ? this : null);
}
}
};
PullToRefresh.prototype.calculateTopTrigger = function(){
this._iTopTrigger = 1;
// find the scroll container that embeds the PullToRefresh control
if (this._oDomRef && this._oDomRef.parentNode && this._oDomRef.parentNode.parentNode &&
this._oDomRef.parentNode.parentNode.offsetHeight < this._oDomRef.offsetHeight * 1.5) {
// if there is no place to pull to show the image, pull only until the top line of text
this._iTopTrigger = this.getDomRef("T").offsetTop;
}
};
PullToRefresh.prototype.onAfterRendering = function(){
this._oDomRef = this.getDomRef();
if (this._bTouchMode) {
if (this._oScroller) {
this._oScroller.refresh();
}
if (this.getVisible() && this._oScroller && this._oScroller._bIScroll) {
// recalculate top pull offset by resize
jQuery(window).on("resize.sapMP2R", jQuery.proxy(this.calculateTopTrigger, this));
this.calculateTopTrigger();
}
}
};
PullToRefresh.prototype.exit = function(){
if (this._bTouchMode && this._oScroller && this._oScroller._bIScroll) {
jQuery(window).off("resize.sapMP2R", this.calculateTopTrigger);
}
if (this._oScroller) {
this._oScroller.setPullDown(null);
this._oScroller = null;
}
if (this._oCustomImage) {
this._oCustomImage.destroy();
this._oCustomImage = null;
}
if (this._oBusyIndicator) {
this._oBusyIndicator.destroy();
this._oBusyIndicator = null;
}
};
// ScrollEnablement callback functions
PullToRefresh.prototype.doScrollMove = function(){
//callback for iScroll
if (!this._oScroller) { return; }
var domRef = this._oDomRef;
var _scroller = this._oScroller._scroller;
if (_scroller.y > -this._iTopTrigger && this._iState < 1 ) {
this.setState(1);
_scroller.minScrollY = 0;
} else if (_scroller.y < -this._iTopTrigger && this._iState == 1) {
this.setState(0);
_scroller.minScrollY = -domRef.offsetHeight;
}
};
PullToRefresh.prototype.doPull = function(posY){
// callback native scrolling, pull
if (this._bTouchMode && this._iState < 2) {
// switch pull down state: rotate its arrow
this.setState(posY >= -1 ? 1 : 0);
}
};
PullToRefresh.prototype.doRefresh = function(){
this.setState(0);
};
PullToRefresh.prototype.doScrollEnd = function(){
if (this._iState == 1) { // if released when ready - load
this.setState(2);
this.fireRefresh();
}
};
/*
* Set display state: 0 - pull to refresh, 1 - release to refresh, 2 - loading
* @private
*/
PullToRefresh.prototype.setState = function(iState){
if (this._iState == iState) {
return;
}
this._iState = iState;
if (!this._oDomRef) {
return;
}
var $this = this.$();
var $text = $this.find(".sapMPullDownText");
var oResourceBundle = this._getRB();
switch (iState) {
case 0:
$this.toggleClass("sapMFlip", false).toggleClass("sapMLoading", false);
$text.html(oResourceBundle.getText(this._bTouchMode ? "PULL2REFRESH_PULLDOWN" : "PULL2REFRESH_REFRESH"));
$this.removeAttr("aria-live");
$this.find(".sapMPullDownInfo").html(encodeXML(this.getDescription()));
break;
case 1:
$this.toggleClass("sapMFlip", true);
$text.html(oResourceBundle.getText("PULL2REFRESH_RELEASE"));
$this.removeAttr("aria-live");
break;
case 2:
$this.toggleClass("sapMFlip", false).toggleClass("sapMLoading", true);
this._oBusyIndicator.setVisible(true);
$text.html(oResourceBundle.getText("PULL2REFRESH_LOADING"));
$this.attr("aria-live", "assertive");
$this.find(".sapMPullDownInfo").html(this._bTouchMode ? oResourceBundle.getText("PULL2REFRESH_LOADING_LONG") : "");
break;
}
};
/*
* Override re-rendering for description
* @private
*/
PullToRefresh.prototype.setDescription = function(sDescription){
if (this._oDomRef) {
this.$().find(".sapMPullDownInfo").html(encodeXML(sDescription));
}
return this.setProperty("description", sDescription, true);
};
/*
* Return a private custom icon image control for internal rendering
* @private
*/
PullToRefresh.prototype.getCustomIconImage = function(){
var mProperties = {
src : this.getCustomIcon(),
densityAware : this.getIconDensityAware(),
useIconTooltip : false
};
var aCssClasses = ['sapMPullDownCIImg'];
this._oCustomImage = ImageHelper.getImageControl(null, this._oCustomImage, this, mProperties, aCssClasses);
return this._oCustomImage;
};
// mouse version (non-touch)
PullToRefresh.prototype.onclick = function() {
if (!this._bTouchMode) {
this.setState(2);
this.fireRefresh();
}
};
/**
* Handle the key down event for F5, if focused.
*
* @param {jQuery.Event} event - the keyboard event.
* @private
*/
PullToRefresh.prototype.onkeydown = function(event) {
if ( event.which == KeyCodes.F5) {
this.onclick();
// do not refresh browser window
event.stopPropagation();
event.preventDefault();
}
};
/**
* Handle the enter key event
*
* @param {jQuery.Event} oEvent The ENTER keyboard event object
* @private
*/
PullToRefresh.prototype.onsapenter = function(oEvent) {
if (this._iState < 1) {
this.setState(2);
this.fireRefresh();
}
};
/**
* Handle the space key event
*
* @param {jQuery.Event} oEvent The SPACE keyboard event object
* @private
*/
PullToRefresh.prototype.onsapspace = function(oEvent) {
oEvent.preventDefault();
if (this._iState < 1) {
this.setState(2);
this.fireRefresh();
}
};
// API implementation
/**
* Hides the control and resets it to the normal state. In non-touch environments the control is not hidden.
*
* @public
* @ui5-metamodel This method also will be described in the UI5 (legacy) designtime metamodel
*/
PullToRefresh.prototype.hide = function(){
this.setState(0);
if (this._oScroller) {
this._oScroller.refresh();
}
};
PullToRefresh.prototype.setVisible = function(bVisible){
if (this.getVisible() == bVisible) {
return this;
}
if (this._oDomRef && this._oScroller && this._oScroller._oControl) {
this._oScroller._oControl.invalidate();
}
return this.setProperty("visible", bVisible);
};
PullToRefresh.prototype._getRB = function(){
return sap.ui.getCore().getLibraryResourceBundle("sap.m");
};
return PullToRefresh;
});