Skip to content

Commit

Permalink
attempt to work on onshiny feature issue #168
Browse files Browse the repository at this point in the history
  • Loading branch information
daattali committed Oct 30, 2018
1 parent 22f3fa2 commit 7803c24
Show file tree
Hide file tree
Showing 2 changed files with 129 additions and 0 deletions.
44 changes: 44 additions & 0 deletions R/onshiny.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# connected and disconnected and sessioninitialized don't work because shiny is not ready yet/has already been killed
#' @export
onshiny <- function(event, expr, id = NULL, asis = FALSE) {
# get the Shiny session
session <- getSession()

# Make sure onshiny works with namespaces (shiny modules)
if (inherits(session, "session_proxy")) {
if (!is.null(id) && !asis) {
id <- session$ns(id)
}
}

hashable <- sprintf("%s_%s_%s_%s",
id,
as.integer(Sys.time()),
as.integer(sample(1e9, 1)),
deparse(substitute(expr)))
hash <- digest::digest(hashable, algo = "md5")

# send a call to JavaScript to register this event
shinyInputId <- paste0("shinyjs-onshiny-cb-", hash)
shinyInputIdJs <- shinyInputId
if (inherits(session, "session_proxy")) {
shinyInputIdJs <- session$ns(shinyInputIdJs)
}

session$sendCustomMessage(
"shinyjs-onshiny",
list(
event = event,
id = id,
shinyInputId = shinyInputIdJs
)
)

# listen for a response from javascript when the event occurs
shiny::observeEvent(session$input[[shinyInputId]], {
cat('HERE')
expr
})

invisible(NULL)
}
85 changes: 85 additions & 0 deletions inst/srcjs/shinyjs-default-funcs.js
Original file line number Diff line number Diff line change
Expand Up @@ -482,6 +482,39 @@ shinyjs = function() {
el.attr(attrName, JSON.stringify(attrValue));
};

// Some browsers cannot serialize all types of event properties, so whitelist
// the specific properties that should be passed to Shiny from javascript events
// (this list of properties is based on the list of javascript events in the
// shiny documentation)
var _onshinyEventsWhitelist = {
'shiny:busy' : [],
'shiny:idle' : [],
'shiny:inputchanged' : ['name', 'value', 'inputType', 'binding', 'el'],
'shiny:message' : ['message'],
'shiny:conditional' : [],
'shiny:bound' : ['binding', 'bindingType'],
'shiny:unbound' : ['binding', 'bindingType'],
'shiny:value' : ['name', 'value', 'binding'],
'shiny:error' : ['name', 'error', 'binding'],
'shiny:outputinvalidated' : ['name', 'binding'],
'shiny:recalculating' : [],
'shiny:recalculated' : [],
'shiny:visualchange' : ['visible', 'binding'],
'shiny:updateinput' : ['message', 'binding'],
'shiny:filedownload' : ['name', 'href']
};

// create a unique id
function _guid() {
function s4() {
return Math.floor((1 + Math.random()) * 0x10000)
.toString(16)
.substring(1);
}
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
s4() + '-' + s4() + s4() + s4();
}

return {

// by default, debug mode is off. If shinyjs is initialized with debug mode,
Expand Down Expand Up @@ -800,7 +833,59 @@ shinyjs = function() {
var $el = _getElements(params);
if ($el === null) return;
$el.click();
},

// when a shiny javascript event occurs
onshiny : function (params) {
var defaultParams = {
event : null,
id : null,
shinyInputId : null
}
params = shinyjs.getParams(params, defaultParams);

// Send a message back to R when the shiny event occurs
var selector = $(document);
if (params.id !== null) {
selector = _jqid(params.id);
}
selector.on(
'shiny:' + params.event,
function(event) {

// make sure we don't get into infinite recursion by exiting if the
// event is something we created
if (event.type === "shiny:inputchanged" &&
event.name.indexOf("shinyjs-onshiny-cb") != -1) {
return;
}

// Only keep event properties from a whitelist because some properties
// cannot be serialized by all browsers
var miniEvent = {};
$.each(_onshinyEventsWhitelist[event.type], function(idx, prop) {
if (prop == "el") {
// DOM elements cannot be serialized, but we don't want to throw
// them away completely, so just keep the most important attributes
miniEvent[prop] = {
id : event.el.id,
tagName : event.el.tagName,
className : event.el.className
};
} else {
miniEvent[prop] = event[prop];
}
});
// Ensure there is some new piece of information so that Shiny will
// trigger a new event
miniEvent["_rnd"] = _guid();

// Send to shiny the information about the event
Shiny.onInputChange(params.shinyInputId, miniEvent);
}
);
}

};
}();

Expand Down

0 comments on commit 7803c24

Please sign in to comment.