mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-10 23:48:01 -05:00
Compare commits
1 Commits
wch-module
...
revert-107
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
44a98b34cf |
@@ -3,10 +3,6 @@
|
||||
#' These functions show and remove notifications in a Shiny application.
|
||||
#'
|
||||
#' @param ui Content of message.
|
||||
#' @param action Message content that represents an action. For example, this
|
||||
#' could be a link that the user can click on. This is separate from \code{ui}
|
||||
#' so customized layouts can handle the main notification content separately
|
||||
#' from action content.
|
||||
#' @param duration Number of seconds to display the message before it
|
||||
#' disappears. Use \code{NULL} to make the message not automatically
|
||||
#' disappear.
|
||||
@@ -32,9 +28,7 @@
|
||||
#' ),
|
||||
#' server = function(input, output) {
|
||||
#' observeEvent(input$show, {
|
||||
#' showNotification("Message text",
|
||||
#' action = a(href = "javascript:location.reload();", "Reload page")
|
||||
#' )
|
||||
#' showNotification("Message text")
|
||||
#' })
|
||||
#' }
|
||||
#' )
|
||||
@@ -67,9 +61,8 @@
|
||||
#' )
|
||||
#' }
|
||||
#' @export
|
||||
showNotification <- function(ui, action = NULL, duration = 5,
|
||||
closeButton = TRUE, id = NULL,
|
||||
type = c("default", "message", "warning", "error"),
|
||||
showNotification <- function(ui, duration = 5, closeButton = TRUE,
|
||||
id = NULL, type = c("default", "message", "warning", "error"),
|
||||
session = getDefaultReactiveDomain())
|
||||
{
|
||||
|
||||
@@ -77,13 +70,11 @@ showNotification <- function(ui, action = NULL, duration = 5,
|
||||
id <- randomID()
|
||||
|
||||
res <- processDeps(ui, session)
|
||||
actionRes <- processDeps(action, session)
|
||||
|
||||
session$sendNotification("show",
|
||||
list(
|
||||
html = res$html,
|
||||
action = actionRes$html,
|
||||
deps = c(res$deps, actionRes$deps),
|
||||
deps = res$deps,
|
||||
duration = if (!is.null(duration)) duration * 1000,
|
||||
closeButton = closeButton,
|
||||
id = id,
|
||||
|
||||
20
R/shiny.R
20
R/shiny.R
@@ -241,18 +241,6 @@ workerId <- local({
|
||||
#' This is the request that was used to initiate the websocket connection
|
||||
#' (as opposed to the request that downloaded the web page for the app).
|
||||
#' }
|
||||
#' \item{allowReconnect(value)}{
|
||||
#' If \code{value} is \code{TRUE} and run in a hosting environment (Shiny
|
||||
#' Server or Connect) with reconnections enabled, then when the session ends
|
||||
#' due to the network connection closing, the client will attempt to
|
||||
#' reconnect to the server. If a reconnection is successful, the browser will
|
||||
#' send all the current input values to the new session on the server, and
|
||||
#' the server will recalculate any outputs and send them back to the client.
|
||||
#' If \code{value} is \code{FALSE}, reconnections will be disabled (this is
|
||||
#' the default state). If \code{"force"}, then the client browser will always
|
||||
#' attempt to reconnect. The only reason to use \code{"force"} is for testing
|
||||
#' on a local connection (without Shiny Server or Connect).
|
||||
#' }
|
||||
#' \item{sendCustomMessage(type, message)}{
|
||||
#' Sends a custom message to the web page. \code{type} must be a
|
||||
#' single-element character vector giving the type of message, while
|
||||
@@ -542,14 +530,6 @@ ShinySession <- R6Class(
|
||||
setShowcase = function(value) {
|
||||
private$showcase <- !is.null(value) && as.logical(value)
|
||||
},
|
||||
|
||||
allowReconnect = function(value) {
|
||||
if (!(identical(value, TRUE) || identical(value, FALSE) || identical(value, "force"))) {
|
||||
stop('value must be TRUE, FALSE, or "force"')
|
||||
}
|
||||
private$write(toJSON(list(allowReconnect = value)))
|
||||
},
|
||||
|
||||
defineOutput = function(name, func, label) {
|
||||
"Binds an output generating function to this name. The function can either
|
||||
take no parameters, or have named parameters for \\code{name} and
|
||||
|
||||
@@ -1,13 +1,6 @@
|
||||
#shiny-disconnected-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
body.disconnected {
|
||||
background-color: #999;
|
||||
opacity: 0.5;
|
||||
overflow: hidden;
|
||||
z-index: 99998;
|
||||
}
|
||||
|
||||
.table.shiny-table > thead > tr > th,
|
||||
@@ -284,7 +277,7 @@
|
||||
background-color: rgba(0,0,0,0);
|
||||
padding: 2px;
|
||||
width: 250px;
|
||||
z-index: 99999;
|
||||
z-index: 9999;
|
||||
}
|
||||
|
||||
.shiny-notification {
|
||||
@@ -329,9 +322,3 @@
|
||||
.shiny-notification-close:hover {
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.shiny-notification-content-action a {
|
||||
color: rgb(51, 122, 183);
|
||||
text-decoration: underline;
|
||||
font-weight: bold;
|
||||
}
|
||||
|
||||
@@ -550,8 +550,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
this.$pendingMessages = [];
|
||||
this.$activeRequests = {};
|
||||
this.$nextRequestId = 0;
|
||||
|
||||
this.$allowReconnect = false;
|
||||
};
|
||||
|
||||
(function () {
|
||||
@@ -575,19 +573,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
return !!this.$socket;
|
||||
};
|
||||
|
||||
var scheduledReconnect = null;
|
||||
this.reconnect = function () {
|
||||
// This function can be invoked directly even if there's a scheduled
|
||||
// reconnect, so be sure to clear any such scheduled reconnects.
|
||||
clearTimeout(scheduledReconnect);
|
||||
|
||||
if (this.isConnected()) throw "Attempted to reconnect, but already connected.";
|
||||
|
||||
this.$socket = this.createSocket();
|
||||
this.$initialInput = $.extend({}, this.$inputValues);
|
||||
this.$updateConditionals();
|
||||
};
|
||||
|
||||
this.createSocket = function () {
|
||||
var self = this;
|
||||
|
||||
@@ -610,22 +595,15 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
|
||||
var ws = new WebSocket(protocol + '//' + window.location.host + defaultPath);
|
||||
ws.binaryType = 'arraybuffer';
|
||||
|
||||
return ws;
|
||||
};
|
||||
|
||||
var socket = createSocketFunc();
|
||||
var hasOpened = false;
|
||||
socket.onopen = function () {
|
||||
hasOpened = true;
|
||||
|
||||
$(document).trigger({
|
||||
type: 'shiny:connected',
|
||||
socket: socket
|
||||
});
|
||||
|
||||
self.onConnected();
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
method: 'init',
|
||||
data: self.$initialInput
|
||||
@@ -639,22 +617,13 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
socket.onmessage = function (e) {
|
||||
self.dispatchMessage(e.data);
|
||||
};
|
||||
// Called when a successfully-opened websocket is closed, or when an
|
||||
// attempt to open a connection fails.
|
||||
socket.onclose = function () {
|
||||
// These things are needed only if we've successfully opened the
|
||||
// websocket.
|
||||
if (hasOpened) {
|
||||
$(document).trigger({
|
||||
type: 'shiny:disconnected',
|
||||
socket: socket
|
||||
});
|
||||
|
||||
self.$notifyDisconnected();
|
||||
}
|
||||
|
||||
self.onDisconnected(); // Must be run before self.$removeSocket()
|
||||
self.$removeSocket();
|
||||
$(document).trigger({
|
||||
type: 'shiny:disconnected',
|
||||
socket: socket
|
||||
});
|
||||
$(document.body).addClass('disconnected');
|
||||
self.$notifyDisconnected();
|
||||
};
|
||||
return socket;
|
||||
};
|
||||
@@ -695,73 +664,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
}
|
||||
};
|
||||
|
||||
this.$removeSocket = function () {
|
||||
this.$socket = null;
|
||||
};
|
||||
|
||||
this.$scheduleReconnect = function (delay) {
|
||||
var self = this;
|
||||
console.log("Waiting " + delay / 1000 + "s before trying to reconnect.");
|
||||
|
||||
scheduledReconnect = setTimeout(function () {
|
||||
self.reconnect();
|
||||
}, delay);
|
||||
};
|
||||
|
||||
// How long should we wait before trying the next reconnection?
|
||||
// The delay will increase with subsequent attempts.
|
||||
// .next: Return the time to wait for next connection, and increment counter.
|
||||
// .reset: Reset the attempt counter.
|
||||
var reconnectDelay = function () {
|
||||
var attempts = 0;
|
||||
// Time to wait before each reconnection attempt. If we go through all of
|
||||
// these values, use otherDelay. Add 500ms to each one so that in the last
|
||||
// 0.5s, it shows "..."
|
||||
var delays = [1500, 1500, 2500, 2500, 5500, 5500];
|
||||
var otherDelay = 10500;
|
||||
|
||||
return {
|
||||
next: function next() {
|
||||
var delay;
|
||||
if (attempts >= delays.length) {
|
||||
delay = otherDelay;
|
||||
} else {
|
||||
delay = delays[attempts];
|
||||
}
|
||||
|
||||
attempts++;
|
||||
return delay;
|
||||
},
|
||||
reset: function reset() {
|
||||
attempts = 0;
|
||||
}
|
||||
};
|
||||
}();
|
||||
|
||||
this.onDisconnected = function () {
|
||||
// Add gray-out overlay, if not already present
|
||||
var $overlay = $('#shiny-disconnected-overlay');
|
||||
if ($overlay.length === 0) {
|
||||
$(document.body).append('<div id="shiny-disconnected-overlay"></div>');
|
||||
}
|
||||
|
||||
// To try a reconnect, both the app (this.$allowReconnect) and the
|
||||
// server (this.$socket.allowReconnect) must allow reconnections, or
|
||||
// session$allowReconnect("force") was called. The "force" option should
|
||||
// only be used for testing.
|
||||
if (this.$allowReconnect === true && this.$socket.allowReconnect === true || this.$allowReconnect === "force") {
|
||||
var delay = reconnectDelay.next();
|
||||
exports.showReconnectDialog(delay);
|
||||
this.$scheduleReconnect(delay);
|
||||
}
|
||||
};
|
||||
|
||||
this.onConnected = function () {
|
||||
$('#shiny-disconnected-overlay').remove();
|
||||
exports.hideReconnectDialog();
|
||||
reconnectDelay.reset();
|
||||
};
|
||||
|
||||
// NB: Including blobs will cause IE to break!
|
||||
// TODO: Make blobs work with Internet Explorer
|
||||
//
|
||||
@@ -1088,14 +990,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
}
|
||||
});
|
||||
|
||||
addMessageHandler('allowReconnect', function (message) {
|
||||
if (message === true || message === false || message === "force") {
|
||||
this.$allowReconnect = message;
|
||||
} else {
|
||||
throw "Invalid value for allowReconnect: " + message;
|
||||
}
|
||||
});
|
||||
|
||||
addMessageHandler('custom', function (message) {
|
||||
// For old-style custom messages - should deprecate and migrate to new
|
||||
// method
|
||||
@@ -1214,61 +1108,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
exports.progressHandlers = progressHandlers;
|
||||
}).call(ShinyApp.prototype);
|
||||
|
||||
// showReconnectDialog and hideReconnectDialog are conceptually related to the
|
||||
// socket code, but they belong in the Shiny/exports object.
|
||||
{
|
||||
(function () {
|
||||
var notificationID = null;
|
||||
|
||||
exports.showReconnectDialog = function () {
|
||||
var reconnectTime = null;
|
||||
|
||||
function updateTime() {
|
||||
var $time = $("#shiny-reconnect-time");
|
||||
// If the time has been removed, exit and don't reschedule this function.
|
||||
if ($time.length === 0) return;
|
||||
|
||||
var seconds = Math.floor((reconnectTime - new Date().getTime()) / 1000);
|
||||
if (seconds > 0) {
|
||||
$time.text(" in " + seconds + "s");
|
||||
} else {
|
||||
$time.text("...");
|
||||
}
|
||||
|
||||
// Reschedule this function after 1 second
|
||||
setTimeout(updateTime, 1000);
|
||||
}
|
||||
|
||||
return function (delay) {
|
||||
reconnectTime = new Date().getTime() + delay;
|
||||
|
||||
// If there's already a reconnect dialog, don't add another
|
||||
if ($('#shiny-reconnect-text').length > 0) return;
|
||||
|
||||
var html = '<span id="shiny-reconnect-text">Attempting to reconnect</span>' + '<span id="shiny-reconnect-time"></span>';
|
||||
var action = '<a id="shiny-reconnect-now" href="#" onclick="Shiny.shinyapp.reconnect();">Try now</a>';
|
||||
|
||||
notificationID = exports.notifications.show({
|
||||
html: html,
|
||||
action: action,
|
||||
duration: null,
|
||||
closeButton: false,
|
||||
type: 'warning'
|
||||
});
|
||||
|
||||
updateTime();
|
||||
};
|
||||
}();
|
||||
|
||||
exports.hideReconnectDialog = function () {
|
||||
if (notificationID) {
|
||||
exports.notifications.remove(notificationID);
|
||||
notificationID = null;
|
||||
}
|
||||
};
|
||||
})();
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
// Source file: ../srcjs/notifications.js
|
||||
|
||||
@@ -1281,9 +1120,7 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
var _ref = arguments.length <= 0 || arguments[0] === undefined ? {} : arguments[0];
|
||||
|
||||
var _ref$html = _ref.html;
|
||||
var html = _ref$html === undefined ? '' : _ref$html;
|
||||
var _ref$action = _ref.action;
|
||||
var action = _ref$action === undefined ? '' : _ref$action;
|
||||
var html = _ref$html === undefined ? null : _ref$html;
|
||||
var _ref$deps = _ref.deps;
|
||||
var deps = _ref$deps === undefined ? [] : _ref$deps;
|
||||
var _ref$duration = _ref.duration;
|
||||
@@ -1305,9 +1142,8 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
if ($notification.length === 0) $notification = _create(id);
|
||||
|
||||
// Render html and dependencies
|
||||
var newHtml = '<div class="shiny-notification-content-text">' + html + '</div>' + ('<div class="shiny-notification-content-action">' + action + '</div>');
|
||||
var $content = $notification.find('.shiny-notification-content');
|
||||
exports.renderContent($content, { html: newHtml, deps: deps });
|
||||
exports.renderContent($content, { html: html, deps: deps });
|
||||
|
||||
// Remove any existing classes of the form 'shiny-notification-xxxx'.
|
||||
// The xxxx would be strings like 'warning'.
|
||||
@@ -1351,7 +1187,6 @@ var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol
|
||||
|
||||
// Returns an individual notification DOM object (wrapped in jQuery).
|
||||
function _get(id) {
|
||||
if (!id) return null;
|
||||
return _getPanel().find('#shiny-notification-' + $escape(id));
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because one or more lines are too long
6
inst/www/shared/shiny.min.js
vendored
6
inst/www/shared/shiny.min.js
vendored
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -85,18 +85,6 @@
|
||||
This is the request that was used to initiate the websocket connection
|
||||
(as opposed to the request that downloaded the web page for the app).
|
||||
}
|
||||
\item{allowReconnect(value)}{
|
||||
If \code{value} is \code{TRUE} and run in a hosting environment (Shiny
|
||||
Server or Connect) with reconnections enabled, then when the session ends
|
||||
due to the network connection closing, the client will attempt to
|
||||
reconnect to the server. If a reconnection is successful, the browser will
|
||||
send all the current input values to the new session on the server, and
|
||||
the server will recalculate any outputs and send them back to the client.
|
||||
If \code{value} is \code{FALSE}, reconnections will be disabled (this is
|
||||
the default state). If \code{"force"}, then the client browser will always
|
||||
attempt to reconnect. The only reason to use \code{"force"} is for testing
|
||||
on a local connection (without Shiny Server or Connect).
|
||||
}
|
||||
\item{sendCustomMessage(type, message)}{
|
||||
Sends a custom message to the web page. \code{type} must be a
|
||||
single-element character vector giving the type of message, while
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
\alias{showNotification}
|
||||
\title{Show or remove a notification}
|
||||
\usage{
|
||||
showNotification(ui, action = NULL, duration = 5, closeButton = TRUE,
|
||||
id = NULL, type = c("default", "message", "warning", "error"),
|
||||
showNotification(ui, duration = 5, closeButton = TRUE, id = NULL,
|
||||
type = c("default", "message", "warning", "error"),
|
||||
session = getDefaultReactiveDomain())
|
||||
|
||||
removeNotification(id = NULL, session = getDefaultReactiveDomain())
|
||||
@@ -14,11 +14,6 @@ removeNotification(id = NULL, session = getDefaultReactiveDomain())
|
||||
\arguments{
|
||||
\item{ui}{Content of message.}
|
||||
|
||||
\item{action}{Message content that represents an action. For example, this
|
||||
could be a link that the user can click on. This is separate from \code{ui}
|
||||
so customized layouts can handle the main notification content separately
|
||||
from action content.}
|
||||
|
||||
\item{duration}{Number of seconds to display the message before it
|
||||
disappears. Use \code{NULL} to make the message not automatically
|
||||
disappear.}
|
||||
@@ -52,9 +47,7 @@ shinyApp(
|
||||
),
|
||||
server = function(input, output) {
|
||||
observeEvent(input$show, {
|
||||
showNotification("Message text",
|
||||
action = a(href = "javascript:location.reload();", "Reload page")
|
||||
)
|
||||
showNotification("Message text")
|
||||
})
|
||||
}
|
||||
)
|
||||
|
||||
@@ -3,8 +3,8 @@ exports.notifications = (function() {
|
||||
// Milliseconds to fade in or out
|
||||
const fadeDuration = 250;
|
||||
|
||||
function show({ html='', action='', deps=[], duration=5000,
|
||||
id=null, closeButton=true, type=null } = {})
|
||||
function show({ html=null, deps=[], duration=5000, id=null,
|
||||
closeButton=true, type=null } = {})
|
||||
{
|
||||
if (!id)
|
||||
id = randomId();
|
||||
@@ -18,10 +18,8 @@ exports.notifications = (function() {
|
||||
$notification = _create(id);
|
||||
|
||||
// Render html and dependencies
|
||||
const newHtml = `<div class="shiny-notification-content-text">${html}</div>` +
|
||||
`<div class="shiny-notification-content-action">${action}</div>`;
|
||||
const $content = $notification.find('.shiny-notification-content');
|
||||
exports.renderContent($content, { html: newHtml, deps: deps });
|
||||
exports.renderContent($content, { html, deps });
|
||||
|
||||
// Remove any existing classes of the form 'shiny-notification-xxxx'.
|
||||
// The xxxx would be strings like 'warning'.
|
||||
@@ -71,8 +69,6 @@ exports.notifications = (function() {
|
||||
|
||||
// Returns an individual notification DOM object (wrapped in jQuery).
|
||||
function _get(id) {
|
||||
if (!id)
|
||||
return null;
|
||||
return _getPanel().find('#shiny-notification-' + $escape(id));
|
||||
}
|
||||
|
||||
|
||||
@@ -17,8 +17,6 @@ var ShinyApp = function() {
|
||||
this.$pendingMessages = [];
|
||||
this.$activeRequests = {};
|
||||
this.$nextRequestId = 0;
|
||||
|
||||
this.$allowReconnect = false;
|
||||
};
|
||||
|
||||
(function() {
|
||||
@@ -43,20 +41,6 @@ var ShinyApp = function() {
|
||||
return !!this.$socket;
|
||||
};
|
||||
|
||||
var scheduledReconnect = null;
|
||||
this.reconnect = function() {
|
||||
// This function can be invoked directly even if there's a scheduled
|
||||
// reconnect, so be sure to clear any such scheduled reconnects.
|
||||
clearTimeout(scheduledReconnect);
|
||||
|
||||
if (this.isConnected())
|
||||
throw "Attempted to reconnect, but already connected.";
|
||||
|
||||
this.$socket = this.createSocket();
|
||||
this.$initialInput = $.extend({}, this.$inputValues);
|
||||
this.$updateConditionals();
|
||||
};
|
||||
|
||||
this.createSocket = function () {
|
||||
var self = this;
|
||||
|
||||
@@ -81,22 +65,15 @@ var ShinyApp = function() {
|
||||
|
||||
var ws = new WebSocket(protocol + '//' + window.location.host + defaultPath);
|
||||
ws.binaryType = 'arraybuffer';
|
||||
|
||||
return ws;
|
||||
};
|
||||
|
||||
var socket = createSocketFunc();
|
||||
var hasOpened = false;
|
||||
socket.onopen = function() {
|
||||
hasOpened = true;
|
||||
|
||||
$(document).trigger({
|
||||
type: 'shiny:connected',
|
||||
socket: socket
|
||||
});
|
||||
|
||||
self.onConnected();
|
||||
|
||||
socket.send(JSON.stringify({
|
||||
method: 'init',
|
||||
data: self.$initialInput
|
||||
@@ -110,22 +87,13 @@ var ShinyApp = function() {
|
||||
socket.onmessage = function(e) {
|
||||
self.dispatchMessage(e.data);
|
||||
};
|
||||
// Called when a successfully-opened websocket is closed, or when an
|
||||
// attempt to open a connection fails.
|
||||
socket.onclose = function() {
|
||||
// These things are needed only if we've successfully opened the
|
||||
// websocket.
|
||||
if (hasOpened) {
|
||||
$(document).trigger({
|
||||
type: 'shiny:disconnected',
|
||||
socket: socket
|
||||
});
|
||||
|
||||
self.$notifyDisconnected();
|
||||
}
|
||||
|
||||
self.onDisconnected(); // Must be run before self.$removeSocket()
|
||||
self.$removeSocket();
|
||||
$(document).trigger({
|
||||
type: 'shiny:disconnected',
|
||||
socket: socket
|
||||
});
|
||||
$(document.body).addClass('disconnected');
|
||||
self.$notifyDisconnected();
|
||||
};
|
||||
return socket;
|
||||
};
|
||||
@@ -170,73 +138,6 @@ var ShinyApp = function() {
|
||||
}
|
||||
};
|
||||
|
||||
this.$removeSocket = function() {
|
||||
this.$socket = null;
|
||||
};
|
||||
|
||||
this.$scheduleReconnect = function(delay) {
|
||||
var self = this;
|
||||
console.log("Waiting " + (delay/1000) + "s before trying to reconnect.");
|
||||
|
||||
scheduledReconnect = setTimeout(function() { self.reconnect(); }, delay);
|
||||
};
|
||||
|
||||
// How long should we wait before trying the next reconnection?
|
||||
// The delay will increase with subsequent attempts.
|
||||
// .next: Return the time to wait for next connection, and increment counter.
|
||||
// .reset: Reset the attempt counter.
|
||||
var reconnectDelay = (function() {
|
||||
var attempts = 0;
|
||||
// Time to wait before each reconnection attempt. If we go through all of
|
||||
// these values, use otherDelay. Add 500ms to each one so that in the last
|
||||
// 0.5s, it shows "..."
|
||||
var delays = [1500, 1500, 2500, 2500, 5500, 5500];
|
||||
var otherDelay = 10500;
|
||||
|
||||
return {
|
||||
next: function() {
|
||||
var delay;
|
||||
if (attempts >= delays.length) {
|
||||
delay = otherDelay;
|
||||
} else {
|
||||
delay = delays[attempts];
|
||||
}
|
||||
|
||||
attempts++;
|
||||
return delay;
|
||||
},
|
||||
reset: function() {
|
||||
attempts = 0;
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
||||
this.onDisconnected = function() {
|
||||
// Add gray-out overlay, if not already present
|
||||
var $overlay = $('#shiny-disconnected-overlay');
|
||||
if ($overlay.length === 0) {
|
||||
$(document.body).append('<div id="shiny-disconnected-overlay"></div>');
|
||||
}
|
||||
|
||||
// To try a reconnect, both the app (this.$allowReconnect) and the
|
||||
// server (this.$socket.allowReconnect) must allow reconnections, or
|
||||
// session$allowReconnect("force") was called. The "force" option should
|
||||
// only be used for testing.
|
||||
if ((this.$allowReconnect === true && this.$socket.allowReconnect === true) ||
|
||||
this.$allowReconnect === "force")
|
||||
{
|
||||
var delay = reconnectDelay.next();
|
||||
exports.showReconnectDialog(delay);
|
||||
this.$scheduleReconnect(delay);
|
||||
}
|
||||
};
|
||||
|
||||
this.onConnected = function() {
|
||||
$('#shiny-disconnected-overlay').remove();
|
||||
exports.hideReconnectDialog();
|
||||
reconnectDelay.reset();
|
||||
};
|
||||
|
||||
// NB: Including blobs will cause IE to break!
|
||||
// TODO: Make blobs work with Internet Explorer
|
||||
//
|
||||
@@ -588,14 +489,6 @@ var ShinyApp = function() {
|
||||
}
|
||||
});
|
||||
|
||||
addMessageHandler('allowReconnect', function(message) {
|
||||
if (message === true || message === false || message === "force") {
|
||||
this.$allowReconnect = message;
|
||||
} else {
|
||||
throw "Invalid value for allowReconnect: " + message;
|
||||
}
|
||||
});
|
||||
|
||||
addMessageHandler('custom', function(message) {
|
||||
// For old-style custom messages - should deprecate and migrate to new
|
||||
// method
|
||||
@@ -726,61 +619,3 @@ var ShinyApp = function() {
|
||||
|
||||
|
||||
}).call(ShinyApp.prototype);
|
||||
|
||||
|
||||
|
||||
// showReconnectDialog and hideReconnectDialog are conceptually related to the
|
||||
// socket code, but they belong in the Shiny/exports object.
|
||||
{
|
||||
let notificationID = null;
|
||||
|
||||
exports.showReconnectDialog = (function() {
|
||||
var reconnectTime = null;
|
||||
|
||||
function updateTime() {
|
||||
var $time = $("#shiny-reconnect-time");
|
||||
// If the time has been removed, exit and don't reschedule this function.
|
||||
if ($time.length === 0) return;
|
||||
|
||||
var seconds = Math.floor((reconnectTime - new Date().getTime()) / 1000);
|
||||
if (seconds > 0) {
|
||||
$time.text(" in " + seconds + "s");
|
||||
} else {
|
||||
$time.text("...");
|
||||
}
|
||||
|
||||
// Reschedule this function after 1 second
|
||||
setTimeout(updateTime, 1000);
|
||||
}
|
||||
|
||||
|
||||
return function(delay) {
|
||||
reconnectTime = new Date().getTime() + delay;
|
||||
|
||||
// If there's already a reconnect dialog, don't add another
|
||||
if ($('#shiny-reconnect-text').length > 0)
|
||||
return;
|
||||
|
||||
var html = '<span id="shiny-reconnect-text">Attempting to reconnect</span>' +
|
||||
'<span id="shiny-reconnect-time"></span>';
|
||||
var action = '<a id="shiny-reconnect-now" href="#" onclick="Shiny.shinyapp.reconnect();">Try now</a>';
|
||||
|
||||
notificationID = exports.notifications.show({
|
||||
html: html,
|
||||
action: action,
|
||||
duration: null,
|
||||
closeButton: false,
|
||||
type: 'warning'
|
||||
});
|
||||
|
||||
updateTime();
|
||||
};
|
||||
})();
|
||||
|
||||
exports.hideReconnectDialog = function() {
|
||||
if (notificationID) {
|
||||
exports.notifications.remove(notificationID);
|
||||
notificationID = null;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user