"use strict";/* global Tablet, Script *///// libraries/appUi.js//// Created by Howard Stearns on 3/20/18.// Copyright 2018 High Fidelity, Inc.//// Distributed under the Apache License, Version 2.0.// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html// function AppUi(properties) { var request = Script.require('request').request; /* Example development order: 1. var AppUi = Script.require('appUi'); 2. Put appname-i.svg, appname-a.svg in graphicsDirectory (where non-default graphicsDirectory can be added in #3). 3. ui = new AppUi({buttonName: "APPNAME", home: "qml-or-html-path"}); (And if converting an existing app, define var tablet = ui.tablet, button = ui.button; as needed. remove button.clicked.[dis]connect and tablet.remove(button).) 4. Define onOpened and onClosed behavior in #3, if any. (And if converting an existing app, remove screenChanged.[dis]connect.) 5. Define onMessage and sendMessage in #3, if any. onMessage is wired/unwired on open/close. If you want a handler to be "always on", connect it yourself at script startup. (And if converting an existing app, remove code that [un]wires that message handling such as fromQml/sendToQml or webEventReceived/emitScriptEvent.) 6. (If converting an existing app, cleanup stuff that is no longer necessary, like references to button, tablet, and use isOpen, open(), and close() as needed.) 7. lint! */ var that = this; function defaultButton(name, suffix) { var base = that[name] || (that.buttonPrefix + suffix); that[name] = (base.indexOf('/') >= 0) ? base : (that.graphicsDirectory + base); // poor man's merge } // Defaults: that.tabletName = "com.highfidelity.interface.tablet.system"; that.inject = ""; that.graphicsDirectory = "icons/tablet-icons/"; // Where to look for button svgs. See below. that.additionalAppScreens = []; that.checkIsOpen = function checkIsOpen(type, tabletUrl) { // Are we active? Value used to set isOpen. // Actual url may have prefix or suffix. return that.currentVisibleUrl && ((that.home.indexOf(that.currentVisibleUrl) > -1) || (that.additionalAppScreens.indexOf(that.currentVisibleUrl) > -1)); }; that.setCurrentVisibleScreenMetadata = function setCurrentVisibleScreenMetadata(type, url) { that.currentVisibleScreenType = type; that.currentVisibleUrl = url; }; that.open = function open(optionalUrl, optionalInject) { // How to open the app. var url = optionalUrl || that.home; var inject = optionalInject || that.inject; if (that.isQMLUrl(url)) { that.tablet.loadQMLSource(url); } else { that.tablet.gotoWebScreen(url, inject); } }; // Opens some app on top of the current app (on desktop, opens new window) that.openNewAppOnTop = function openNewAppOnTop(url, optionalInject) { var inject = optionalInject || ""; if (that.isQMLUrl(url)) { that.tablet.loadQMLOnTop(url); } else { that.tablet.loadWebScreenOnTop(url, inject); } }; that.close = function close() { // How to close the app. that.currentVisibleUrl = ""; // for toolbar-mode: go back to home screen, this will close the window. that.tablet.gotoHomeScreen(); }; that.buttonActive = function buttonActive(isActive) { // How to make the button active (white). that.button.editProperties({isActive: isActive}); }; that.isQMLUrl = function isQMLUrl(url) { var type = /.qml$/.test(url) ? 'QML' : 'Web'; return type === 'QML'; }; that.isCurrentlyOnQMLScreen = function isCurrentlyOnQMLScreen() { return that.currentVisibleScreenType === 'QML'; }; // // START Notification Handling Defaults // that.messagesWaiting = function messagesWaiting(isWaiting) { // How to indicate a message light on button. // Note that waitingButton doesn't have to exist unless someone explicitly calls this with isWaiting true. that.button.editProperties({ icon: isWaiting ? that.normalMessagesButton : that.normalButton, activeIcon: isWaiting ? that.activeMessagesButton : that.activeButton }); }; that.notificationPollTimeout = [false]; that.notificationPollTimeoutMs = [60000]; that.notificationPollEndpoint = [false]; that.notificationPollStopPaginatingConditionMet = [false]; that.notificationDataProcessPage = function (data) { return data; }; that.notificationPollCallback = [that.ignore]; that.notificationPollCaresAboutSince = [false]; that.notificationInitialCallbackMade = [false]; that.notificationDisplayBanner = function (message) { if (!that.isOpen) { Window.displayAnnouncement(message); } }; // // END Notification Handling Defaults // // Handlers that.onScreenChanged = function onScreenChanged(type, url) { // Set isOpen, wireEventBridge, set buttonActive as appropriate, // and finally call onOpened() or onClosed() IFF defined. that.setCurrentVisibleScreenMetadata(type, url); if (that.checkIsOpen(type, url)) { that.wireEventBridge(true); if (!that.isOpen) { that.buttonActive(true); if (that.onOpened) { that.onOpened(); } that.isOpen = true; } } else { // A different screen is now visible, or the tablet has been closed. // Tablet visibility is controlled separately by `tabletShownChanged()` that.wireEventBridge(false); if (that.isOpen) { that.buttonActive(false); if (that.onClosed) { that.onClosed(); } that.isOpen = false; } } }; // Overwrite with the given properties: Object.keys(properties).forEach(function (key) { that[key] = properties[key]; }); // // START Notification Handling // var currentDataPageToRetrieve = []; var concatenatedServerResponse = []; for (var i = 0; i < that.notificationPollEndpoint.length; i++) { currentDataPageToRetrieve[i] = 1; concatenatedServerResponse[i] = new Array(); } var MAX_LOG_LENGTH_CHARACTERS = 300; function requestCallback(error, response, optionalParams) { var indexOfRequest = optionalParams.indexOfRequest; var urlOfRequest = optionalParams.urlOfRequest; if (error || (response.status !== 'success')) { print("Error: unable to complete request from URL. Error:", error || response.status); startNotificationTimer(indexOfRequest); return; } if (!that.notificationPollStopPaginatingConditionMet[indexOfRequest] || that.notificationPollStopPaginatingConditionMet[indexOfRequest](response)) { startNotificationTimer(indexOfRequest); var notificationData; if (concatenatedServerResponse[indexOfRequest].length) { notificationData = concatenatedServerResponse[indexOfRequest]; } else { notificationData = that.notificationDataProcessPage[indexOfRequest](response); } console.debug(that.buttonName, 'truncated notification data for processing:', JSON.stringify(notificationData).substring(0, MAX_LOG_LENGTH_CHARACTERS)); that.notificationPollCallback[indexOfRequest](notificationData); that.notificationInitialCallbackMade[indexOfRequest] = true; currentDataPageToRetrieve[indexOfRequest] = 1; concatenatedServerResponse[indexOfRequest] = new Array(); } else { concatenatedServerResponse[indexOfRequest] = concatenatedServerResponse[indexOfRequest].concat(that.notificationDataProcessPage[indexOfRequest](response)); currentDataPageToRetrieve[indexOfRequest]++; request({ json: true, uri: (urlOfRequest + "&page=" + currentDataPageToRetrieve[indexOfRequest]) }, requestCallback, optionalParams); } } var METAVERSE_BASE = Account.metaverseServerURL; var MS_IN_SEC = 1000; that.notificationPoll = function (i) { if (!that.notificationPollEndpoint[i]) { return; } // User is "appearing offline" or is not logged in if (GlobalServices.findableBy === "none" || Account.username === "Unknown user") { // The notification polling will restart when the user changes their availability // or when they log in, so it's not necessary to restart a timer here. console.debug(that.buttonName + " Notifications: User is appearing offline or not logged in. " + that.buttonName + " will poll for notifications when user logs in and has their availability " + "set to not appear offline."); return; } var url = METAVERSE_BASE + that.notificationPollEndpoint[i]; var settingsKey = "notifications/" + that.notificationPollEndpoint[i] + "/lastPoll"; var currentTimestamp = new Date().getTime(); var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp); if (that.notificationPollCaresAboutSince[i]) { url = url + "&since=" + lastPollTimestamp / MS_IN_SEC; } Settings.setValue(settingsKey, currentTimestamp); request({ json: true, uri: url }, requestCallback, { indexOfRequest: i, urlOfRequest: url }); }; // This won't do anything if there isn't a notification endpoint set for (i = 0; i < that.notificationPollEndpoint.length; i++) { that.notificationPoll(i); } function startNotificationTimer(indexOfRequest) { that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(function () { that.notificationPoll(indexOfRequest); }, that.notificationPollTimeoutMs[indexOfRequest]); } function restartNotificationPoll() { for (var j = 0; j < that.notificationPollEndpoint.length; j++) { that.notificationInitialCallbackMade[j] = false; if (that.notificationPollTimeout[j]) { Script.clearTimeout(that.notificationPollTimeout[j]); that.notificationPollTimeout[j] = false; } that.notificationPoll(j); } } // // END Notification Handling // // Properties: that.tablet = Tablet.getTablet(that.tabletName); // Must be after we gather properties. that.buttonPrefix = that.buttonPrefix || that.buttonName.toLowerCase() + "-"; defaultButton('normalButton', 'i.svg'); defaultButton('activeButton', 'a.svg'); defaultButton('normalMessagesButton', 'i-msg.svg'); defaultButton('activeMessagesButton', 'a-msg.svg'); var buttonOptions = { icon: that.normalButton, activeIcon: that.activeButton, text: that.buttonName }; // `TabletScriptingInterface` looks for the presence of a `sortOrder` key. // What it SHOULD do is look to see if the value inside that key is defined. // To get around the current code, we do this instead. if (that.sortOrder) { buttonOptions.sortOrder = that.sortOrder; } that.button = that.tablet.addButton(buttonOptions); that.ignore = function ignore() { }; that.hasOutboundEventBridge = false; that.hasInboundQmlEventBridge = false; that.hasInboundHtmlEventBridge = false; // HTML event bridge uses strings, not objects. Here we abstract over that. // (Although injected javascript still has to use JSON.stringify/JSON.parse.) that.sendToHtml = function (messageObject) { that.tablet.emitScriptEvent(JSON.stringify(messageObject)); }; that.fromHtml = function (messageString) { var parsedMessage = JSON.parse(messageString); parsedMessage.messageSrc = "HTML"; that.onMessage(parsedMessage); }; that.sendMessage = that.ignore; that.wireEventBridge = function wireEventBridge(on) { // Uniquivocally sets that.sendMessage(messageObject) to do the right thing. // Sets has*EventBridge and wires onMessage to the proper event bridge as appropriate, IFF onMessage defined. var isCurrentlyOnQMLScreen = that.isCurrentlyOnQMLScreen(); // Outbound (always, regardless of whether there is an inbound handler). if (on) { that.sendMessage = isCurrentlyOnQMLScreen ? that.tablet.sendToQml : that.sendToHtml; that.hasOutboundEventBridge = true; } else { that.sendMessage = that.ignore; that.hasOutboundEventBridge = false; } if (!that.onMessage) { return; } // Inbound if (on) { if (isCurrentlyOnQMLScreen && !that.hasInboundQmlEventBridge) { console.debug(that.buttonName, 'connecting', that.tablet.fromQml); that.tablet.fromQml.connect(that.onMessage); that.hasInboundQmlEventBridge = true; } else if (!isCurrentlyOnQMLScreen && !that.hasInboundHtmlEventBridge) { console.debug(that.buttonName, 'connecting', that.tablet.webEventReceived); that.tablet.webEventReceived.connect(that.fromHtml); that.hasInboundHtmlEventBridge = true; } } else { if (that.hasInboundQmlEventBridge) { console.debug(that.buttonName, 'disconnecting', that.tablet.fromQml); that.tablet.fromQml.disconnect(that.onMessage); that.hasInboundQmlEventBridge = false; } if (that.hasInboundHtmlEventBridge) { console.debug(that.buttonName, 'disconnecting', that.tablet.webEventReceived); that.tablet.webEventReceived.disconnect(that.fromHtml); that.hasInboundHtmlEventBridge = false; } } }; that.isOpen = false; // To facilitate incremental development, only wire onClicked to do something when "home" is defined in properties. that.onClicked = that.home ? function onClicked() { // Call open() or close(), and reset type based on current home property. if (that.isOpen) { that.close(); } else { that.open(); } } : that.ignore; that.onScriptEnding = function onScriptEnding() { // Close if necessary, clean up any remaining handlers, and remove the button. GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll); GlobalServices.findableByChanged.disconnect(restartNotificationPoll); that.tablet.screenChanged.disconnect(that.onScreenChanged); if (that.isOpen) { that.close(); that.onScreenChanged("", ""); } if (that.button) { if (that.onClicked) { that.button.clicked.disconnect(that.onClicked); } that.tablet.removeButton(that.button); } for (var i = 0; i < that.notificationPollTimeout.length; i++) { if (that.notificationPollTimeout[i]) { Script.clearInterval(that.notificationPollTimeout[i]); that.notificationPollTimeout[i] = false; } } }; // Set up the handlers. that.tablet.screenChanged.connect(that.onScreenChanged); that.button.clicked.connect(that.onClicked); Script.scriptEnding.connect(that.onScriptEnding); GlobalServices.findableByChanged.connect(restartNotificationPoll); GlobalServices.myUsernameChanged.connect(restartNotificationPoll); if (that.buttonName === Settings.getValue("startUpApp")) { Settings.setValue("startUpApp", ""); Script.setTimeout(function () { that.open(); }, 1000); }}module.exports = AppUi;
"use strict";
/* global Tablet, Script */
//
// libraries/appUi.js
//
// Created by Howard Stearns on 3/20/18.
// Copyright 2018 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
function AppUi(properties) {
var request = Script.require('request').request;
/* Example development order:
1. var AppUi = Script.require('appUi');
2. Put appname-i.svg, appname-a.svg in graphicsDirectory (where non-default graphicsDirectory can be added in #3).
3. ui = new AppUi({buttonName: "APPNAME", home: "qml-or-html-path"});
(And if converting an existing app,
define var tablet = ui.tablet, button = ui.button; as needed.
remove button.clicked.[dis]connect and tablet.remove(button).)
4. Define onOpened and onClosed behavior in #3, if any.
(And if converting an existing app, remove screenChanged.[dis]connect.)
5. Define onMessage and sendMessage in #3, if any. onMessage is wired/unwired on open/close. If you
want a handler to be "always on", connect it yourself at script startup.
(And if converting an existing app, remove code that [un]wires that message handling such as
fromQml/sendToQml or webEventReceived/emitScriptEvent.)
6. (If converting an existing app, cleanup stuff that is no longer necessary, like references to button, tablet,
and use isOpen, open(), and close() as needed.)
7. lint!
*/
var that = this;
function defaultButton(name, suffix) {
var base = that[name] || (that.buttonPrefix + suffix);
that[name] = (base.indexOf('/') >= 0) ? base : (that.graphicsDirectory + base); // poor man's merge
}
// Defaults:
that.tabletName = "com.highfidelity.interface.tablet.system";
that.inject = "";
that.graphicsDirectory = "icons/tablet-icons/"; // Where to look for button svgs. See below.
that.additionalAppScreens = [];
that.checkIsOpen = function checkIsOpen(type, tabletUrl) { // Are we active? Value used to set isOpen.
// Actual url may have prefix or suffix.
return that.currentVisibleUrl &&
((that.home.indexOf(that.currentVisibleUrl) > -1) ||
(that.additionalAppScreens.indexOf(that.currentVisibleUrl) > -1));
};
that.setCurrentVisibleScreenMetadata = function setCurrentVisibleScreenMetadata(type, url) {
that.currentVisibleScreenType = type;
that.currentVisibleUrl = url;
};
that.open = function open(optionalUrl, optionalInject) { // How to open the app.
var url = optionalUrl || that.home;
var inject = optionalInject || that.inject;
if (that.isQMLUrl(url)) {
that.tablet.loadQMLSource(url);
} else {
that.tablet.gotoWebScreen(url, inject);
}
};
// Opens some app on top of the current app (on desktop, opens new window)
that.openNewAppOnTop = function openNewAppOnTop(url, optionalInject) {
var inject = optionalInject || "";
if (that.isQMLUrl(url)) {
that.tablet.loadQMLOnTop(url);
} else {
that.tablet.loadWebScreenOnTop(url, inject);
}
};
that.close = function close() { // How to close the app.
that.currentVisibleUrl = "";
// for toolbar-mode: go back to home screen, this will close the window.
that.tablet.gotoHomeScreen();
};
that.buttonActive = function buttonActive(isActive) { // How to make the button active (white).
that.button.editProperties({isActive: isActive});
};
that.isQMLUrl = function isQMLUrl(url) {
var type = /.qml$/.test(url) ? 'QML' : 'Web';
return type === 'QML';
};
that.isCurrentlyOnQMLScreen = function isCurrentlyOnQMLScreen() {
return that.currentVisibleScreenType === 'QML';
};
//
// START Notification Handling Defaults
//
that.messagesWaiting = function messagesWaiting(isWaiting) { // How to indicate a message light on button.
// Note that waitingButton doesn't have to exist unless someone explicitly calls this with isWaiting true.
that.button.editProperties({
icon: isWaiting ? that.normalMessagesButton : that.normalButton,
activeIcon: isWaiting ? that.activeMessagesButton : that.activeButton
});
};
that.notificationPollTimeout = [false];
that.notificationPollTimeoutMs = [60000];
that.notificationPollEndpoint = [false];
that.notificationPollStopPaginatingConditionMet = [false];
that.notificationDataProcessPage = function (data) {
return data;
};
that.notificationPollCallback = [that.ignore];
that.notificationPollCaresAboutSince = [false];
that.notificationInitialCallbackMade = [false];
that.notificationDisplayBanner = function (message) {
if (!that.isOpen) {
Window.displayAnnouncement(message);
}
};
//
// END Notification Handling Defaults
//
// Handlers
that.onScreenChanged = function onScreenChanged(type, url) {
// Set isOpen, wireEventBridge, set buttonActive as appropriate,
// and finally call onOpened() or onClosed() IFF defined.
that.setCurrentVisibleScreenMetadata(type, url);
if (that.checkIsOpen(type, url)) {
that.wireEventBridge(true);
if (!that.isOpen) {
that.buttonActive(true);
if (that.onOpened) {
that.onOpened();
}
that.isOpen = true;
}
} else {
// A different screen is now visible, or the tablet has been closed.
// Tablet visibility is controlled separately by `tabletShownChanged()`
that.wireEventBridge(false);
if (that.isOpen) {
that.buttonActive(false);
if (that.onClosed) {
that.onClosed();
}
that.isOpen = false;
}
}
};
// Overwrite with the given properties:
Object.keys(properties).forEach(function (key) {
that[key] = properties[key];
});
//
// START Notification Handling
//
var currentDataPageToRetrieve = [];
var concatenatedServerResponse = [];
for (var i = 0; i < that.notificationPollEndpoint.length; i++) {
currentDataPageToRetrieve[i] = 1;
concatenatedServerResponse[i] = new Array();
}
var MAX_LOG_LENGTH_CHARACTERS = 300;
function requestCallback(error, response, optionalParams) {
var indexOfRequest = optionalParams.indexOfRequest;
var urlOfRequest = optionalParams.urlOfRequest;
if (error || (response.status !== 'success')) {
print("Error: unable to complete request from URL. Error:", error || response.status);
startNotificationTimer(indexOfRequest);
return;
}
if (!that.notificationPollStopPaginatingConditionMet[indexOfRequest] ||
that.notificationPollStopPaginatingConditionMet[indexOfRequest](response)) {
startNotificationTimer(indexOfRequest);
var notificationData;
if (concatenatedServerResponse[indexOfRequest].length) {
notificationData = concatenatedServerResponse[indexOfRequest];
} else {
notificationData = that.notificationDataProcessPage[indexOfRequest](response);
}
console.debug(that.buttonName,
'truncated notification data for processing:',
JSON.stringify(notificationData).substring(0, MAX_LOG_LENGTH_CHARACTERS));
that.notificationPollCallback[indexOfRequest](notificationData);
that.notificationInitialCallbackMade[indexOfRequest] = true;
currentDataPageToRetrieve[indexOfRequest] = 1;
concatenatedServerResponse[indexOfRequest] = new Array();
} else {
concatenatedServerResponse[indexOfRequest] =
concatenatedServerResponse[indexOfRequest].concat(that.notificationDataProcessPage[indexOfRequest](response));
currentDataPageToRetrieve[indexOfRequest]++;
request({
json: true,
uri: (urlOfRequest + "&page=" + currentDataPageToRetrieve[indexOfRequest])
}, requestCallback, optionalParams);
}
}
var METAVERSE_BASE = Account.metaverseServerURL;
var MS_IN_SEC = 1000;
that.notificationPoll = function (i) {
if (!that.notificationPollEndpoint[i]) {
return;
}
// User is "appearing offline" or is not logged in
if (GlobalServices.findableBy === "none" || Account.username === "Unknown user") {
// The notification polling will restart when the user changes their availability
// or when they log in, so it's not necessary to restart a timer here.
console.debug(that.buttonName + " Notifications: User is appearing offline or not logged in. " +
that.buttonName + " will poll for notifications when user logs in and has their availability " +
"set to not appear offline.");
return;
}
var url = METAVERSE_BASE + that.notificationPollEndpoint[i];
var settingsKey = "notifications/" + that.notificationPollEndpoint[i] + "/lastPoll";
var currentTimestamp = new Date().getTime();
var lastPollTimestamp = Settings.getValue(settingsKey, currentTimestamp);
if (that.notificationPollCaresAboutSince[i]) {
url = url + "&since=" + lastPollTimestamp / MS_IN_SEC;
}
Settings.setValue(settingsKey, currentTimestamp);
request({
json: true,
uri: url
},
requestCallback,
{
indexOfRequest: i,
urlOfRequest: url
});
};
// This won't do anything if there isn't a notification endpoint set
for (i = 0; i < that.notificationPollEndpoint.length; i++) {
that.notificationPoll(i);
}
function startNotificationTimer(indexOfRequest) {
that.notificationPollTimeout[indexOfRequest] = Script.setTimeout(function () {
that.notificationPoll(indexOfRequest);
}, that.notificationPollTimeoutMs[indexOfRequest]);
}
function restartNotificationPoll() {
for (var j = 0; j < that.notificationPollEndpoint.length; j++) {
that.notificationInitialCallbackMade[j] = false;
if (that.notificationPollTimeout[j]) {
Script.clearTimeout(that.notificationPollTimeout[j]);
that.notificationPollTimeout[j] = false;
}
that.notificationPoll(j);
}
}
//
// END Notification Handling
//
// Properties:
that.tablet = Tablet.getTablet(that.tabletName);
// Must be after we gather properties.
that.buttonPrefix = that.buttonPrefix || that.buttonName.toLowerCase() + "-";
defaultButton('normalButton', 'i.svg');
defaultButton('activeButton', 'a.svg');
defaultButton('normalMessagesButton', 'i-msg.svg');
defaultButton('activeMessagesButton', 'a-msg.svg');
var buttonOptions = {
icon: that.normalButton,
activeIcon: that.activeButton,
text: that.buttonName
};
// `TabletScriptingInterface` looks for the presence of a `sortOrder` key.
// What it SHOULD do is look to see if the value inside that key is defined.
// To get around the current code, we do this instead.
if (that.sortOrder) {
buttonOptions.sortOrder = that.sortOrder;
}
that.button = that.tablet.addButton(buttonOptions);
that.ignore = function ignore() { };
that.hasOutboundEventBridge = false;
that.hasInboundQmlEventBridge = false;
that.hasInboundHtmlEventBridge = false;
// HTML event bridge uses strings, not objects. Here we abstract over that.
// (Although injected javascript still has to use JSON.stringify/JSON.parse.)
that.sendToHtml = function (messageObject) {
that.tablet.emitScriptEvent(JSON.stringify(messageObject));
};
that.fromHtml = function (messageString) {
var parsedMessage = JSON.parse(messageString);
parsedMessage.messageSrc = "HTML";
that.onMessage(parsedMessage);
};
that.sendMessage = that.ignore;
that.wireEventBridge = function wireEventBridge(on) {
// Uniquivocally sets that.sendMessage(messageObject) to do the right thing.
// Sets has*EventBridge and wires onMessage to the proper event bridge as appropriate, IFF onMessage defined.
var isCurrentlyOnQMLScreen = that.isCurrentlyOnQMLScreen();
// Outbound (always, regardless of whether there is an inbound handler).
if (on) {
that.sendMessage = isCurrentlyOnQMLScreen ? that.tablet.sendToQml : that.sendToHtml;
that.hasOutboundEventBridge = true;
} else {
that.sendMessage = that.ignore;
that.hasOutboundEventBridge = false;
}
if (!that.onMessage) {
return;
}
// Inbound
if (on) {
if (isCurrentlyOnQMLScreen && !that.hasInboundQmlEventBridge) {
console.debug(that.buttonName, 'connecting', that.tablet.fromQml);
that.tablet.fromQml.connect(that.onMessage);
that.hasInboundQmlEventBridge = true;
} else if (!isCurrentlyOnQMLScreen && !that.hasInboundHtmlEventBridge) {
console.debug(that.buttonName, 'connecting', that.tablet.webEventReceived);
that.tablet.webEventReceived.connect(that.fromHtml);
that.hasInboundHtmlEventBridge = true;
}
} else {
if (that.hasInboundQmlEventBridge) {
console.debug(that.buttonName, 'disconnecting', that.tablet.fromQml);
that.tablet.fromQml.disconnect(that.onMessage);
that.hasInboundQmlEventBridge = false;
}
if (that.hasInboundHtmlEventBridge) {
console.debug(that.buttonName, 'disconnecting', that.tablet.webEventReceived);
that.tablet.webEventReceived.disconnect(that.fromHtml);
that.hasInboundHtmlEventBridge = false;
}
}
};
that.isOpen = false;
// To facilitate incremental development, only wire onClicked to do something when "home" is defined in properties.
that.onClicked = that.home
? function onClicked() {
// Call open() or close(), and reset type based on current home property.
if (that.isOpen) {
that.close();
} else {
that.open();
}
} : that.ignore;
that.onScriptEnding = function onScriptEnding() {
// Close if necessary, clean up any remaining handlers, and remove the button.
GlobalServices.myUsernameChanged.disconnect(restartNotificationPoll);
GlobalServices.findableByChanged.disconnect(restartNotificationPoll);
that.tablet.screenChanged.disconnect(that.onScreenChanged);
if (that.isOpen) {
that.close();
that.onScreenChanged("", "");
}
if (that.button) {
if (that.onClicked) {
that.button.clicked.disconnect(that.onClicked);
}
that.tablet.removeButton(that.button);
}
for (var i = 0; i < that.notificationPollTimeout.length; i++) {
if (that.notificationPollTimeout[i]) {
Script.clearInterval(that.notificationPollTimeout[i]);
that.notificationPollTimeout[i] = false;
}
}
};
// Set up the handlers.
that.tablet.screenChanged.connect(that.onScreenChanged);
that.button.clicked.connect(that.onClicked);
Script.scriptEnding.connect(that.onScriptEnding);
GlobalServices.findableByChanged.connect(restartNotificationPoll);
GlobalServices.myUsernameChanged.connect(restartNotificationPoll);
if (that.buttonName === Settings.getValue("startUpApp")) {
Settings.setValue("startUpApp", "");
Script.setTimeout(function () {
that.open();
}, 1000);
}
}
module.exports = AppUi;