Getting rid of the renderUI
- Defining the new JS binding.
Use the
_
prefix to make the difference between the default input binding methods and the user-defined methods.
let boxBinding = new Shiny.InputBinding();
$.extend(boxBinding, {
// we are using the same class
find: function(scope) {
return $(scope).find('.box');
},
// we still want to comunite to R
// wheter the box is collapsed or not
getValue: function(el) {
let isCollapsed = $(el).hasClass('collapsed-box');
return {collapsed: isCollapsed}; // this will be a list in R
},
// Just returns the config script:
_getConfigScript: function(el) {
return(
// Starting from the box
$(el)
// We have to look one level up to be able to use the `find` method
.parent()
// Target the script tag for current id
.find("script[data-for='" + el.id + "']")
);
},
// Converts the script content to a JS object
_processConfig: function(el) {
return(
JSON.parse(
this
._getConfigScript(el)
.html()
)
);
},
// user defined binding: update box width
_updateWidth: function(el, o, n) {
// removes old class
$(el).parent().toggleClass("col-sm-" + o);
$(el).parent().addClass("col-sm-" + n);
// trigger resize so that output resize
$(el).trigger('resize');
},
// Input binding default method
setValue: function(el, value) {
let config = this._processConfig(el);
// Only apply change for action update
if (value.action === "update") {
// check whether value.options.width exists
if (value.options.hasOwnProperty("width")) {
// config.width returns the initial width
// value.options.width contains the new width value
// provided in the updateBox2 message output
if (value.options.width !== config.width) {
this._updateWidth(
el,
config.width,
value.options.width
)
// Updating the confing after changing the UI
config.width = value.options.width;
}
}
// other items to update
if (value.options.hasOwnProperty("title")) {
if (value.options.title !== config.title) {
let newTitle;
newTitle = `<h3 class="box-title">${value.options.title}</h3>`
newTitle = $.parseHTML(newTitle);
$(el)
.find(".box-title")
.replaceWith($(newTitle));
config.title = value.options.title;
}
}
// Don’t forget to update the config script attached
// to the card tag at the end of the update condition
// OTHERWISE THE INPUT VALUE WON’T BE MODIFIED
this
._getConfigScript(el)
.replaceWith(
'<script type="application/json" data-for="' +
el.id +
'">' +
JSON.stringify(config) +
'</script>'
);
} else if (value.action === "toggle") {
// if action is toggle
$(el).toggleBox();
}
},
receiveMessage: function(el, data) {
this.setValue(el, data);
$(el).trigger('change');
},
subscribe: function(el, callback) {
$(el).on('click', '[data-widget="collapse"]', function(event) {
setTimeout(function() {
callback();
}, 50);
});
$(el).on('change', function(event) {
setTimeout(function() {
callback();
}, 50);
});
},
unsubscribe: function(el) {
$(el).off('.boxBinding');
}
});
Shiny.inputBindings.register(boxBinding, 'box-input');
$(function() {
// overwrite box animation speed. Putting 500 ms add unnecessary delay for Shiny.
$.AdminLTE.boxWidget.animationSpeed = 10;
});