2018-01-02 00:00:45 +00:00
/ *
2018-01-17 16:39:08 +00:00
Floorplan Fully Kiosk for Home Assistant
Version : 1.0 . 7.50
By Petar Kozul
https : //github.com/pkozul/ha-floorplan
2018-01-02 00:00:45 +00:00
* /
'use strict' ;
( function ( ) {
if ( typeof window . FullyKiosk === 'function' ) {
return ;
}
class FullyKiosk {
constructor ( floorplan ) {
2018-01-17 16:39:08 +00:00
this . version = '1.0.7.50' ;
2018-01-02 00:00:45 +00:00
this . floorplan = floorplan ;
this . authToken = ( window . localStorage && window . localStorage . authToken ) ? window . localStorage . authToken : '' ;
this . fullyInfo = { } ;
this . fullyState = { } ;
2018-01-17 16:39:08 +00:00
this . beacons = { } ;
this . throttledFunctions = { } ;
2018-01-02 00:00:45 +00:00
}
/***************************************************************************************************************************/
/ * I n i t i a l i z a t i o n
/***************************************************************************************************************************/
init ( ) {
this . logInfo ( 'VERSION' , ` Fully Kiosk v ${ this . version } ` ) ;
2018-01-17 16:39:08 +00:00
/ *
let uuid = 'a445425b-c718-461c-a876-aa647abd99d4' ;
let deviceId = uuid . replace ( /[-_]/g , '' ) . toUpperCase ( ) ;
let payload = { room : 'entry hall' , id : uuid , distance : 123.45 } ;
this . PostToHomeAssistant ( ` /api/room_presence/ ${ deviceId } ` , payload ) ;
* /
2018-01-02 00:00:45 +00:00
if ( typeof fully === "undefined" ) {
this . logInfo ( 'FULLY_KIOSK' , ` Fully Kiosk is not running or not enabled. You can enable it via Settings > Other Settings > Enable Website Integration (PLUS). ` ) ;
return ;
}
let macAddress = fully . getMacAddress ( ) . toLowerCase ( ) ;
let device = this . floorplan . config && this . floorplan . config . fully _kiosk &&
this . floorplan . config . fully _kiosk . find ( x => x . address . toLowerCase ( ) == macAddress ) ;
if ( ! device ) {
return ;
}
if ( ! navigator . geolocation ) {
this . logInfo ( 'FULLY_KIOSK' , "Geolocation is not supported or not enabled. You can enable it via Settings > Web Content Settings > Enable Geolocation Access (PLUS) and on the device via Google Settings > Location > Fully Kiosk Browser." ) ;
}
this . fullyInfo = this . getFullyInfo ( device ) ;
this . updateFullyState ( ) ;
this . updateCurrentPosition ( ) ;
this . initAudio ( ) ;
this . addAudioEventHandlers ( ) ;
this . addFullyEventHandlers ( ) ;
this . subscribeHomeAssistantEvents ( ) ;
this . sendMotionState ( ) ;
this . sendPluggedState ( ) ;
this . sendScreensaverState ( ) ;
this . sendMediaPlayerState ( ) ;
}
initAudio ( ) {
this . audio = new Audio ( ) ;
this . isAudioPlaying = false ;
}
getFullyInfo ( device ) {
return {
motionBinarySensorEntityId : device . motion _sensor ,
pluggedBinarySensorEntityId : device . plugged _sensor ,
screensaverLightEntityId : device . screensaver _light ,
mediaPlayerEntityId : device . media _player ,
2018-01-17 16:39:08 +00:00
locationName : device . presence _detection ? device . presence _detection . location _name : undefined ,
2018-01-02 00:00:45 +00:00
startUrl : fully . getStartUrl ( ) ,
currentLocale : fully . getCurrentLocale ( ) ,
ipAddressv4 : fully . getIp4Address ( ) ,
ipAddressv6 : fully . getIp6Address ( ) ,
macAddress : fully . getMacAddress ( ) ,
wifiSSID : fully . getWifiSsid ( ) ,
serialNumber : fully . getSerialNumber ( ) ,
deviceId : fully . getDeviceId ( ) ,
isMotionDetected : false ,
isScreensaverOn : false ,
supportsGeolocation : ( navigator . geolocation != undefined ) ,
} ;
}
updateFullyState ( ) {
this . fullyState . batteryLevel = fully . getBatteryLevel ( ) ;
this . fullyState . screenBrightness = fully . getScreenBrightness ( ) ;
this . fullyState . isScreenOn = fully . getScreenOn ( ) ;
this . fullyState . isPluggedIn = fully . isPlugged ( ) ;
}
/***************************************************************************************************************************/
/ * S e t u p e v e n t h a n d l e r s
/***************************************************************************************************************************/
addAudioEventHandlers ( ) {
this . audio . addEventListener ( 'play' , this . onAudioPlay . bind ( this ) ) ;
this . audio . addEventListener ( 'playing' , this . onAudioPlaying . bind ( this ) ) ;
this . audio . addEventListener ( 'pause' , this . onAudioPause . bind ( this ) ) ;
this . audio . addEventListener ( 'ended' , this . onAudioEnded . bind ( this ) ) ;
this . audio . addEventListener ( 'volumechange' , this . onAudioVolumeChange . bind ( this ) ) ;
}
addFullyEventHandlers ( ) {
window [ 'onFullyEvent' ] = ( e ) => { window . dispatchEvent ( new Event ( e ) ) ; }
window [ 'onFullyIBeaconEvent' ] = ( e , uuid , major , minor , distance ) => {
let event = new CustomEvent ( e , {
detail : { uuid : uuid , major : major , minor : minor , distance : distance , timestamp : new Date ( ) }
} ) ;
window . dispatchEvent ( event ) ;
}
window . addEventListener ( 'fully.screenOn' , this . onScreenOn . bind ( this ) ) ;
window . addEventListener ( 'fully.screenOff' , this . onScreenOff . bind ( this ) ) ;
window . addEventListener ( 'fully.networkDisconnect' , this . onNetworkDisconnect . bind ( this ) ) ;
window . addEventListener ( 'fully.networkReconnect' , this . onNetworkReconnect . bind ( this ) ) ;
window . addEventListener ( 'fully.internetDisconnect' , this . onInternetDisconnect . bind ( this ) ) ;
window . addEventListener ( 'fully.internetReconnect' , this . onInternetReconnect . bind ( this ) ) ;
window . addEventListener ( 'fully.unplugged' , this . onUnplugged . bind ( this ) ) ;
window . addEventListener ( 'fully.pluggedAC' , this . onPluggedAC . bind ( this ) ) ;
window . addEventListener ( 'fully.pluggedUSB' , this . onPluggedUSB . bind ( this ) ) ;
window . addEventListener ( 'fully.onScreensaverStart' , this . onScreensaverStart . bind ( this ) ) ;
window . addEventListener ( 'fully.onScreensaverStop' , this . onScreensaverStop . bind ( this ) ) ;
window . addEventListener ( 'fully.onBatteryLevelChanged' , this . onBatteryLevelChanged . bind ( this ) ) ;
window . addEventListener ( 'fully.onMotion' , this . onMotion . bind ( this ) ) ;
2018-01-17 16:39:08 +00:00
if ( this . fullyInfo . supportsGeolocation ) {
window . addEventListener ( 'fully.onMovement' , this . onMovement . bind ( this ) ) ;
}
if ( this . fullyInfo . locationName ) {
this . logInfo ( 'KIOSK' , 'Listening for beacon messages' ) ;
window . addEventListener ( 'fully.onIBeacon' , this . onIBeacon . bind ( this ) ) ;
}
2018-01-02 00:00:45 +00:00
fully . bind ( 'screenOn' , 'onFullyEvent("fully.screenOn");' )
fully . bind ( 'screenOff' , 'onFullyEvent("fully.screenOff");' )
fully . bind ( 'networkDisconnect' , 'onFullyEvent("fully.networkDisconnect");' )
fully . bind ( 'networkReconnect' , 'onFullyEvent("fully.networkReconnect");' )
fully . bind ( 'internetDisconnect' , 'onFullyEvent("fully.internetDisconnect");' )
fully . bind ( 'internetReconnect' , 'onFullyEvent("fully.internetReconnect");' )
fully . bind ( 'unplugged' , 'onFullyEvent("fully.unplugged");' )
fully . bind ( 'pluggedAC' , 'onFullyEvent("fully.pluggedAC");' )
fully . bind ( 'pluggedUSB' , 'onFullyEvent("fully.pluggedUSB");' )
fully . bind ( 'onScreensaverStart' , 'onFullyEvent("fully.onScreensaverStart");' )
fully . bind ( 'onScreensaverStop' , 'onFullyEvent("fully.onScreensaverStop");' )
fully . bind ( 'onBatteryLevelChanged' , 'onFullyEvent("fully.onBatteryLevelChanged");' )
fully . bind ( 'onMotion' , 'onFullyEvent("fully.onMotion");' ) // Max. one per second
fully . bind ( 'onMovement' , 'onFullyEvent("fully.onMovement");' )
fully . bind ( 'onIBeacon' , 'onFullyIBeaconEvent("fully.onIBeacon", "$id1", "$id2", "$id3", $distance);' )
}
/***************************************************************************************************************************/
/ * F u l l y K i o s k e v e n t s
/***************************************************************************************************************************/
onScreenOn ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Screen turned on' ) ;
}
onScreenOff ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Screen turned off' ) ;
}
onNetworkDisconnect ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Network disconnected' ) ;
}
onNetworkReconnect ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Network reconnected' ) ;
}
onInternetDisconnect ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Internet disconnected' ) ;
}
onInternetReconnect ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Internet reconnected' ) ;
}
onUnplugged ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Unplugged AC' ) ;
this . fullyState . isPluggedIn = false ;
this . sendPluggedState ( ) ;
}
onPluggedAC ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Plugged AC' ) ;
this . fullyState . isPluggedIn = true ;
this . sendPluggedState ( ) ;
}
onPluggedUSB ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Unplugged USB' ) ;
this . logDebug ( 'FULLY_KIOSK' , 'Device plugged into USB' ) ;
}
onScreensaverStart ( ) {
this . fullyState . isScreensaverOn = true ;
this . logDebug ( 'FULLY_KIOSK' , 'Screensaver started' ) ;
this . sendScreensaverState ( ) ;
}
onScreensaverStop ( ) {
this . fullyState . isScreensaverOn = false ;
this . logDebug ( 'FULLY_KIOSK' , 'Screensaver stopped' ) ;
this . sendScreensaverState ( ) ;
}
onBatteryLevelChanged ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Battery level changed' ) ;
}
onMotion ( ) {
this . fullyState . isMotionDetected = true ;
this . logDebug ( 'FULLY_KIOSK' , 'Motion detected' ) ;
this . sendMotionState ( ) ;
}
2018-01-17 16:39:08 +00:00
onMovement ( e ) {
let functionId = 'onMovement' ;
let throttledFunc = this . throttledFunctions [ functionId ] ;
if ( ! throttledFunc ) {
throttledFunc = this . throttle ( this . onMovementThrottled . bind ( this ) , 10000 ) ;
this . throttledFunctions [ functionId ] = throttledFunc ;
}
return throttledFunc ( e ) ;
}
onMovementThrottled ( ) {
this . logDebug ( 'FULLY_KIOSK' , 'Movement detected (throttled)' ) ;
2018-01-02 00:00:45 +00:00
if ( this . fullyInfo . supportsGeolocation ) {
this . updateCurrentPosition ( )
. then ( ( ) => {
this . sendMotionState ( ) ;
} ) ;
}
}
onIBeacon ( e ) {
2018-01-17 16:39:08 +00:00
let functionId = e . detail . uuid ;
let throttledFunc = this . throttledFunctions [ functionId ] ;
if ( ! throttledFunc ) {
throttledFunc = this . throttle ( this . onIBeaconThrottled . bind ( this ) , 10000 ) ;
this . throttledFunctions [ functionId ] = throttledFunc ;
}
return throttledFunc ( e ) ;
}
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
onIBeaconThrottled ( e ) {
let beacon = e . detail ;
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
this . logDebug ( 'FULLY_KIOSK' , ` Received (throttled) beacon message ( ${ JSON . stringify ( beacon ) } ) ` ) ;
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
let beaconId = beacon . uuid ;
beaconId += ( beacon . major ? ` _ ${ beacon . major } ` : '' ) ;
beaconId += ( beacon . minor ? ` _ ${ beacon . minor } ` : '' ) ;
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
this . beacons [ beaconId ] = beacon ;
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
this . sendBeaconState ( beacon ) ;
2018-01-02 00:00:45 +00:00
}
/***************************************************************************************************************************/
/ * H T M L 5 A u d i o
/***************************************************************************************************************************/
onAudioPlay ( ) {
this . isAudioPlaying = true ;
this . sendMediaPlayerState ( ) ;
}
onAudioPlaying ( ) {
this . isAudioPlaying = true ;
this . sendMediaPlayerState ( ) ;
}
onAudioPause ( ) {
this . isAudioPlaying = false ;
this . sendMediaPlayerState ( ) ;
}
onAudioEnded ( ) {
this . isAudioPlaying = false ;
this . sendMediaPlayerState ( ) ;
}
onAudioVolumeChange ( ) {
this . sendMediaPlayerState ( ) ;
}
/***************************************************************************************************************************/
/ * S e n d s t a t e t o H o m e A s s i s t a n t
/***************************************************************************************************************************/
sendMotionState ( ) {
if ( ! this . fullyInfo . motionBinarySensorEntityId ) {
return ;
}
clearTimeout ( this . sendMotionStateTimer ) ;
let timeout = this . fullyState . isMotionDetected ? 5000 : 10000 ;
let state = this . fullyState . isMotionDetected ? "on" : "off" ;
this . PostToHomeAssistant ( ` /api/states/ ${ this . fullyInfo . motionBinarySensorEntityId } ` , this . newPayload ( state ) , ( ) => {
this . sendMotionStateTimer = setTimeout ( ( ) => {
this . fullyState . isMotionDetected = false ;
this . sendMotionState ( ) ;
// Send other states as well
this . sendPluggedState ( ) ;
this . sendScreensaverState ( ) ;
this . sendMediaPlayerState ( ) ;
} , timeout ) ;
} ) ;
}
sendPluggedState ( ) {
if ( ! this . fullyInfo . pluggedBinarySensorEntityId ) {
return ;
}
let state = this . fullyState . isPluggedIn ? "on" : "off" ;
this . PostToHomeAssistant ( ` /api/states/ ${ this . fullyInfo . pluggedBinarySensorEntityId } ` , this . newPayload ( state ) ) ;
}
sendScreensaverState ( ) {
if ( ! this . fullyInfo . screensaverLightEntityId ) {
return ;
}
let state = this . fullyState . isScreensaverOn ? "on" : "off" ;
this . PostToHomeAssistant ( ` /api/states/ ${ this . fullyInfo . screensaverLightEntityId } ` , this . newPayload ( state ) ) ;
}
sendMediaPlayerState ( ) {
if ( ! this . fullyInfo . mediaPlayerEntityId ) {
return ;
}
let state = this . isAudioPlaying ? "playing" : "idle" ;
this . PostToHomeAssistant ( ` /api/fully_kiosk/media_player/ ${ this . fullyInfo . mediaPlayerEntityId } ` , this . newPayload ( state ) ) ;
}
2018-01-17 16:39:08 +00:00
sendBeaconState ( beacon ) {
2018-01-02 00:00:45 +00:00
if ( ! this . fullyInfo . motionBinarySensorEntityId ) {
return ;
}
2018-01-17 16:39:08 +00:00
/ *
let payload = {
name : this . fullyInfo . locationName ,
address : this . fullyInfo . macAddress ,
device : beacon . uuid ,
beaconUUID : beacon . uuid ,
latitude : this . position ? this . position . coords . latitude : undefined ,
longitude : this . position ? this . position . coords . longitude : undefined ,
entry : 1 ,
}
this . PostToHomeAssistant ( ` /api/geofency ` , payload , undefined , false ) ;
* /
/ *
2018-01-02 00:00:45 +00:00
let payload = {
mac : undefined ,
2018-01-17 16:39:08 +00:00
dev _id : beacon . uuid . replace ( /-/g , '_' ) ,
2018-01-02 00:00:45 +00:00
host _name : undefined ,
location _name : this . fullyInfo . macAddress ,
gps : this . position ? [ this . position . coords . latitude , this . position . coords . longitude ] : undefined ,
gps _accuracy : undefined ,
battery : undefined ,
2018-01-17 16:39:08 +00:00
uuid : beacon . uuid ,
major : beacon . major ,
minor : beacon . minor ,
2018-01-02 00:00:45 +00:00
} ;
2018-01-17 16:39:08 +00:00
this . PostToHomeAssistant ( ` /api/services/device_tracker/see ` , payload ) ;
* /
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
/ *
2018-01-02 00:00:45 +00:00
let fullyId = this . fullyInfo . macAddress . replace ( /[:-]/g , "_" ) ;
2018-01-17 16:39:08 +00:00
payload = { topic : ` room_presence/ ${ fullyId } ` , payload : ` { \" id \" : \" ${ beacon . uuid } \" , \" distance \" : ${ beacon . distance } } ` } ;
2018-01-02 00:00:45 +00:00
this . floorplan . hass . callService ( 'mqtt' , 'publish' , payload ) ;
2018-01-17 16:39:08 +00:00
* /
let deviceId = beacon . uuid . replace ( /[-_]/g , '' ) . toUpperCase ( ) ;
let payload = {
room : this . fullyInfo . locationName ,
uuid : beacon . uuid ,
major : beacon . major ,
minor : beacon . minor ,
distance : beacon . distance ,
latitude : this . position ? this . position . coords . latitude : undefined ,
longitude : this . position ? this . position . coords . longitude : undefined ,
} ;
this . PostToHomeAssistant ( ` /api/room_presence/ ${ deviceId } ` , payload ) ;
2018-01-02 00:00:45 +00:00
}
newPayload ( state ) {
this . updateFullyState ( ) ;
let payload = {
state : state ,
brightness : this . fullyState . screenBrightness ,
attributes : {
volume _level : this . audio . volume ,
media _content _id : this . audio . src ,
address : this . fullyInfo . macAddress ,
mac _address : this . fullyInfo . macAddress ,
serial _number : this . fullyInfo . serialNumber ,
device _id : this . fullyInfo . deviceId ,
battery _level : this . fullyState . batteryLevel ,
screen _brightness : this . fullyState . screenBrightness ,
_isScreenOn : this . fullyState . isScreenOn ,
_isPluggedIn : this . fullyState . isPluggedIn ,
_isMotionDetected : this . fullyState . isMotionDetected ,
_isScreensaverOn : this . fullyState . isScreensaverOn ,
_latitude : this . position && this . position . coords . latitude ,
_longitude : this . position && this . position . coords . longitude ,
2018-01-17 16:39:08 +00:00
_beacons : JSON . stringify ( Object . keys ( this . beacons ) . map ( beaconId => this . beacons [ beaconId ] ) ) ,
2018-01-02 00:00:45 +00:00
}
} ;
return payload ;
}
/***************************************************************************************************************************/
/ * G e o l o c a t i o n
/***************************************************************************************************************************/
setScreenBrightness ( brightness ) {
fully . setScreenBrightness ( brightness ) ;
}
startScreensaver ( ) {
this . logInfo ( 'FULLY_KIOSK' , ` Starting screensaver ` ) ;
fully . startScreensaver ( ) ;
}
stopScreensaver ( ) {
this . logInfo ( 'FULLY_KIOSK' , ` Stopping screensaver ` ) ;
fully . stopScreensaver ( ) ;
}
playTextToSpeech ( text ) {
this . logInfo ( 'FULLY_KIOSK' , ` Playing text-to-speech: ${ text } ` ) ;
fully . textToSpeech ( text ) ;
}
playMedia ( mediaUrl ) {
this . audio . src = mediaUrl ;
this . logInfo ( 'FULLY_KIOSK' , ` Playing media: ${ this . audio . src } ` ) ;
this . audio . play ( ) ;
}
pauseMedia ( ) {
this . logInfo ( 'FULLY_KIOSK' , ` Pausing media: ${ this . audio . src } ` ) ;
this . audio . pause ( ) ;
}
setVolume ( level ) {
this . audio . volume = level ;
}
PostToHomeAssistant ( url , payload , onSuccess ) {
let options = {
type : 'POST' ,
url : url ,
headers : { "X-HA-Access" : this . authToken } ,
data : JSON . stringify ( payload ) ,
success : function ( result ) {
this . logDebug ( 'FULLY_KIOSK' , ` Posted state: ${ url } ${ JSON . stringify ( payload ) } ` ) ;
if ( onSuccess ) {
onSuccess ( ) ;
}
} . bind ( this ) ,
error : function ( error ) {
this . handleError ( new URIError ( ` Error posting state: ${ url } ` ) ) ;
} . bind ( this )
} ;
jQuery . ajax ( options ) ;
}
subscribeHomeAssistantEvents ( ) {
/ *
this . floorplan . hass . connection . subscribeEvents ( ( event ) => {
} ,
'state_changed' ) ;
* /
this . floorplan . hass . connection . subscribeEvents ( ( event ) => {
if ( this . fullyInfo . screensaverLightEntityId && ( event . data . domain === 'light' ) ) {
if ( event . data . service _data . entity _id . toString ( ) === this . fullyInfo . screensaverLightEntityId ) {
switch ( event . data . service ) {
case 'turn_on' :
this . startScreensaver ( ) ;
break ;
case 'turn_off' :
this . stopScreensaver ( ) ;
break ;
}
let brightness = event . data . service _data . brightness ;
if ( brightness ) {
this . setScreenBrightness ( brightness ) ;
}
}
}
else if ( this . fullyInfo . mediaPlayerEntityId && ( event . data . domain === 'media_player' ) ) {
let targetEntityId ;
let serviceEntityId = event . data . service _data . entity _id ;
if ( Array . isArray ( serviceEntityId ) ) {
targetEntityId = serviceEntityId . find ( entityId => ( entityId === this . fullyInfo . mediaPlayerEntityId ) ) ;
}
else {
targetEntityId = ( serviceEntityId === this . fullyInfo . mediaPlayerEntityId ) ? serviceEntityId : undefined ;
}
if ( targetEntityId ) {
switch ( event . data . service ) {
case 'play_media' :
this . playMedia ( event . data . service _data . media _content _id ) ;
break ;
case 'media_play' :
this . playMedia ( ) ;
break ;
case 'media_pause' :
case 'media_stop' :
this . pauseMedia ( ) ;
break ;
case 'volume_set' :
this . setVolume ( event . data . service _data . volume _level ) ;
break ;
default :
this . logWarning ( 'FULLY_KIOSK' , ` Service not supported: ${ event . data . service } ` ) ;
break ;
}
}
}
/ *
if ( ( event . data . domain === 'tts' ) && ( event . data . service === 'google_say' ) ) {
if ( this . fullyInfo . mediaPlayerEntityId === event . data . service _data . entity _id ) {
this . logDebug ( 'FULLY_KIOSK' , 'Playing TTS using Fully Kiosk' ) ;
this . playTextToSpeech ( event . data . service _data . message ) ;
}
}
* /
} ,
'call_service' ) ;
}
/***************************************************************************************************************************/
/ * G e o l o c a t i o n
/***************************************************************************************************************************/
updateCurrentPosition ( ) {
if ( ! navigator . geolocation ) {
return Promise . resolve ( undefined ) ;
}
return new Promise ( ( resolve , reject ) => {
navigator . geolocation . getCurrentPosition (
( position ) => {
this . logDebug ( 'FULLY_KIOSK' , ` Current location: latitude: ${ position . coords . latitude } , longitude: ${ position . coords . longitude } ` ) ;
this . position = position ;
resolve ( position ) ;
} ,
( err ) => {
this . logError ( 'FULLY_KIOSK' , 'Unable to retrieve location' ) ;
reject ( err ) ;
} ) ;
} )
}
/***************************************************************************************************************************/
/* Errors / logging
/***************************************************************************************************************************/
handleError ( message ) {
this . floorplan . handleError ( message ) ;
}
logError ( area , message ) {
this . floorplan . logError ( message ) ;
}
logWarning ( area , message ) {
this . floorplan . logWarning ( area , message ) ;
}
logInfo ( area , message ) {
this . floorplan . logInfo ( area , message ) ;
}
logDebug ( area , message ) {
this . floorplan . logDebug ( area , message ) ;
}
/***************************************************************************************************************************/
/ * U t i l i t y f u n c t i o n s
/***************************************************************************************************************************/
2018-01-17 16:39:08 +00:00
debounce ( func , wait , options ) {
let lastArgs ,
lastThis ,
maxWait ,
result ,
timerId ,
lastCallTime
let lastInvokeTime = 0
let leading = false
let maxing = false
let trailing = true
if ( typeof func != 'function' ) {
throw new TypeError ( 'Expected a function' )
}
wait = + wait || 0
if ( options ) {
leading = ! ! options . leading
maxing = 'maxWait' in options
maxWait = maxing ? Math . max ( + options . maxWait || 0 , wait ) : maxWait
trailing = 'trailing' in options ? ! ! options . trailing : trailing
}
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
function invokeFunc ( time ) {
const args = lastArgs
const thisArg = lastThis
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
lastArgs = lastThis = undefined
lastInvokeTime = time
result = func . apply ( thisArg , args )
return result
}
2018-01-02 00:00:45 +00:00
2018-01-17 16:39:08 +00:00
function leadingEdge ( time ) {
// Reset any `maxWait` timer.
lastInvokeTime = time
// Start the timer for the trailing edge.
timerId = setTimeout ( timerExpired , wait )
// Invoke the leading edge.
return leading ? invokeFunc ( time ) : result
}
function remainingWait ( time ) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
const timeWaiting = wait - timeSinceLastCall
return maxing
? Math . min ( timeWaiting , maxWait - timeSinceLastInvoke )
: timeWaiting
}
function shouldInvoke ( time ) {
const timeSinceLastCall = time - lastCallTime
const timeSinceLastInvoke = time - lastInvokeTime
// Either this is the first call, activity has stopped and we're at the
// trailing edge, the system time has gone backwards and we're treating
// it as the trailing edge, or we've hit the `maxWait` limit.
return ( lastCallTime === undefined || ( timeSinceLastCall >= wait ) ||
( timeSinceLastCall < 0 ) || ( maxing && timeSinceLastInvoke >= maxWait ) )
}
function timerExpired ( ) {
const time = Date . now ( )
if ( shouldInvoke ( time ) ) {
return trailingEdge ( time )
}
// Restart the timer.
timerId = setTimeout ( timerExpired , remainingWait ( time ) )
}
function trailingEdge ( time ) {
timerId = undefined
// Only invoke if we have `lastArgs` which means `func` has been
// debounced at least once.
if ( trailing && lastArgs ) {
return invokeFunc ( time )
}
lastArgs = lastThis = undefined
return result
}
function cancel ( ) {
if ( timerId !== undefined ) {
clearTimeout ( timerId )
}
lastInvokeTime = 0
lastArgs = lastCallTime = lastThis = timerId = undefined
}
function flush ( ) {
return timerId === undefined ? result : trailingEdge ( Date . now ( ) )
}
function pending ( ) {
return timerId !== undefined
}
function debounced ( ... args ) {
const time = Date . now ( )
const isInvoking = shouldInvoke ( time )
lastArgs = args
lastThis = this
lastCallTime = time
if ( isInvoking ) {
if ( timerId === undefined ) {
return leadingEdge ( lastCallTime )
}
if ( maxing ) {
// Handle invocations in a tight loop.
timerId = setTimeout ( timerExpired , wait )
return invokeFunc ( lastCallTime )
}
}
if ( timerId === undefined ) {
timerId = setTimeout ( timerExpired , wait )
}
return result
}
debounced . cancel = cancel
debounced . flush = flush
debounced . pending = pending
return debounced
}
throttle ( func , wait , options ) {
let leading = true
let trailing = true
if ( typeof func != 'function' ) {
throw new TypeError ( 'Expected a function' ) ;
}
if ( options ) {
leading = 'leading' in options ? ! ! options . leading : leading
trailing = 'trailing' in options ? ! ! options . trailing : trailing
}
return this . debounce ( func , wait , {
'leading' : leading ,
'maxWait' : wait ,
'trailing' : trailing
} )
2018-01-02 00:00:45 +00:00
}
}
window . FullyKiosk = FullyKiosk ;
} ) . call ( this ) ;