mirror of
https://github.com/CCOSTAN/Home-AssistantConfig.git
synced 2025-08-16 18:44:58 +00:00
Massive Migration! #292
This commit is contained in:
591
www/custom_ui/floorplan/lib/fully-kiosk.js
Executable file
591
www/custom_ui/floorplan/lib/fully-kiosk.js
Executable file
@@ -0,0 +1,591 @@
|
||||
/*
|
||||
Floorplan Fully Kiosk for Home Assistant
|
||||
Version: 1.0.7.42
|
||||
By Petar Kozul
|
||||
https://github.com/pkozul/ha-floorplan
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
(function () {
|
||||
if (typeof window.FullyKiosk === 'function') {
|
||||
return;
|
||||
}
|
||||
|
||||
class FullyKiosk {
|
||||
constructor(floorplan) {
|
||||
this.version = '1.0.7.42';
|
||||
|
||||
this.floorplan = floorplan;
|
||||
this.authToken = (window.localStorage && window.localStorage.authToken) ? window.localStorage.authToken : '';
|
||||
|
||||
this.fullyInfo = {};
|
||||
this.fullyState = {};
|
||||
this.iBeacons = {};
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Initialization
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
init() {
|
||||
this.logInfo('VERSION', `Fully Kiosk v${this.version}`);
|
||||
|
||||
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,
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Set up event handlers
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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));
|
||||
window.addEventListener('fully.onMovement', this.onMovement.bind(this));
|
||||
window.addEventListener('fully.onIBeacon', this.onIBeacon.bind(this));
|
||||
|
||||
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);')
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Fully Kiosk events
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
onMovement() {
|
||||
this.logDebug('FULLY_KIOSK', 'Movement detected');
|
||||
|
||||
if (this.fullyInfo.supportsGeolocation) {
|
||||
this.updateCurrentPosition()
|
||||
.then(() => {
|
||||
this.sendMotionState();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
onIBeacon(e) {
|
||||
let iBeacon = e.detail;
|
||||
|
||||
this.logDebug('FULLY_KIOSK', `iBeacon (${JSON.stringify(iBeacon)})`);
|
||||
|
||||
let iBeaconId = iBeacon.uuid;
|
||||
iBeaconId += (iBeacon.major ? `_${iBeacon.major}` : '');
|
||||
iBeaconId += (iBeacon.minor ? `_${iBeacon.minor}` : '');
|
||||
|
||||
this.iBeacons[iBeaconId] = iBeacon;
|
||||
|
||||
this.sendMotionState();
|
||||
|
||||
this.sendIBeaconState(iBeacon);
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* HTML5 Audio
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Send state to Home Assistant
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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));
|
||||
}
|
||||
|
||||
sendIBeaconState(iBeacon) {
|
||||
if (!this.fullyInfo.motionBinarySensorEntityId) {
|
||||
return;
|
||||
}
|
||||
|
||||
let payload = {
|
||||
mac: undefined,
|
||||
dev_id: iBeacon.uuid.replace(/-/g, '_'),
|
||||
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,
|
||||
|
||||
uuid: iBeacon.uuid,
|
||||
major: iBeacon.major,
|
||||
minor: iBeacon.minor,
|
||||
};
|
||||
|
||||
//this.PostToHomeAssistant(`/api/services/device_tracker/see`, payload);
|
||||
|
||||
let fullyId = this.fullyInfo.macAddress.replace(/[:-]/g, "_");
|
||||
payload = { topic: `room_presence/${fullyId}`, payload: `{ \"id\": \"${iBeacon.uuid}\", \"distance\": ${iBeacon.distance} }` };
|
||||
this.floorplan.hass.callService('mqtt', 'publish', payload);
|
||||
}
|
||||
|
||||
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,
|
||||
_iBeacons: JSON.stringify(Object.keys(this.iBeacons).map(iBeaconId => this.iBeacons[iBeaconId])),
|
||||
}
|
||||
};
|
||||
|
||||
return payload;
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Geolocation
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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');
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Geolocation
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
/***************************************************************************************************************************/
|
||||
/* Utility functions
|
||||
/***************************************************************************************************************************/
|
||||
|
||||
debounce(func, wait, immediate) {
|
||||
let timeout;
|
||||
return function () {
|
||||
let context = this, args = arguments;
|
||||
|
||||
let later = function () {
|
||||
timeout = null;
|
||||
if (!immediate) func.apply(context, args);
|
||||
};
|
||||
|
||||
let callNow = immediate && !timeout;
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(later, wait);
|
||||
|
||||
if (callNow) func.apply(context, args);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
window.FullyKiosk = FullyKiosk;
|
||||
}).call(this);
|
Reference in New Issue
Block a user