mirror of
https://github.com/rstudio/shiny.git
synced 2026-01-09 15:08:04 -05:00
7706 lines
258 KiB
JavaScript
7706 lines
258 KiB
JavaScript
/*! shiny 1.12.1.9000 | (c) 2012-2025 Posit Software, PBC. | License: GPL-3 | file LICENSE */
|
|
"use strict";
|
|
(() => {
|
|
var __create = Object.create;
|
|
var __defProp = Object.defineProperty;
|
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
var __getProtoOf = Object.getPrototypeOf;
|
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
var __typeError = (msg) => {
|
|
throw TypeError(msg);
|
|
};
|
|
var __commonJS = (cb, mod) => function __require() {
|
|
return mod || (0, cb[__getOwnPropNames(cb)[0]])((mod = { exports: {} }).exports, mod), mod.exports;
|
|
};
|
|
var __copyProps = (to, from, except, desc) => {
|
|
if (from && typeof from === "object" || typeof from === "function") {
|
|
for (let key of __getOwnPropNames(from))
|
|
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
}
|
|
return to;
|
|
};
|
|
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
// If the importer is in node compatibility mode or this is not an ESM
|
|
// file that has been converted to a CommonJS file using a Babel-
|
|
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
mod
|
|
));
|
|
var __accessCheck = (obj, member, msg) => member.has(obj) || __typeError("Cannot " + msg);
|
|
var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read from private field"), getter ? getter.call(obj) : member.get(obj));
|
|
var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
|
|
var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
|
|
var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
|
|
|
|
// globals:jquery
|
|
var require_jquery = __commonJS({
|
|
"globals:jquery"(exports, module) {
|
|
module.exports = window.jQuery;
|
|
}
|
|
});
|
|
|
|
// srcts/src/initialize/browser.ts
|
|
var import_jquery = __toESM(require_jquery());
|
|
|
|
// srcts/src/utils/browser.ts
|
|
var isQtVal = false;
|
|
var isIEVal = false;
|
|
var versionIE = -1;
|
|
function setIsQt(isQt2) {
|
|
isQtVal = isQt2;
|
|
}
|
|
function setIsIE(isIE2) {
|
|
isIEVal = isIE2;
|
|
}
|
|
function setIEVersion(versionIE_) {
|
|
versionIE = versionIE_;
|
|
}
|
|
function isQt() {
|
|
return isQtVal;
|
|
}
|
|
function isIE() {
|
|
return isIEVal;
|
|
}
|
|
function IEVersion() {
|
|
return versionIE;
|
|
}
|
|
|
|
// srcts/src/utils/userAgent.ts
|
|
var userAgent;
|
|
function setUserAgent(userAgent_) {
|
|
userAgent = userAgent_;
|
|
}
|
|
|
|
// srcts/src/initialize/browser.ts
|
|
function getIEVersion() {
|
|
const msie = userAgent.indexOf("MSIE ");
|
|
if (isIE() && msie > 0) {
|
|
return parseInt(
|
|
userAgent.substring(msie + 5, userAgent.indexOf(".", msie)),
|
|
10
|
|
);
|
|
}
|
|
const trident = userAgent.indexOf("Trident/");
|
|
if (trident > 0) {
|
|
const rv = userAgent.indexOf("rv:");
|
|
return parseInt(
|
|
userAgent.substring(rv + 3, userAgent.indexOf(".", rv)),
|
|
10
|
|
);
|
|
}
|
|
return -1;
|
|
}
|
|
function determineBrowserInfo() {
|
|
if (/\bQt\//.test(userAgent)) {
|
|
(0, import_jquery.default)(document.documentElement).addClass("qt");
|
|
setIsQt(true);
|
|
} else {
|
|
setIsQt(false);
|
|
}
|
|
if (/\bQt/.test(userAgent) && /\bMacintosh/.test(userAgent)) {
|
|
(0, import_jquery.default)(document.documentElement).addClass("qtmac");
|
|
}
|
|
if (/\bQt\/5/.test(userAgent) && /Linux/.test(userAgent)) {
|
|
(0, import_jquery.default)(document.documentElement).addClass("qt5");
|
|
}
|
|
setIsIE(/MSIE|Trident|Edge/.test(userAgent));
|
|
setIEVersion(getIEVersion());
|
|
}
|
|
|
|
// srcts/src/initialize/disableForm.ts
|
|
var import_jquery2 = __toESM(require_jquery());
|
|
function disableFormSubmission() {
|
|
(0, import_jquery2.default)(document).on("submit", "form:not([action])", function(e4) {
|
|
e4.preventDefault();
|
|
});
|
|
}
|
|
|
|
// srcts/src/initialize/history.ts
|
|
var import_jquery3 = __toESM(require_jquery());
|
|
function trackHistory() {
|
|
const origPushState = window.history.pushState;
|
|
window.history.pushState = function(...args) {
|
|
const result = origPushState.apply(this, args);
|
|
(0, import_jquery3.default)(document).trigger("pushstate");
|
|
return result;
|
|
};
|
|
}
|
|
|
|
// srcts/src/shiny/index.ts
|
|
var import_jquery40 = __toESM(require_jquery());
|
|
|
|
// srcts/src/utils/index.ts
|
|
var import_jquery6 = __toESM(require_jquery());
|
|
|
|
// srcts/src/shiny/render.ts
|
|
var import_jquery5 = __toESM(require_jquery());
|
|
|
|
// srcts/src/utils/object.ts
|
|
function hasOwnProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop);
|
|
}
|
|
function hasDefinedProperty(obj, prop) {
|
|
return Object.prototype.hasOwnProperty.call(obj, prop) && obj[prop] !== void 0;
|
|
}
|
|
function ifUndefined(value, alternate) {
|
|
if (value === void 0) return alternate;
|
|
return value;
|
|
}
|
|
function asArray(value) {
|
|
if (value === null || value === void 0) return [];
|
|
if (Array.isArray(value)) return value;
|
|
return [value];
|
|
}
|
|
|
|
// srcts/src/shiny/initedMethods.ts
|
|
var fullShinyObj;
|
|
function setShinyObj(shiny) {
|
|
fullShinyObj = shiny;
|
|
}
|
|
function validateShinyHasBeenSet() {
|
|
if (typeof fullShinyObj === "undefined") {
|
|
throw "Shiny has not finish initialization yet. Please wait for the 'shiny-initialized' event.";
|
|
}
|
|
return fullShinyObj;
|
|
}
|
|
function shinySetInputValue(name, value, opts) {
|
|
validateShinyHasBeenSet().setInputValue(name, value, opts);
|
|
}
|
|
function shinyShinyApp() {
|
|
return validateShinyHasBeenSet().shinyapp;
|
|
}
|
|
function setShinyUser(user) {
|
|
validateShinyHasBeenSet().user = user;
|
|
}
|
|
function shinyForgetLastInputValue(name) {
|
|
validateShinyHasBeenSet().forgetLastInputValue(name);
|
|
}
|
|
async function shinyBindAll(scope) {
|
|
await validateShinyHasBeenSet().bindAll(scope);
|
|
}
|
|
function shinyUnbindAll(scope, includeSelf = false) {
|
|
validateShinyHasBeenSet().unbindAll(scope, includeSelf);
|
|
}
|
|
function shinyInitializeInputs(scope) {
|
|
validateShinyHasBeenSet().initializeInputs(scope);
|
|
}
|
|
async function shinyAppBindOutput(id, binding) {
|
|
await shinyShinyApp().bindOutput(id, binding);
|
|
}
|
|
function shinyAppUnbindOutput(id, binding) {
|
|
return shinyShinyApp().unbindOutput(id, binding);
|
|
}
|
|
function getShinyOnCustomMessage() {
|
|
return validateShinyHasBeenSet().oncustommessage;
|
|
}
|
|
var fileInputBinding;
|
|
function getFileInputBinding() {
|
|
return fileInputBinding;
|
|
}
|
|
function setFileInputBinding(fileInputBinding_) {
|
|
fileInputBinding = fileInputBinding_;
|
|
}
|
|
function getShinyCreateWebsocket() {
|
|
return validateShinyHasBeenSet().createSocket;
|
|
}
|
|
|
|
// srcts/src/time/debounce.ts
|
|
var Debouncer = class {
|
|
constructor(target, func, delayMs) {
|
|
this.target = target;
|
|
this.func = func;
|
|
this.delayMs = delayMs;
|
|
this.timerId = null;
|
|
this.args = null;
|
|
}
|
|
normalCall(...args) {
|
|
this.$clearTimer();
|
|
this.args = args;
|
|
this.timerId = setTimeout(() => {
|
|
if (this.timerId === null) return;
|
|
this.$clearTimer();
|
|
this.$invoke();
|
|
}, this.delayMs);
|
|
}
|
|
immediateCall(...args) {
|
|
this.$clearTimer();
|
|
this.args = args;
|
|
this.$invoke();
|
|
}
|
|
isPending() {
|
|
return this.timerId !== null;
|
|
}
|
|
$clearTimer() {
|
|
if (this.timerId !== null) {
|
|
clearTimeout(this.timerId);
|
|
this.timerId = null;
|
|
}
|
|
}
|
|
$invoke() {
|
|
if (this.args && this.args.length > 0) {
|
|
this.func.apply(this.target, this.args);
|
|
} else {
|
|
this.func.apply(this.target);
|
|
}
|
|
this.args = null;
|
|
}
|
|
};
|
|
function debounce(threshold, func) {
|
|
let timerId = null;
|
|
return function thisFunc(...args) {
|
|
if (timerId !== null) {
|
|
clearTimeout(timerId);
|
|
timerId = null;
|
|
}
|
|
timerId = setTimeout(() => {
|
|
if (timerId === null) return;
|
|
timerId = null;
|
|
func.apply(thisFunc, args);
|
|
}, threshold);
|
|
};
|
|
}
|
|
|
|
// srcts/src/time/invoke.ts
|
|
var Invoker = class {
|
|
constructor(target, func) {
|
|
this.target = target;
|
|
this.func = func;
|
|
}
|
|
// TODO-barret - Don't know how to define the method twice and still have access to "this"
|
|
normalCall(...args) {
|
|
this.func.apply(this.target, args);
|
|
}
|
|
immediateCall(...args) {
|
|
this.func.apply(this.target, args);
|
|
}
|
|
};
|
|
|
|
// srcts/src/time/throttle.ts
|
|
var Throttler = class {
|
|
constructor(target, func, delayMs) {
|
|
this.target = target;
|
|
this.func = func;
|
|
this.delayMs = delayMs;
|
|
this.timerId = null;
|
|
this.args = null;
|
|
}
|
|
// If no timer is currently running, immediately call the function and set the
|
|
// timer; if a timer is running out, just queue up the args for the call when
|
|
// the timer runs out. Later calls during the same timeout will overwrite
|
|
// earlier ones.
|
|
normalCall(...args) {
|
|
this.args = args;
|
|
if (this.timerId === null) {
|
|
this.$invoke();
|
|
}
|
|
}
|
|
// Reset the timer if active and call immediately
|
|
immediateCall(...args) {
|
|
this.$clearTimer();
|
|
this.args = args;
|
|
this.$invoke();
|
|
}
|
|
// Is there a call waiting to send?
|
|
isPending() {
|
|
return this.args !== null;
|
|
}
|
|
$clearTimer() {
|
|
if (this.timerId !== null) {
|
|
clearTimeout(this.timerId);
|
|
this.timerId = null;
|
|
}
|
|
}
|
|
// Invoke the throttled function with the currently-stored args and start the
|
|
// timer.
|
|
$invoke() {
|
|
if (this.args === null) {
|
|
return;
|
|
}
|
|
this.func.apply(this.target, this.args);
|
|
this.args = null;
|
|
this.timerId = setTimeout(() => {
|
|
if (this.timerId === null) return;
|
|
this.$clearTimer();
|
|
if (this.isPending()) {
|
|
this.$invoke();
|
|
}
|
|
}, this.delayMs);
|
|
}
|
|
};
|
|
|
|
// srcts/src/shiny/sendImageSize.ts
|
|
var SendImageSize = class {
|
|
setImageSend(inputBatchSender, doSendImageSize) {
|
|
const sendImageSizeDebouncer = new Debouncer(null, doSendImageSize, 0);
|
|
this.regular = function() {
|
|
sendImageSizeDebouncer.normalCall();
|
|
};
|
|
inputBatchSender.lastChanceCallback.push(function() {
|
|
if (sendImageSizeDebouncer.isPending())
|
|
sendImageSizeDebouncer.immediateCall();
|
|
});
|
|
this.transitioned = debounce(200, this.regular);
|
|
return sendImageSizeDebouncer;
|
|
}
|
|
};
|
|
var sendImageSizeFns = new SendImageSize();
|
|
|
|
// srcts/src/shiny/singletons.ts
|
|
var import_jquery4 = __toESM(require_jquery());
|
|
var reSingleton = /<!--(SHINY.SINGLETON\[([\w]+)\])-->([\s\S]*?)<!--\/\1-->/;
|
|
var reHead = /<head(?:\s[^>]*)?>([\s\S]*?)<\/head>/;
|
|
var knownSingletons = {};
|
|
function renderHtml(html, el, where) {
|
|
const processed = processHtml(html);
|
|
addToHead(processed.head);
|
|
register(processed.singletons);
|
|
switch (where.toLowerCase()) {
|
|
case "replace":
|
|
(0, import_jquery4.default)(el).html(processed.html);
|
|
break;
|
|
case "beforebegin":
|
|
(0, import_jquery4.default)(el).before(processed.html);
|
|
break;
|
|
case "afterbegin":
|
|
(0, import_jquery4.default)(el).prepend(processed.html);
|
|
break;
|
|
case "beforeend":
|
|
(0, import_jquery4.default)(el).append(processed.html);
|
|
break;
|
|
case "afterend":
|
|
(0, import_jquery4.default)(el).after(processed.html);
|
|
break;
|
|
default:
|
|
throw new Error("Unknown where position: " + where);
|
|
}
|
|
return processed;
|
|
}
|
|
function register(s4) {
|
|
import_jquery4.default.extend(knownSingletons, s4);
|
|
}
|
|
function registerNames(s4) {
|
|
if (typeof s4 === "string") {
|
|
knownSingletons[s4] = true;
|
|
} else if (s4 instanceof Array) {
|
|
for (let i5 = 0; i5 < s4.length; i5++) {
|
|
knownSingletons[s4[i5]] = true;
|
|
}
|
|
}
|
|
}
|
|
function addToHead(head) {
|
|
if (head.length > 0) {
|
|
const tempDiv = (0, import_jquery4.default)("<div>" + head + "</div>").get(0);
|
|
const $head = (0, import_jquery4.default)("head");
|
|
while (tempDiv.hasChildNodes()) {
|
|
$head.append(tempDiv.firstChild);
|
|
}
|
|
}
|
|
}
|
|
function processHtml(val) {
|
|
const newSingletons = {};
|
|
let newVal;
|
|
const findNewPayload = function(match, p1, sig, payload) {
|
|
if (knownSingletons[sig] || newSingletons[sig]) return "";
|
|
newSingletons[sig] = true;
|
|
return payload;
|
|
};
|
|
while (true) {
|
|
newVal = val.replace(reSingleton, findNewPayload);
|
|
if (val.length === newVal.length) break;
|
|
val = newVal;
|
|
}
|
|
const heads = [];
|
|
const headAddPayload = function(match, payload) {
|
|
heads.push(payload);
|
|
return "";
|
|
};
|
|
while (true) {
|
|
newVal = val.replace(reHead, headAddPayload);
|
|
if (val.length === newVal.length) break;
|
|
val = newVal;
|
|
}
|
|
return {
|
|
html: val,
|
|
head: heads.join("\n"),
|
|
singletons: newSingletons
|
|
};
|
|
}
|
|
|
|
// srcts/src/shiny/render.ts
|
|
async function renderContentAsync(el, content, where = "replace") {
|
|
if (where === "replace") {
|
|
shinyUnbindAll(el);
|
|
}
|
|
let html = "";
|
|
let dependencies = [];
|
|
if (content === null) {
|
|
html = "";
|
|
} else if (typeof content === "string") {
|
|
html = content;
|
|
} else if (typeof content === "object") {
|
|
html = content.html;
|
|
dependencies = content.deps || [];
|
|
}
|
|
await renderHtmlAsync(html, el, dependencies, where);
|
|
let scope = el;
|
|
if (where === "replace") {
|
|
shinyInitializeInputs(el);
|
|
await shinyBindAll(el);
|
|
} else {
|
|
const $parent = (0, import_jquery5.default)(el).parent();
|
|
if ($parent.length > 0) {
|
|
scope = $parent;
|
|
if (where === "beforeBegin" || where === "afterEnd") {
|
|
const $grandparent = $parent.parent();
|
|
if ($grandparent.length > 0) scope = $grandparent;
|
|
}
|
|
}
|
|
shinyInitializeInputs(scope);
|
|
await shinyBindAll(scope);
|
|
}
|
|
}
|
|
function renderContent(el, content, where = "replace") {
|
|
if (where === "replace") {
|
|
shinyUnbindAll(el);
|
|
}
|
|
let html = "";
|
|
let dependencies = [];
|
|
if (content === null) {
|
|
html = "";
|
|
} else if (typeof content === "string") {
|
|
html = content;
|
|
} else if (typeof content === "object") {
|
|
html = content.html;
|
|
dependencies = content.deps || [];
|
|
}
|
|
renderHtml2(html, el, dependencies, where);
|
|
let scope = el;
|
|
if (where === "replace") {
|
|
shinyInitializeInputs(el);
|
|
return shinyBindAll(el);
|
|
} else {
|
|
const $parent = (0, import_jquery5.default)(el).parent();
|
|
if ($parent.length > 0) {
|
|
scope = $parent;
|
|
if (where === "beforeBegin" || where === "afterEnd") {
|
|
const $grandparent = $parent.parent();
|
|
if ($grandparent.length > 0) scope = $grandparent;
|
|
}
|
|
}
|
|
shinyInitializeInputs(scope);
|
|
return shinyBindAll(scope);
|
|
}
|
|
}
|
|
async function renderHtmlAsync(html, el, dependencies, where = "replace") {
|
|
await renderDependenciesAsync(dependencies);
|
|
return renderHtml(html, el, where);
|
|
}
|
|
function renderHtml2(html, el, dependencies, where = "replace") {
|
|
renderDependencies(dependencies);
|
|
return renderHtml(html, el, where);
|
|
}
|
|
async function renderDependenciesAsync(dependencies) {
|
|
if (dependencies) {
|
|
for (const dep of dependencies) {
|
|
await renderDependencyAsync(dep);
|
|
}
|
|
}
|
|
}
|
|
function renderDependencies(dependencies) {
|
|
if (dependencies) {
|
|
for (const dep of dependencies) {
|
|
renderDependency(dep);
|
|
}
|
|
}
|
|
}
|
|
var htmlDependencies = {};
|
|
function registerDependency(name, version) {
|
|
htmlDependencies[name] = version;
|
|
}
|
|
function needsRestyle(dep) {
|
|
if (!dep.restyle) {
|
|
return false;
|
|
}
|
|
const names = Object.keys(htmlDependencies);
|
|
const idx = names.indexOf(dep.name);
|
|
if (idx === -1) {
|
|
return false;
|
|
}
|
|
return htmlDependencies[names[idx]] === dep.version;
|
|
}
|
|
function addStylesheetsAndRestyle(links) {
|
|
const $head = (0, import_jquery5.default)("head").first();
|
|
const refreshStyle = function(href, oldSheet) {
|
|
const xhr = new XMLHttpRequest();
|
|
xhr.open("GET", href);
|
|
xhr.onload = function() {
|
|
const id = "shiny_restyle_" + href.split("?restyle")[0].replace(/\W/g, "_");
|
|
const oldStyle = $head.find("style#" + id);
|
|
const newStyle = (0, import_jquery5.default)("<style>").attr("id", id).html(xhr.responseText);
|
|
$head.append(newStyle);
|
|
oldStyle.remove();
|
|
removeSheet(oldSheet);
|
|
sendImageSizeFns.transitioned();
|
|
};
|
|
xhr.send();
|
|
};
|
|
const findSheet = function(href) {
|
|
if (!href) return null;
|
|
for (let i5 = 0; i5 < document.styleSheets.length; i5++) {
|
|
const sheet = document.styleSheets[i5];
|
|
if (typeof sheet.href === "string" && sheet.href.indexOf(href) > -1) {
|
|
return sheet;
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
const removeSheet = function(sheet) {
|
|
if (!sheet) return;
|
|
sheet.disabled = true;
|
|
if (isIE()) sheet.cssText = "";
|
|
if (sheet.ownerNode instanceof Element) {
|
|
(0, import_jquery5.default)(sheet.ownerNode).remove();
|
|
}
|
|
};
|
|
links.map((link) => {
|
|
const $link = (0, import_jquery5.default)(link);
|
|
const oldSheet = findSheet($link.attr("href"));
|
|
const href = $link.attr("href") + "?restyle=" + (/* @__PURE__ */ new Date()).getTime();
|
|
if (isIE()) {
|
|
refreshStyle(href, oldSheet);
|
|
} else {
|
|
$link.attr("href", href);
|
|
$link.attr("onload", () => {
|
|
const $dummyEl = (0, import_jquery5.default)("<div>").css("transition", "0.1s all").css("position", "absolute").css("top", "-1000px").css("left", "0");
|
|
$dummyEl.one("transitionend", () => {
|
|
$dummyEl.remove();
|
|
removeSheet(oldSheet);
|
|
sendImageSizeFns.transitioned();
|
|
});
|
|
(0, import_jquery5.default)(document.body).append($dummyEl);
|
|
const color = "#" + Math.floor(Math.random() * 16777215).toString(16);
|
|
setTimeout(() => $dummyEl.css("color", color), 10);
|
|
});
|
|
$head.append(link);
|
|
}
|
|
});
|
|
}
|
|
function getStylesheetLinkTags(dep) {
|
|
return dep.stylesheet.map((x2) => {
|
|
if (x2.rel === void 0) x2.rel = "stylesheet";
|
|
if (x2.type === void 0) x2.type = "text/css";
|
|
const link = document.createElement("link");
|
|
Object.entries(x2).forEach(function([attr, val]) {
|
|
if (attr === "href") {
|
|
val = encodeURI(val);
|
|
}
|
|
link.setAttribute(attr, val ? val : "");
|
|
});
|
|
return link;
|
|
});
|
|
}
|
|
function appendStylesheetLinkTags(dep, $head) {
|
|
const stylesheetLinks = getStylesheetLinkTags(dep);
|
|
if (stylesheetLinks.length !== 0) {
|
|
$head.append(stylesheetLinks);
|
|
}
|
|
}
|
|
function appendScriptTags(dep, $head) {
|
|
dep.script.forEach((x2) => {
|
|
const script = document.createElement("script");
|
|
Object.entries(x2).forEach(function([attr, val]) {
|
|
if (attr === "src") {
|
|
val = encodeURI(val);
|
|
}
|
|
script.setAttribute(attr, val ? val : "");
|
|
});
|
|
$head.append(script);
|
|
});
|
|
}
|
|
async function appendScriptTagsAsync(dep) {
|
|
const scriptPromises = [];
|
|
dep.script.forEach((x2) => {
|
|
const script = document.createElement("script");
|
|
if (!hasDefinedProperty(x2, "async")) {
|
|
script.async = false;
|
|
}
|
|
Object.entries(x2).forEach(function([attr, val]) {
|
|
if (attr === "src") {
|
|
val = encodeURI(val);
|
|
}
|
|
script.setAttribute(attr, val ? val : "");
|
|
});
|
|
const p3 = new Promise((resolve, reject) => {
|
|
script.onload = (e4) => {
|
|
resolve(null);
|
|
};
|
|
script.onerror = (e4) => {
|
|
reject(e4);
|
|
};
|
|
});
|
|
scriptPromises.push(p3);
|
|
document.head.append(script);
|
|
});
|
|
await Promise.allSettled(scriptPromises);
|
|
}
|
|
function appendMetaTags(dep, $head) {
|
|
dep.meta.forEach((x2) => {
|
|
const meta = document.createElement("meta");
|
|
for (const [attr, val] of Object.entries(x2)) {
|
|
meta.setAttribute(attr, val);
|
|
}
|
|
$head.append(meta);
|
|
});
|
|
}
|
|
function appendAttachmentLinkTags(dep, $head) {
|
|
dep.attachment.forEach((x2) => {
|
|
const link = (0, import_jquery5.default)("<link rel='attachment'>").attr("id", dep.name + "-" + x2.key + "-attachment").attr("href", encodeURI(x2.href));
|
|
$head.append(link);
|
|
});
|
|
}
|
|
function appendExtraHeadContent(dep, $head) {
|
|
if (dep.head) {
|
|
const $newHead = (0, import_jquery5.default)("<head></head>");
|
|
$newHead.html(dep.head);
|
|
$head.append($newHead.children());
|
|
}
|
|
}
|
|
async function renderDependencyAsync(dep_) {
|
|
const dep = normalizeHtmlDependency(dep_);
|
|
if (needsRestyle(dep)) {
|
|
addStylesheetsAndRestyle(getStylesheetLinkTags(dep));
|
|
return true;
|
|
}
|
|
if (hasDefinedProperty(htmlDependencies, dep.name)) return false;
|
|
registerDependency(dep.name, dep.version);
|
|
const $head = (0, import_jquery5.default)("head").first();
|
|
appendMetaTags(dep, $head);
|
|
appendStylesheetLinkTags(dep, $head);
|
|
await appendScriptTagsAsync(dep);
|
|
appendAttachmentLinkTags(dep, $head);
|
|
appendExtraHeadContent(dep, $head);
|
|
return true;
|
|
}
|
|
function renderDependency(dep_) {
|
|
const dep = normalizeHtmlDependency(dep_);
|
|
if (needsRestyle(dep)) {
|
|
addStylesheetsAndRestyle(getStylesheetLinkTags(dep));
|
|
return true;
|
|
}
|
|
if (hasDefinedProperty(htmlDependencies, dep.name)) return false;
|
|
registerDependency(dep.name, dep.version);
|
|
const $head = (0, import_jquery5.default)("head").first();
|
|
appendMetaTags(dep, $head);
|
|
appendStylesheetLinkTags(dep, $head);
|
|
appendScriptTags(dep, $head);
|
|
appendAttachmentLinkTags(dep, $head);
|
|
appendExtraHeadContent(dep, $head);
|
|
return true;
|
|
}
|
|
function normalizeHtmlDependency(dep) {
|
|
const hrefPrefix = dep.src?.href;
|
|
const result = {
|
|
name: dep.name,
|
|
version: dep.version,
|
|
restyle: dep.restyle,
|
|
meta: [],
|
|
stylesheet: [],
|
|
script: [],
|
|
attachment: [],
|
|
head: dep.head
|
|
};
|
|
if (dep.meta) {
|
|
if (Array.isArray(dep.meta)) {
|
|
result.meta = dep.meta;
|
|
} else {
|
|
result.meta = Object.entries(dep.meta).map(function([attr, val]) {
|
|
return { name: attr, content: val };
|
|
});
|
|
}
|
|
}
|
|
result.stylesheet = asArray(dep.stylesheet).map((s4) => {
|
|
if (typeof s4 === "string") {
|
|
s4 = { href: s4 };
|
|
}
|
|
if (hrefPrefix) {
|
|
s4.href = hrefPrefix + "/" + s4.href;
|
|
}
|
|
return s4;
|
|
});
|
|
result.script = asArray(dep.script).map((s4) => {
|
|
if (typeof s4 === "string") {
|
|
s4 = { src: s4 };
|
|
}
|
|
if (hrefPrefix) {
|
|
s4.src = hrefPrefix + "/" + s4.src;
|
|
}
|
|
return s4;
|
|
});
|
|
let attachments = dep.attachment;
|
|
if (!attachments) attachments = [];
|
|
if (typeof attachments === "string") attachments = [attachments];
|
|
if (Array.isArray(attachments)) {
|
|
const tmp = attachments;
|
|
attachments = tmp.map((attachment, index) => {
|
|
if (typeof attachment === "string") {
|
|
return {
|
|
key: (index + 1).toString(),
|
|
href: attachment
|
|
};
|
|
} else {
|
|
return attachment;
|
|
}
|
|
});
|
|
} else {
|
|
attachments = Object.entries(attachments).map(function([attr, val]) {
|
|
return { key: attr, href: val };
|
|
});
|
|
}
|
|
result.attachment = attachments.map((s4) => {
|
|
if (hrefPrefix) {
|
|
s4.href = hrefPrefix + "/" + s4.href;
|
|
}
|
|
return s4;
|
|
});
|
|
return result;
|
|
}
|
|
|
|
// srcts/src/window/pixelRatio.ts
|
|
function windowDevicePixelRatio() {
|
|
return window.devicePixelRatio;
|
|
}
|
|
|
|
// srcts/src/utils/index.ts
|
|
function escapeHTML(str) {
|
|
const escaped = {
|
|
"&": "&",
|
|
"<": "<",
|
|
">": ">",
|
|
'"': """,
|
|
"'": "'",
|
|
"/": "/"
|
|
};
|
|
return str.replace(/[&<>'"/]/g, function(m2) {
|
|
return escaped[m2];
|
|
});
|
|
}
|
|
function randomId() {
|
|
return Math.floor(4294967296 + Math.random() * 64424509440).toString(16);
|
|
}
|
|
function strToBool(str) {
|
|
if (!str || !str.toLowerCase) return void 0;
|
|
switch (str.toLowerCase()) {
|
|
case "true":
|
|
return true;
|
|
case "false":
|
|
return false;
|
|
default:
|
|
return void 0;
|
|
}
|
|
}
|
|
function getStyle(el, styleProp) {
|
|
let x2 = void 0;
|
|
if ("currentStyle" in el) {
|
|
x2 = el.currentStyle[styleProp];
|
|
} else {
|
|
const style = document?.defaultView?.getComputedStyle(el, null);
|
|
if (style) x2 = style.getPropertyValue(styleProp);
|
|
}
|
|
return x2;
|
|
}
|
|
function padZeros(n4, digits) {
|
|
let str = n4.toString();
|
|
while (str.length < digits) str = "0" + str;
|
|
return str;
|
|
}
|
|
function roundSignif(x2, digits = 1) {
|
|
if (digits < 1) throw "Significant digits must be at least 1.";
|
|
return parseFloat(x2.toPrecision(digits));
|
|
}
|
|
function parseDate(dateString) {
|
|
let date = new Date(dateString);
|
|
if (date.toString() === "Invalid Date") {
|
|
date = new Date(dateString.replace(/-/g, "/"));
|
|
}
|
|
return date;
|
|
}
|
|
function formatDateUTC(date) {
|
|
if (date instanceof Date) {
|
|
return date.getUTCFullYear() + "-" + padZeros(date.getUTCMonth() + 1, 2) + "-" + padZeros(date.getUTCDate(), 2);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
function makeResizeFilter(el, func) {
|
|
let lastSize = {};
|
|
return function() {
|
|
const rect = el.getBoundingClientRect();
|
|
const size = { w: rect.width, h: rect.height };
|
|
if (size.w === 0 && size.h === 0) return;
|
|
if (size.w === lastSize.w && size.h === lastSize.h) return;
|
|
lastSize = size;
|
|
func(size.w, size.h);
|
|
};
|
|
}
|
|
function pixelRatio() {
|
|
if (windowDevicePixelRatio()) {
|
|
return Math.round(windowDevicePixelRatio() * 100) / 100;
|
|
} else {
|
|
return 1;
|
|
}
|
|
}
|
|
function getBoundingClientSizeBeforeZoom(el) {
|
|
const rect = el.getBoundingClientRect();
|
|
const zoom = el.currentCSSZoom || 1;
|
|
return {
|
|
width: rect.width / zoom,
|
|
height: rect.height / zoom
|
|
};
|
|
}
|
|
function scopeExprToFunc(expr) {
|
|
const exprEscaped = expr.replace(/[\\"']/g, "\\$&").replace(/\u0000/g, "\\0").replace(/\n/g, "\\n").replace(/\r/g, "\\r").replace(/[\b]/g, "\\b");
|
|
let func;
|
|
try {
|
|
func = new Function(
|
|
`with (this) {
|
|
try {
|
|
return (${expr});
|
|
} catch (e) {
|
|
console.error('Error evaluating expression: ${exprEscaped}');
|
|
throw e;
|
|
}
|
|
}`
|
|
);
|
|
} catch (e4) {
|
|
console.error("Error parsing expression: " + expr);
|
|
throw e4;
|
|
}
|
|
return function(scope) {
|
|
return func.call(scope);
|
|
};
|
|
}
|
|
function mergeSort(list, sortfunc) {
|
|
function merge(a3, b3) {
|
|
let ia = 0;
|
|
let ib = 0;
|
|
const sorted = [];
|
|
while (ia < a3.length && ib < b3.length) {
|
|
if (Number(sortfunc(a3[ia], b3[ib])) <= 0) {
|
|
sorted.push(a3[ia++]);
|
|
} else {
|
|
sorted.push(b3[ib++]);
|
|
}
|
|
}
|
|
while (ia < a3.length) sorted.push(a3[ia++]);
|
|
while (ib < b3.length) sorted.push(b3[ib++]);
|
|
return sorted;
|
|
}
|
|
list = list.slice(0);
|
|
for (let chunkSize = 1; chunkSize < list.length; chunkSize *= 2) {
|
|
for (let i5 = 0; i5 < list.length; i5 += chunkSize * 2) {
|
|
const listA = list.slice(i5, i5 + chunkSize);
|
|
const listB = list.slice(i5 + chunkSize, i5 + chunkSize * 2);
|
|
const merged = merge(listA, listB);
|
|
const args = [i5, merged.length];
|
|
Array.prototype.push.apply(args, merged);
|
|
Array.prototype.splice.apply(list, args);
|
|
}
|
|
}
|
|
return list;
|
|
}
|
|
function $escape(val) {
|
|
if (typeof val === "undefined") return val;
|
|
return val.replace(/([!"#$%&'()*+,./:;<=>?@[\\\]^`{|}~])/g, "\\$1");
|
|
}
|
|
function mapValues(obj, f3) {
|
|
const newObj = {};
|
|
Object.keys(obj).forEach((key) => {
|
|
newObj[key] = f3(obj[key], key, obj);
|
|
});
|
|
return newObj;
|
|
}
|
|
function isnan(x2) {
|
|
return typeof x2 === "number" && isNaN(x2);
|
|
}
|
|
function _equal(x2, y3) {
|
|
if (import_jquery6.default.type(x2) === "object" && import_jquery6.default.type(y3) === "object") {
|
|
const xo = x2;
|
|
const yo = y3;
|
|
if (Object.keys(xo).length !== Object.keys(yo).length) return false;
|
|
for (const prop in xo) {
|
|
if (!hasOwnProperty(yo, prop) || !_equal(xo[prop], yo[prop]))
|
|
return false;
|
|
}
|
|
return true;
|
|
} else if (import_jquery6.default.type(x2) === "array" && import_jquery6.default.type(y3) === "array") {
|
|
const xa = x2;
|
|
const ya = y3;
|
|
if (xa.length !== ya.length) return false;
|
|
for (let i5 = 0; i5 < xa.length; i5++) if (!_equal(xa[i5], ya[i5])) return false;
|
|
return true;
|
|
} else {
|
|
return x2 === y3;
|
|
}
|
|
}
|
|
function equal(...args) {
|
|
if (args.length < 2)
|
|
throw new Error("equal requires at least two arguments.");
|
|
for (let i5 = 0; i5 < args.length - 1; i5++) {
|
|
if (!_equal(args[i5], args[i5 + 1])) return false;
|
|
}
|
|
return true;
|
|
}
|
|
var compareVersion = function(a3, op, b3) {
|
|
function versionParts(ver) {
|
|
return (ver + "").replace(/-/, ".").replace(/(\.0)+[^.]*$/, "").split(".");
|
|
}
|
|
function cmpVersion(a4, b4) {
|
|
const aParts = versionParts(a4);
|
|
const bParts = versionParts(b4);
|
|
const len = Math.min(aParts.length, bParts.length);
|
|
let cmp;
|
|
for (let i5 = 0; i5 < len; i5++) {
|
|
cmp = parseInt(aParts[i5], 10) - parseInt(bParts[i5], 10);
|
|
if (cmp !== 0) {
|
|
return cmp;
|
|
}
|
|
}
|
|
return aParts.length - bParts.length;
|
|
}
|
|
const diff = cmpVersion(a3, b3);
|
|
if (op === "==") return diff === 0;
|
|
else if (op === ">=") return diff >= 0;
|
|
else if (op === ">") return diff > 0;
|
|
else if (op === "<=") return diff <= 0;
|
|
else if (op === "<") return diff < 0;
|
|
else throw `Unknown operator: ${op}`;
|
|
};
|
|
async function updateLabel(labelContent, labelNode) {
|
|
if (typeof labelContent === "undefined") return;
|
|
if (labelNode.length !== 1) {
|
|
throw new Error("labelNode must be of length 1");
|
|
}
|
|
if (typeof labelContent === "string") {
|
|
labelContent = {
|
|
html: labelContent,
|
|
deps: []
|
|
};
|
|
}
|
|
if (labelContent.html === "") {
|
|
labelNode.addClass("shiny-label-null");
|
|
} else {
|
|
await renderContent(labelNode, labelContent);
|
|
labelNode.removeClass("shiny-label-null");
|
|
}
|
|
}
|
|
function getComputedLinkColor(el) {
|
|
const a3 = document.createElement("a");
|
|
a3.href = "/";
|
|
const div = document.createElement("div");
|
|
div.style.setProperty("position", "absolute", "important");
|
|
div.style.setProperty("top", "-1000px", "important");
|
|
div.style.setProperty("left", "0", "important");
|
|
div.style.setProperty("width", "30px", "important");
|
|
div.style.setProperty("height", "10px", "important");
|
|
div.appendChild(a3);
|
|
el.appendChild(div);
|
|
const linkColor = window.getComputedStyle(a3).getPropertyValue("color");
|
|
el.removeChild(div);
|
|
return linkColor;
|
|
}
|
|
function isBS3() {
|
|
return !window.bootstrap;
|
|
}
|
|
function isShinyInDevMode() {
|
|
if ("__SHINY_DEV_MODE__" in window) return Boolean(window.__SHINY_DEV_MODE__);
|
|
return false;
|
|
}
|
|
|
|
// srcts/src/bindings/registry.ts
|
|
var BindingRegistry = class {
|
|
constructor() {
|
|
this.bindings = [];
|
|
this.bindingNames = {};
|
|
}
|
|
register(binding, bindingName, priority = 0) {
|
|
const bindingObj = { binding, priority };
|
|
this.bindings.unshift(bindingObj);
|
|
if (bindingName) {
|
|
this.bindingNames[bindingName] = bindingObj;
|
|
binding.name = bindingName;
|
|
}
|
|
}
|
|
setPriority(bindingName, priority) {
|
|
const bindingObj = this.bindingNames[bindingName];
|
|
if (!bindingObj)
|
|
throw "Tried to set priority on unknown binding " + bindingName;
|
|
bindingObj.priority = priority || 0;
|
|
}
|
|
getPriority(bindingName) {
|
|
const bindingObj = this.bindingNames[bindingName];
|
|
if (!bindingObj) return false;
|
|
return bindingObj.priority;
|
|
}
|
|
getBindings() {
|
|
return mergeSort(this.bindings, function(a3, b3) {
|
|
return b3.priority - a3.priority;
|
|
});
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/inputBinding.ts
|
|
var InputBinding = class {
|
|
// Returns a jQuery object or element array that contains the
|
|
// descendants of scope that match this binding
|
|
find(scope) {
|
|
throw "Not implemented";
|
|
scope;
|
|
}
|
|
getId(el) {
|
|
return el.getAttribute("data-input-id") || el.id;
|
|
}
|
|
// Gives the input a type in case the server needs to know it
|
|
// to deserialize the JSON correctly
|
|
getType(el) {
|
|
return null;
|
|
el;
|
|
}
|
|
getValue(el) {
|
|
throw "Not implemented";
|
|
el;
|
|
}
|
|
subscribe(el, callback) {
|
|
return;
|
|
el;
|
|
callback;
|
|
}
|
|
unsubscribe(el) {
|
|
return;
|
|
el;
|
|
}
|
|
// This is used for receiving messages that tell the input object to do
|
|
// things, such as setting values (including min, max, and others).
|
|
// 'data' should be an object with elements corresponding to value, min,
|
|
// max, etc., as appropriate for the type of input object. It also should
|
|
// trigger a change event.
|
|
receiveMessage(el, data) {
|
|
throw "Not implemented";
|
|
el;
|
|
data;
|
|
}
|
|
getState(el) {
|
|
throw "Not implemented";
|
|
el;
|
|
}
|
|
getRatePolicy(el) {
|
|
return null;
|
|
el;
|
|
}
|
|
// Some input objects need initialization before being bound. This is
|
|
// called when the document is ready (for statically-added input objects),
|
|
// and when new input objects are added to the document with
|
|
// htmlOutputBinding.renderValue() (for dynamically-added input objects).
|
|
// This is called before the input is bound.
|
|
initialize(el) {
|
|
return;
|
|
el;
|
|
}
|
|
// This is called after unbinding the output.
|
|
dispose(el) {
|
|
return;
|
|
el;
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/actionbutton.ts
|
|
var import_jquery7 = __toESM(require_jquery());
|
|
var ActionButtonInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery7.default)(scope).find(".action-button");
|
|
}
|
|
getValue(el) {
|
|
return (0, import_jquery7.default)(el).data("val") || 0;
|
|
}
|
|
setValue(el, value) {
|
|
(0, import_jquery7.default)(el).data("val", value);
|
|
}
|
|
getType(el) {
|
|
return "shiny.action";
|
|
el;
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery7.default)(el).on(
|
|
"click.actionButtonInputBinding",
|
|
// e: Event
|
|
function() {
|
|
const $el = (0, import_jquery7.default)(this);
|
|
const val = $el.data("val") || 0;
|
|
$el.data("val", val + 1);
|
|
callback(false);
|
|
}
|
|
);
|
|
}
|
|
getState(el) {
|
|
return { value: this.getValue(el) };
|
|
}
|
|
async receiveMessage(el, data) {
|
|
if (hasDefinedProperty(data, "icon")) {
|
|
let iconContainer = el.querySelector(
|
|
":scope > .action-icon"
|
|
);
|
|
if (!iconContainer) {
|
|
iconContainer = document.createElement("span");
|
|
iconContainer.className = "action-icon";
|
|
el.prepend(iconContainer);
|
|
}
|
|
await renderContent(iconContainer, data.icon);
|
|
}
|
|
if (hasDefinedProperty(data, "label")) {
|
|
let labelContainer = el.querySelector(
|
|
":scope > .action-label"
|
|
);
|
|
if (!labelContainer) {
|
|
labelContainer = document.createElement("span");
|
|
labelContainer.className = "action-label";
|
|
el.appendChild(labelContainer);
|
|
}
|
|
await renderContent(labelContainer, data.label);
|
|
}
|
|
if (hasDefinedProperty(data, "disabled")) {
|
|
if (data.disabled) {
|
|
el.setAttribute("disabled", "");
|
|
} else {
|
|
el.removeAttribute("disabled");
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery7.default)(el).off(".actionButtonInputBinding");
|
|
}
|
|
};
|
|
(0, import_jquery7.default)(document).on("click", "a.action-button", function(e4) {
|
|
e4.preventDefault();
|
|
});
|
|
|
|
// srcts/src/bindings/input/checkbox.ts
|
|
var import_jquery8 = __toESM(require_jquery());
|
|
var CheckboxInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery8.default)(scope).find('input[type="checkbox"]');
|
|
}
|
|
getValue(el) {
|
|
return el.checked;
|
|
}
|
|
setValue(el, value) {
|
|
el.checked = value;
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery8.default)(el).on("change.checkboxInputBinding", function() {
|
|
callback(true);
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery8.default)(el).off(".checkboxInputBinding");
|
|
}
|
|
getState(el) {
|
|
return {
|
|
label: (0, import_jquery8.default)(el).parent().find("span").text(),
|
|
value: el.checked
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
if (hasDefinedProperty(data, "value")) {
|
|
el.checked = data.value;
|
|
}
|
|
if (hasDefinedProperty(data, "label")) {
|
|
const labelSpan = (0, import_jquery8.default)(el).parent().find("span");
|
|
await renderContent(labelSpan, data.label);
|
|
}
|
|
(0, import_jquery8.default)(el).trigger("change");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/checkboxgroup.ts
|
|
var import_jquery9 = __toESM(require_jquery());
|
|
function getLabelNode(el) {
|
|
return (0, import_jquery9.default)(el).find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
function getLabel(obj) {
|
|
const parentNode = obj.parentNode;
|
|
if (parentNode.tagName === "LABEL") {
|
|
return (0, import_jquery9.default)(parentNode).find("span").text().trim();
|
|
}
|
|
return null;
|
|
}
|
|
var CheckboxGroupInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery9.default)(scope).find(".shiny-input-checkboxgroup");
|
|
}
|
|
getValue(el) {
|
|
const $objs = (0, import_jquery9.default)('input:checkbox[name="' + $escape(el.id) + '"]:checked');
|
|
const values = new Array($objs.length);
|
|
for (let i5 = 0; i5 < $objs.length; i5++) {
|
|
values[i5] = $objs[i5].value;
|
|
}
|
|
return values;
|
|
}
|
|
setValue(el, value) {
|
|
value = value ?? [];
|
|
(0, import_jquery9.default)('input:checkbox[name="' + $escape(el.id) + '"]').prop("checked", false);
|
|
if (value instanceof Array) {
|
|
for (let i5 = 0; i5 < value.length; i5++) {
|
|
(0, import_jquery9.default)(
|
|
'input:checkbox[name="' + $escape(el.id) + '"][value="' + $escape(value[i5]) + '"]'
|
|
).prop("checked", true);
|
|
}
|
|
} else {
|
|
(0, import_jquery9.default)(
|
|
'input:checkbox[name="' + $escape(el.id) + '"][value="' + $escape(value) + '"]'
|
|
).prop("checked", true);
|
|
}
|
|
}
|
|
getState(el) {
|
|
const $objs = (0, import_jquery9.default)(
|
|
'input:checkbox[name="' + $escape(el.id) + '"]'
|
|
);
|
|
const options = new Array($objs.length);
|
|
for (let i5 = 0; i5 < options.length; i5++) {
|
|
options[i5] = { value: $objs[i5].value, label: getLabel($objs[i5]) };
|
|
}
|
|
return {
|
|
label: getLabelNode(el).text(),
|
|
value: this.getValue(el),
|
|
options
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $el = (0, import_jquery9.default)(el);
|
|
if (hasDefinedProperty(data, "options")) {
|
|
$el.find("div.shiny-options-group").remove();
|
|
$el.find("label.checkbox").remove();
|
|
$el.append(data.options);
|
|
}
|
|
if (hasDefinedProperty(data, "value")) {
|
|
this.setValue(el, data.value);
|
|
}
|
|
await updateLabel(data.label, getLabelNode(el));
|
|
(0, import_jquery9.default)(el).trigger("change");
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery9.default)(el).on("change.checkboxGroupInputBinding", function() {
|
|
callback(false);
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery9.default)(el).off(".checkboxGroupInputBinding");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/date.ts
|
|
var import_jquery10 = __toESM(require_jquery());
|
|
var DateInputBindingBase = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery10.default)(scope).find(".shiny-date-input");
|
|
}
|
|
getType(el) {
|
|
return "shiny.date";
|
|
el;
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery10.default)(el).on(
|
|
"changeDate.dateInputBinding change.dateInputBinding",
|
|
// event: Event
|
|
function() {
|
|
callback(false);
|
|
}
|
|
);
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery10.default)(el).off(".dateInputBinding");
|
|
}
|
|
getRatePolicy() {
|
|
return {
|
|
policy: "debounce",
|
|
delay: 250
|
|
};
|
|
}
|
|
setValue(el, data) {
|
|
throw "not implemented";
|
|
el;
|
|
data;
|
|
}
|
|
initialize(el) {
|
|
const $input = (0, import_jquery10.default)(el).find("input");
|
|
let date = $input.data("initial-date");
|
|
if (date === void 0 || date === null) {
|
|
date = this._floorDateTime(this._dateAsUTC(/* @__PURE__ */ new Date()));
|
|
}
|
|
this.setValue(el, date);
|
|
if ($input.data("min-date") !== void 0) {
|
|
this._setMin($input[0], $input.data("min-date"));
|
|
}
|
|
if ($input.data("max-date") !== void 0) {
|
|
this._setMax($input[0], $input.data("max-date"));
|
|
}
|
|
}
|
|
_getLabelNode(el) {
|
|
return (0, import_jquery10.default)(el).find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
// Given a format object from a date picker, return a string
|
|
_formatToString(format) {
|
|
let str = "";
|
|
let i5;
|
|
for (i5 = 0; i5 < format.parts.length; i5++) {
|
|
str += format.separators[i5] + format.parts[i5];
|
|
}
|
|
str += format.separators[i5];
|
|
return str;
|
|
}
|
|
// Given an unambiguous date string or a Date object, set the min (start) date.
|
|
// null will unset. undefined will result in no change,
|
|
_setMin(el, date) {
|
|
if (date === null) {
|
|
(0, import_jquery10.default)(el).bsDatepicker("setStartDate", null);
|
|
return;
|
|
}
|
|
const parsedDate = this._newDate(date);
|
|
if (parsedDate === null) return;
|
|
date = parsedDate;
|
|
if (isNaN(date.valueOf())) return;
|
|
const curValue = (0, import_jquery10.default)(el).bsDatepicker("getUTCDate");
|
|
(0, import_jquery10.default)(el).bsDatepicker("setStartDate", this._utcDateAsLocal(date));
|
|
if (date && curValue && date.getTime() > curValue.getTime()) {
|
|
(0, import_jquery10.default)(el).bsDatepicker("clearDates");
|
|
} else {
|
|
(0, import_jquery10.default)(el).bsDatepicker("setUTCDate", curValue);
|
|
}
|
|
}
|
|
// Given an unambiguous date string or a Date object, set the max (end) date
|
|
// null will unset.
|
|
_setMax(el, date) {
|
|
if (date === null) {
|
|
(0, import_jquery10.default)(el).bsDatepicker("setEndDate", null);
|
|
return;
|
|
}
|
|
const parsedDate = this._newDate(date);
|
|
if (parsedDate === null) return;
|
|
date = parsedDate;
|
|
if (isNaN(date.valueOf())) return;
|
|
const curValue = (0, import_jquery10.default)(el).bsDatepicker("getUTCDate");
|
|
(0, import_jquery10.default)(el).bsDatepicker("setEndDate", this._utcDateAsLocal(date));
|
|
if (date && curValue && date.getTime() < curValue.getTime()) {
|
|
(0, import_jquery10.default)(el).bsDatepicker("clearDates");
|
|
} else {
|
|
(0, import_jquery10.default)(el).bsDatepicker("setUTCDate", curValue);
|
|
}
|
|
}
|
|
// Given a date string of format yyyy-mm-dd, return a Date object with
|
|
// that date at 12AM UTC.
|
|
// If date is a Date object, return it unchanged.
|
|
_newDate(date) {
|
|
if (date instanceof Date) return date;
|
|
if (!date) return null;
|
|
const d3 = parseDate(date);
|
|
if (isNaN(d3.valueOf())) return null;
|
|
return d3;
|
|
}
|
|
// A Date can have any time during a day; this will return a new Date object
|
|
// set to 00:00 in UTC.
|
|
_floorDateTime(date) {
|
|
date = new Date(date.getTime());
|
|
date.setUTCHours(0, 0, 0, 0);
|
|
return date;
|
|
}
|
|
// Given a Date object, return a Date object which has the same "clock time"
|
|
// in UTC. For example, if input date is 2013-02-01 23:00:00 GMT-0600 (CST),
|
|
// output will be 2013-02-01 23:00:00 UTC. Note that the JS console may
|
|
// print this in local time, as "Sat Feb 02 2013 05:00:00 GMT-0600 (CST)".
|
|
_dateAsUTC(date) {
|
|
return new Date(date.getTime() - date.getTimezoneOffset() * 6e4);
|
|
}
|
|
// The inverse of _dateAsUTC. This is needed to adjust time zones because
|
|
// some bootstrap-datepicker methods only take local dates as input, and not
|
|
// UTC.
|
|
_utcDateAsLocal(date) {
|
|
return new Date(date.getTime() + date.getTimezoneOffset() * 6e4);
|
|
}
|
|
};
|
|
var DateInputBinding = class extends DateInputBindingBase {
|
|
// Return the date in an unambiguous format, yyyy-mm-dd (as opposed to a
|
|
// format like mm/dd/yyyy)
|
|
getValue(el) {
|
|
const date = (0, import_jquery10.default)(el).find("input").bsDatepicker("getUTCDate");
|
|
return formatDateUTC(date);
|
|
}
|
|
// value must be an unambiguous string like '2001-01-01', or a Date object.
|
|
setValue(el, value) {
|
|
if (value === null) {
|
|
(0, import_jquery10.default)(el).find("input").val("").bsDatepicker("update");
|
|
return;
|
|
}
|
|
const date = this._newDate(value);
|
|
if (date === null) {
|
|
return;
|
|
}
|
|
if (isNaN(date.valueOf())) return;
|
|
(0, import_jquery10.default)(el).find("input").bsDatepicker("setUTCDate", date);
|
|
}
|
|
getState(el) {
|
|
const $el = (0, import_jquery10.default)(el);
|
|
const $input = $el.find("input");
|
|
let min = $input.data("datepicker").startDate;
|
|
let max = $input.data("datepicker").endDate;
|
|
min = min === -Infinity ? null : formatDateUTC(min);
|
|
max = max === Infinity ? null : formatDateUTC(max);
|
|
let startview = $input.data("datepicker").startViewMode;
|
|
if (startview === 2) startview = "decade";
|
|
else if (startview === 1) startview = "year";
|
|
else if (startview === 0) startview = "month";
|
|
return {
|
|
label: this._getLabelNode(el).text(),
|
|
value: this.getValue(el),
|
|
valueString: $input.val(),
|
|
min,
|
|
max,
|
|
language: $input.data("datepicker").language,
|
|
weekstart: $input.data("datepicker").weekStart,
|
|
format: this._formatToString($input.data("datepicker").format),
|
|
startview
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $input = (0, import_jquery10.default)(el).find("input");
|
|
await updateLabel(data.label, this._getLabelNode(el));
|
|
if (hasDefinedProperty(data, "min")) this._setMin($input[0], data.min);
|
|
if (hasDefinedProperty(data, "max")) this._setMax($input[0], data.max);
|
|
if (hasDefinedProperty(data, "value")) this.setValue(el, data.value);
|
|
(0, import_jquery10.default)(el).trigger("change");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/daterange.ts
|
|
var import_jquery11 = __toESM(require_jquery());
|
|
function getLabelNode2(el) {
|
|
return (0, import_jquery11.default)(el).find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
var DateRangeInputBinding = class extends DateInputBindingBase {
|
|
find(scope) {
|
|
return (0, import_jquery11.default)(scope).find(".shiny-date-range-input");
|
|
}
|
|
// Return the date in an unambiguous format, yyyy-mm-dd (as opposed to a
|
|
// format like mm/dd/yyyy)
|
|
getValue(el) {
|
|
const $inputs = (0, import_jquery11.default)(el).find("input");
|
|
const start = $inputs.eq(0).bsDatepicker("getUTCDate");
|
|
const end = $inputs.eq(1).bsDatepicker("getUTCDate");
|
|
return [formatDateUTC(start), formatDateUTC(end)];
|
|
}
|
|
// value must be an object, with optional fields `start` and `end`. These
|
|
// should be unambiguous strings like '2001-01-01', or Date objects.
|
|
setValue(el, value) {
|
|
if (!(value instanceof Object)) {
|
|
return;
|
|
}
|
|
const $inputs = (0, import_jquery11.default)(el).find("input");
|
|
if (value.start !== void 0) {
|
|
if (value.start === null) {
|
|
$inputs.eq(0).val("").bsDatepicker("update");
|
|
} else {
|
|
const start = this._newDate(value.start);
|
|
$inputs.eq(0).bsDatepicker("setUTCDate", start);
|
|
}
|
|
}
|
|
if (value.end !== void 0) {
|
|
if (value.end === null) {
|
|
$inputs.eq(1).val("").bsDatepicker("update");
|
|
} else {
|
|
const end = this._newDate(value.end);
|
|
$inputs.eq(1).bsDatepicker("setUTCDate", end);
|
|
}
|
|
}
|
|
}
|
|
getState(el) {
|
|
const $el = (0, import_jquery11.default)(el);
|
|
const $inputs = $el.find("input");
|
|
const $startinput = $inputs.eq(0);
|
|
const $endinput = $inputs.eq(1);
|
|
const min = $startinput.bsDatepicker("getStartDate");
|
|
const max = $startinput.bsDatepicker("getEndDate");
|
|
const minStr = min === -Infinity ? null : formatDateUTC(min);
|
|
const maxStr = max === Infinity ? null : formatDateUTC(max);
|
|
let startview = $startinput.data("datepicker").startView;
|
|
if (startview === 2) startview = "decade";
|
|
else if (startview === 1) startview = "year";
|
|
else if (startview === 0) startview = "month";
|
|
return {
|
|
label: getLabelNode2(el).text(),
|
|
value: this.getValue(el),
|
|
valueString: [$startinput.val(), $endinput.val()],
|
|
min: minStr,
|
|
max: maxStr,
|
|
weekstart: $startinput.data("datepicker").weekStart,
|
|
format: this._formatToString($startinput.data("datepicker").format),
|
|
language: $startinput.data("datepicker").language,
|
|
startview
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $el = (0, import_jquery11.default)(el);
|
|
const $inputs = $el.find("input");
|
|
const $startinput = $inputs.eq(0);
|
|
const $endinput = $inputs.eq(1);
|
|
await updateLabel(data.label, getLabelNode2(el));
|
|
if (hasDefinedProperty(data, "min")) {
|
|
this._setMin($startinput[0], data.min);
|
|
this._setMin($endinput[0], data.min);
|
|
}
|
|
if (hasDefinedProperty(data, "max")) {
|
|
this._setMax($startinput[0], data.max);
|
|
this._setMax($endinput[0], data.max);
|
|
}
|
|
if (hasDefinedProperty(data, "value")) {
|
|
this.setValue(el, data.value);
|
|
}
|
|
$el.trigger("change");
|
|
}
|
|
initialize(el) {
|
|
const $el = (0, import_jquery11.default)(el);
|
|
const $inputs = $el.find("input");
|
|
const $startinput = $inputs.eq(0);
|
|
const $endinput = $inputs.eq(1);
|
|
let start = $startinput.data("initial-date");
|
|
let end = $endinput.data("initial-date");
|
|
if (start === void 0 || start === null)
|
|
start = this._dateAsUTC(/* @__PURE__ */ new Date());
|
|
if (end === void 0 || end === null) end = this._dateAsUTC(/* @__PURE__ */ new Date());
|
|
this.setValue(el, { start, end });
|
|
this._setMin($startinput[0], $startinput.data("min-date"));
|
|
this._setMin($endinput[0], $startinput.data("min-date"));
|
|
this._setMax($startinput[0], $endinput.data("max-date"));
|
|
this._setMax($endinput[0], $endinput.data("max-date"));
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery11.default)(el).on(
|
|
"changeDate.dateRangeInputBinding change.dateRangeInputBinding",
|
|
// event: Event
|
|
function() {
|
|
callback(false);
|
|
}
|
|
);
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery11.default)(el).off(".dateRangeInputBinding");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/fileinput.ts
|
|
var import_jquery14 = __toESM(require_jquery());
|
|
|
|
// srcts/src/file/fileProcessor.ts
|
|
var import_jquery13 = __toESM(require_jquery());
|
|
|
|
// srcts/src/events/inputChanged.ts
|
|
var import_jquery12 = __toESM(require_jquery());
|
|
function triggerFileInputChanged(name, value, binding, el, inputType, onEl) {
|
|
const evt = import_jquery12.default.Event("shiny:inputchanged");
|
|
evt.name = name;
|
|
evt.value = value;
|
|
evt.binding = binding;
|
|
evt.el = el;
|
|
evt.inputType = inputType;
|
|
(0, import_jquery12.default)(onEl).trigger(evt);
|
|
return evt;
|
|
}
|
|
|
|
// srcts/src/file/fileProcessor.ts
|
|
var FileProcessor = class {
|
|
constructor(files, exec$run = true) {
|
|
this.fileIndex = -1;
|
|
// Currently need to use small chunk size because R-Websockets can't
|
|
// handle continuation frames
|
|
this.aborted = false;
|
|
this.completed = false;
|
|
this.files = Array.from(files);
|
|
if (exec$run) {
|
|
this.$run();
|
|
}
|
|
}
|
|
// Begin callbacks. Subclassers/cloners may override any or all of these.
|
|
onBegin(files, cont) {
|
|
setTimeout(cont, 0);
|
|
return;
|
|
files;
|
|
}
|
|
onFile(file, cont) {
|
|
setTimeout(cont, 0);
|
|
return;
|
|
file;
|
|
}
|
|
onComplete() {
|
|
return;
|
|
}
|
|
onAbort() {
|
|
return;
|
|
}
|
|
// End callbacks
|
|
// Aborts processing, unless it's already completed
|
|
abort() {
|
|
if (this.completed || this.aborted) return;
|
|
this.aborted = true;
|
|
this.onAbort();
|
|
}
|
|
// Returns a bound function that will call this.$run one time.
|
|
$getRun() {
|
|
let called = false;
|
|
return () => {
|
|
if (called) return;
|
|
called = true;
|
|
this.$run();
|
|
};
|
|
}
|
|
// This function will be called multiple times to advance the process.
|
|
// It relies on the state of the object's fields to know what to do next.
|
|
$run() {
|
|
if (this.aborted || this.completed) return;
|
|
if (this.fileIndex < 0) {
|
|
this.fileIndex = 0;
|
|
this.onBegin(this.files, this.$getRun());
|
|
return;
|
|
}
|
|
if (this.fileIndex === this.files.length) {
|
|
this.completed = true;
|
|
this.onComplete();
|
|
return;
|
|
}
|
|
const file = this.files[this.fileIndex++];
|
|
this.onFile(file, this.$getRun());
|
|
}
|
|
};
|
|
var FileUploader = class extends FileProcessor {
|
|
constructor(shinyapp, id, files, el) {
|
|
super(files, false);
|
|
this.shinyapp = shinyapp;
|
|
this.id = id;
|
|
this.el = el;
|
|
this.$run();
|
|
}
|
|
makeRequest(method, args, onSuccess, onFailure, blobs) {
|
|
this.shinyapp.makeRequest(method, args, onSuccess, onFailure, blobs);
|
|
}
|
|
onBegin(files, cont) {
|
|
this.$setError(null);
|
|
this.$setActive(true);
|
|
this.$setVisible(true);
|
|
this.onProgress(null, 0);
|
|
this.totalBytes = 0;
|
|
this.progressBytes = 0;
|
|
import_jquery13.default.each(files, (i5, file) => {
|
|
this.totalBytes += file.size;
|
|
});
|
|
const fileInfo = import_jquery13.default.map(files, function(file) {
|
|
return {
|
|
name: file.name,
|
|
size: file.size,
|
|
type: file.type
|
|
};
|
|
});
|
|
this.makeRequest(
|
|
"uploadInit",
|
|
[fileInfo],
|
|
(response) => {
|
|
this.jobId = response.jobId;
|
|
this.uploadUrl = response.uploadUrl;
|
|
cont();
|
|
},
|
|
(error) => {
|
|
this.onError(error);
|
|
},
|
|
void 0
|
|
);
|
|
}
|
|
onFile(file, cont) {
|
|
this.onProgress(file, 0);
|
|
import_jquery13.default.ajax(this.uploadUrl, {
|
|
type: "POST",
|
|
cache: false,
|
|
xhr: () => {
|
|
if (typeof import_jquery13.default.ajaxSettings.xhr !== "function")
|
|
throw "jQuery's XHR is not a function";
|
|
const xhrVal = import_jquery13.default.ajaxSettings.xhr();
|
|
if (xhrVal.upload) {
|
|
xhrVal.upload.onprogress = (e4) => {
|
|
if (e4.lengthComputable) {
|
|
this.onProgress(
|
|
file,
|
|
(this.progressBytes + e4.loaded) / this.totalBytes
|
|
);
|
|
}
|
|
};
|
|
}
|
|
return xhrVal;
|
|
},
|
|
data: file,
|
|
contentType: "application/octet-stream",
|
|
processData: false,
|
|
success: () => {
|
|
this.progressBytes += file.size;
|
|
cont();
|
|
},
|
|
error: (jqXHR, textStatus, errorThrown) => {
|
|
this.onError(jqXHR.responseText || textStatus);
|
|
return;
|
|
errorThrown;
|
|
}
|
|
});
|
|
}
|
|
onComplete() {
|
|
const fileInfo = import_jquery13.default.map(this.files, function(file, i5) {
|
|
return {
|
|
name: file.name,
|
|
size: file.size,
|
|
type: file.type
|
|
};
|
|
i5;
|
|
});
|
|
const evt = triggerFileInputChanged(
|
|
this.id,
|
|
fileInfo,
|
|
getFileInputBinding(),
|
|
this.el,
|
|
"shiny.fileupload",
|
|
document
|
|
);
|
|
this.makeRequest(
|
|
"uploadEnd",
|
|
[this.jobId, this.id],
|
|
() => {
|
|
this.$setActive(false);
|
|
this.onProgress(null, 1);
|
|
this.$bar().text("Upload complete");
|
|
(0, import_jquery13.default)(evt.el).val("");
|
|
},
|
|
(error) => {
|
|
this.onError(error);
|
|
},
|
|
void 0
|
|
);
|
|
this.$bar().text("Finishing upload");
|
|
}
|
|
onError(message) {
|
|
this.$setError(message || "");
|
|
this.$setActive(false);
|
|
}
|
|
onAbort() {
|
|
this.$setVisible(false);
|
|
}
|
|
onProgress(file, completed) {
|
|
this.$bar().width(Math.round(completed * 100) + "%");
|
|
this.$bar().text(file ? file.name : "");
|
|
}
|
|
$container() {
|
|
return (0, import_jquery13.default)("#" + $escape(this.id) + "_progress.shiny-file-input-progress");
|
|
}
|
|
$bar() {
|
|
return (0, import_jquery13.default)(
|
|
"#" + $escape(this.id) + "_progress.shiny-file-input-progress .progress-bar"
|
|
);
|
|
}
|
|
$setVisible(visible) {
|
|
this.$container().css("visibility", visible ? "visible" : "hidden");
|
|
}
|
|
$setError(error) {
|
|
this.$bar().toggleClass("progress-bar-danger", error !== null);
|
|
if (error !== null) {
|
|
this.onProgress(null, 1);
|
|
this.$bar().text(error);
|
|
}
|
|
}
|
|
$setActive(active) {
|
|
this.$container().toggleClass("active", !!active);
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/fileinput.ts
|
|
var zoneActive = "shiny-file-input-active";
|
|
var zoneOver = "shiny-file-input-over";
|
|
function zoneOf(el) {
|
|
return (0, import_jquery14.default)(el).closest("div.input-group");
|
|
}
|
|
function enableDraghover(el) {
|
|
const $el = (0, import_jquery14.default)(el);
|
|
let childCounter = 0;
|
|
$el.on({
|
|
"dragenter.draghover": (e4) => {
|
|
if (childCounter++ === 0) {
|
|
$el.trigger("draghover:enter", e4);
|
|
}
|
|
},
|
|
"dragleave.draghover": (e4) => {
|
|
if (--childCounter === 0) {
|
|
$el.trigger("draghover:leave", e4);
|
|
}
|
|
if (childCounter < 0) {
|
|
console.error("draghover childCounter is negative somehow");
|
|
}
|
|
},
|
|
"dragover.draghover": (e4) => {
|
|
e4.preventDefault();
|
|
},
|
|
"drop.draghover": (e4) => {
|
|
childCounter = 0;
|
|
$el.trigger("draghover:drop", e4);
|
|
e4.preventDefault();
|
|
}
|
|
});
|
|
return $el;
|
|
}
|
|
function disableDraghover(el) {
|
|
return (0, import_jquery14.default)(el).off(".draghover");
|
|
}
|
|
function enableDocumentEvents() {
|
|
const $doc = (0, import_jquery14.default)("html");
|
|
enableDraghover($doc).on({
|
|
"draghover:enter.draghover": (
|
|
// e: Event
|
|
() => {
|
|
zoneOf($fileInputs).addClass(zoneActive);
|
|
}
|
|
),
|
|
"draghover:leave.draghover": (
|
|
// e: Event
|
|
() => {
|
|
zoneOf($fileInputs).removeClass(zoneActive);
|
|
}
|
|
),
|
|
"draghover:drop.draghover": (
|
|
// e: Event
|
|
() => {
|
|
zoneOf($fileInputs).removeClass(zoneOver).removeClass(zoneActive);
|
|
}
|
|
)
|
|
});
|
|
}
|
|
function disableDocumentEvents() {
|
|
const $doc = (0, import_jquery14.default)("html");
|
|
$doc.off(".draghover");
|
|
disableDraghover($doc);
|
|
}
|
|
function canSetFiles(fileList) {
|
|
const testEl = document.createElement("input");
|
|
testEl.type = "file";
|
|
try {
|
|
testEl.files = fileList;
|
|
} catch (e4) {
|
|
return false;
|
|
e4;
|
|
}
|
|
return true;
|
|
}
|
|
function handleDrop(e4, el) {
|
|
const files = e4.originalEvent?.dataTransfer?.files, $el = (0, import_jquery14.default)(el);
|
|
if (files === void 0 || files === null) {
|
|
console.log(
|
|
"Dropping files is not supported on this browser. (no FileList)"
|
|
);
|
|
} else if (!canSetFiles(files)) {
|
|
$el.val("");
|
|
uploadDroppedFilesIE10Plus(el, files);
|
|
} else {
|
|
$el.val("");
|
|
el.files = files;
|
|
$el.trigger("change");
|
|
}
|
|
}
|
|
function setFileText($el, files) {
|
|
const $fileText = $el.closest("div.input-group").find("input[type=text]");
|
|
if (files.length === 1) {
|
|
$fileText.val(files[0].name);
|
|
} else {
|
|
$fileText.val(files.length + " files");
|
|
}
|
|
}
|
|
function abortCurrentUpload($el) {
|
|
const uploader = $el.data("currentUploader");
|
|
if (uploader) uploader.abort();
|
|
$el.removeAttr("data-restore");
|
|
}
|
|
function uploadDroppedFilesIE10Plus(el, files) {
|
|
const $el = (0, import_jquery14.default)(el);
|
|
abortCurrentUpload($el);
|
|
setFileText($el, files);
|
|
$el.data(
|
|
"currentUploader",
|
|
new FileUploader(shinyShinyApp(), fileInputBindingGetId(el), files, el)
|
|
);
|
|
}
|
|
function uploadFiles(evt) {
|
|
const $el = (0, import_jquery14.default)(evt.target);
|
|
abortCurrentUpload($el);
|
|
const files = evt.target.files;
|
|
const id = fileInputBindingGetId(evt.target);
|
|
if (files.length === 0) return;
|
|
setFileText($el, files);
|
|
$el.data(
|
|
"currentUploader",
|
|
new FileUploader(shinyShinyApp(), id, files, evt.target)
|
|
);
|
|
}
|
|
var $fileInputs = (0, import_jquery14.default)();
|
|
function fileInputBindingGetId(el) {
|
|
return InputBinding.prototype.getId.call(this, el) || el.name;
|
|
}
|
|
var FileInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery14.default)(scope).find('input[type="file"]');
|
|
}
|
|
getId(el) {
|
|
return fileInputBindingGetId(el);
|
|
}
|
|
getValue(el) {
|
|
const data = (0, import_jquery14.default)(el).attr("data-restore");
|
|
if (data) {
|
|
const dataParsed = JSON.parse(data);
|
|
const $fileText = (0, import_jquery14.default)(el).closest("div.input-group").find("input[type=text]");
|
|
if (dataParsed.name.length === 1) {
|
|
$fileText.val(dataParsed.name[0]);
|
|
} else {
|
|
$fileText.val(dataParsed.name.length + " files");
|
|
}
|
|
const $progress = (0, import_jquery14.default)(el).closest("div.form-group").find(".progress");
|
|
const $bar = $progress.find(".progress-bar");
|
|
$progress.removeClass("active");
|
|
$bar.width("100%");
|
|
$bar.css("visibility", "visible");
|
|
return dataParsed;
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
setValue(el, value) {
|
|
return;
|
|
el;
|
|
value;
|
|
}
|
|
getType(el) {
|
|
return "shiny.file";
|
|
el;
|
|
}
|
|
subscribe(el, callback) {
|
|
callback;
|
|
(0, import_jquery14.default)(el).on("change.fileInputBinding", uploadFiles);
|
|
if ($fileInputs.length === 0) enableDocumentEvents();
|
|
$fileInputs = $fileInputs.add(el);
|
|
const $zone = zoneOf(el);
|
|
enableDraghover($zone).on({
|
|
"draghover:enter.draghover": (e4) => {
|
|
$zone.addClass(zoneOver);
|
|
return;
|
|
e4;
|
|
},
|
|
"draghover:leave.draghover": (e4) => {
|
|
$zone.removeClass(zoneOver);
|
|
e4.stopPropagation();
|
|
},
|
|
"draghover:drop.draghover": (e4, dropEvent) => {
|
|
handleDrop(dropEvent, el);
|
|
return;
|
|
e4;
|
|
}
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
const $el = (0, import_jquery14.default)(el), $zone = zoneOf(el);
|
|
$zone.removeClass(zoneOver).removeClass(zoneActive);
|
|
disableDraghover($zone);
|
|
$el.off(".fileInputBinding");
|
|
$zone.off(".draghover");
|
|
$fileInputs = $fileInputs.not(el);
|
|
if ($fileInputs.length === 0) disableDocumentEvents();
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/number.ts
|
|
var import_jquery16 = __toESM(require_jquery());
|
|
|
|
// srcts/src/bindings/input/text.ts
|
|
var import_jquery15 = __toESM(require_jquery());
|
|
function getLabelNode3(el) {
|
|
return (0, import_jquery15.default)(el).parent().find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
var TextInputBindingBase = class extends InputBinding {
|
|
find(scope) {
|
|
const $inputs = (0, import_jquery15.default)(scope).find(
|
|
'input[type="text"], input[type="search"], input[type="url"], input[type="email"]'
|
|
);
|
|
return $inputs.not('input[type="text"][id$="-selectized"]');
|
|
}
|
|
getId(el) {
|
|
return super.getId(el) || el.name;
|
|
}
|
|
getValue(el) {
|
|
throw "not implemented";
|
|
el;
|
|
}
|
|
setValue(el, value) {
|
|
throw "not implemented";
|
|
el;
|
|
value;
|
|
}
|
|
subscribe(el, callback) {
|
|
const $el = (0, import_jquery15.default)(el);
|
|
const updateOn = $el.data("update-on") || "change";
|
|
if (updateOn === "change") {
|
|
$el.on(
|
|
"keyup.textInputBinding input.textInputBinding",
|
|
// event: Event
|
|
function() {
|
|
callback(true);
|
|
}
|
|
);
|
|
} else if (updateOn === "blur") {
|
|
$el.on("blur.textInputBinding", function() {
|
|
callback(false);
|
|
});
|
|
$el.on("keydown.textInputBinding", function(event) {
|
|
if (event.key !== "Enter") return;
|
|
if ($el.is("textarea")) {
|
|
if (!(event.ctrlKey || event.metaKey)) return;
|
|
}
|
|
callback(false);
|
|
});
|
|
}
|
|
$el.on("change.textInputBinding", function() {
|
|
if (updateOn === "blur" && $el.is(":focus")) {
|
|
return;
|
|
}
|
|
callback(false);
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery15.default)(el).off(".textInputBinding");
|
|
}
|
|
receiveMessage(el, data) {
|
|
throw "not implemented";
|
|
el;
|
|
data;
|
|
}
|
|
getState(el) {
|
|
throw "not implemented";
|
|
el;
|
|
}
|
|
getRatePolicy(el) {
|
|
return {
|
|
policy: "debounce",
|
|
delay: 250
|
|
};
|
|
el;
|
|
}
|
|
};
|
|
var TextInputBinding = class extends TextInputBindingBase {
|
|
setValue(el, value) {
|
|
el.value = value;
|
|
}
|
|
getValue(el) {
|
|
return el.value;
|
|
}
|
|
getState(el) {
|
|
return {
|
|
label: getLabelNode3(el).text(),
|
|
value: el.value,
|
|
placeholder: el.placeholder
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
if (hasDefinedProperty(data, "value")) this.setValue(el, data.value);
|
|
await updateLabel(data.label, getLabelNode3(el));
|
|
if (hasDefinedProperty(data, "placeholder")) {
|
|
el.placeholder = data.placeholder;
|
|
}
|
|
(0, import_jquery15.default)(el).trigger("change");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/number.ts
|
|
function getLabelNode4(el) {
|
|
return (0, import_jquery16.default)(el).parent().find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
var NumberInputBinding = class extends TextInputBindingBase {
|
|
find(scope) {
|
|
return (0, import_jquery16.default)(scope).find('input[type="number"]');
|
|
}
|
|
getValue(el) {
|
|
const numberVal = (0, import_jquery16.default)(el).val();
|
|
if (typeof numberVal == "string") {
|
|
if (/^\s*$/.test(numberVal))
|
|
return null;
|
|
}
|
|
const numberValue = Number(numberVal);
|
|
if (!isNaN(numberValue)) {
|
|
return numberValue;
|
|
}
|
|
return numberVal;
|
|
}
|
|
setValue(el, value) {
|
|
el.value = "" + value;
|
|
}
|
|
getType(el) {
|
|
return "shiny.number";
|
|
el;
|
|
}
|
|
async receiveMessage(el, data) {
|
|
if (hasDefinedProperty(data, "value")) el.value = data.value ?? "";
|
|
if (hasDefinedProperty(data, "min")) el.min = data.min ?? "";
|
|
if (hasDefinedProperty(data, "max")) el.max = data.max ?? "";
|
|
if (hasDefinedProperty(data, "step")) el.step = data.step ?? "";
|
|
await updateLabel(data.label, getLabelNode4(el));
|
|
(0, import_jquery16.default)(el).trigger("change");
|
|
}
|
|
getState(el) {
|
|
return {
|
|
label: getLabelNode4(el).text(),
|
|
value: this.getValue(el),
|
|
min: Number(el.min),
|
|
max: Number(el.max),
|
|
step: Number(el.step)
|
|
};
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/password.ts
|
|
var import_jquery17 = __toESM(require_jquery());
|
|
var PasswordInputBinding = class extends TextInputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery17.default)(scope).find('input[type="password"]');
|
|
}
|
|
getType(el) {
|
|
return "shiny.password";
|
|
el;
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/radio.ts
|
|
var import_jquery18 = __toESM(require_jquery());
|
|
function getLabelNode5(el) {
|
|
return (0, import_jquery18.default)(el).parent().find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
function getLabel2(obj) {
|
|
const parentNode = obj.parentNode;
|
|
if (parentNode.tagName === "LABEL") {
|
|
return (0, import_jquery18.default)(parentNode).find("span").text().trim();
|
|
}
|
|
return null;
|
|
}
|
|
var RadioInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery18.default)(scope).find(".shiny-input-radiogroup");
|
|
}
|
|
getValue(el) {
|
|
const checkedItems = (0, import_jquery18.default)(
|
|
'input:radio[name="' + $escape(el.id) + '"]:checked'
|
|
);
|
|
if (checkedItems.length === 0) {
|
|
return null;
|
|
}
|
|
return checkedItems.val();
|
|
}
|
|
setValue(el, value) {
|
|
if (Array.isArray(value) && value.length === 0) {
|
|
(0, import_jquery18.default)('input:radio[name="' + $escape(el.id) + '"]').prop("checked", false);
|
|
} else {
|
|
(0, import_jquery18.default)(
|
|
'input:radio[name="' + $escape(el.id) + '"][value="' + $escape(value) + '"]'
|
|
).prop("checked", true);
|
|
}
|
|
}
|
|
getState(el) {
|
|
const $objs = (0, import_jquery18.default)(
|
|
'input:radio[name="' + $escape(el.id) + '"]'
|
|
);
|
|
const options = new Array($objs.length);
|
|
for (let i5 = 0; i5 < options.length; i5++) {
|
|
options[i5] = { value: $objs[i5].value, label: getLabel2($objs[i5]) };
|
|
}
|
|
return {
|
|
label: getLabelNode5(el).text(),
|
|
value: this.getValue(el),
|
|
options
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $el = (0, import_jquery18.default)(el);
|
|
if (hasDefinedProperty(data, "options")) {
|
|
$el.find("div.shiny-options-group").remove();
|
|
$el.find("label.radio").remove();
|
|
$el.append(data.options);
|
|
}
|
|
if (hasDefinedProperty(data, "value")) {
|
|
this.setValue(el, data.value);
|
|
}
|
|
await updateLabel(data.label, getLabelNode5(el));
|
|
(0, import_jquery18.default)(el).trigger("change");
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery18.default)(el).on("change.radioInputBinding", function() {
|
|
callback(false);
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery18.default)(el).off(".radioInputBinding");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/selectInput.ts
|
|
var import_jquery19 = __toESM(require_jquery());
|
|
|
|
// srcts/src/utils/eval.ts
|
|
var indirectEval = eval;
|
|
|
|
// srcts/src/bindings/input/selectInput.ts
|
|
function getLabelNode6(el) {
|
|
let escapedId = $escape(el.id);
|
|
if (isSelectize(el)) {
|
|
escapedId += "-selectized";
|
|
}
|
|
return (0, import_jquery19.default)(el).parent().parent().find('label[for="' + escapedId + '"]');
|
|
}
|
|
function isSelectize(el) {
|
|
const config = (0, import_jquery19.default)(el).parent().find('script[data-for="' + $escape(el.id) + '"]');
|
|
return config.length > 0;
|
|
}
|
|
var SelectInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery19.default)(scope).find("select");
|
|
}
|
|
getType(el) {
|
|
const $el = (0, import_jquery19.default)(el);
|
|
if (!$el.hasClass("symbol")) {
|
|
return null;
|
|
}
|
|
if ($el.attr("multiple") === "multiple") {
|
|
return "shiny.symbolList";
|
|
} else {
|
|
return "shiny.symbol";
|
|
}
|
|
}
|
|
getId(el) {
|
|
return InputBinding.prototype.getId.call(this, el) || el.name;
|
|
}
|
|
getValue(el) {
|
|
if (!isSelectize(el)) {
|
|
return (0, import_jquery19.default)(el).val();
|
|
} else {
|
|
const selectize = this._selectize(el);
|
|
return selectize?.getValue();
|
|
}
|
|
}
|
|
setValue(el, value) {
|
|
if (!isSelectize(el)) {
|
|
(0, import_jquery19.default)(el).val(value);
|
|
} else {
|
|
const selectize = this._selectize(el);
|
|
selectize?.setValue(value);
|
|
}
|
|
}
|
|
getState(el) {
|
|
const options = new Array(
|
|
el.length
|
|
);
|
|
for (let i5 = 0; i5 < el.length; i5++) {
|
|
options[i5] = {
|
|
// TODO-barret; Is this a safe assumption?; Are there no Option Groups?
|
|
value: el[i5].value,
|
|
label: el[i5].label
|
|
};
|
|
}
|
|
return {
|
|
label: getLabelNode6(el),
|
|
value: this.getValue(el),
|
|
options
|
|
};
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $el = (0, import_jquery19.default)(el);
|
|
if (hasDefinedProperty(data, "options")) {
|
|
const selectize = this._selectize(el);
|
|
selectize?.destroy();
|
|
$el.empty().append(data.options);
|
|
this._selectize(el);
|
|
}
|
|
if (hasDefinedProperty(data, "config")) {
|
|
$el.parent().find('script[data-for="' + $escape(el.id) + '"]').replaceWith(data.config);
|
|
this._selectize(el, true);
|
|
}
|
|
if (hasDefinedProperty(data, "url")) {
|
|
const selectize = this._selectize(el);
|
|
selectize.clear();
|
|
selectize.clearOptions();
|
|
let loaded = false;
|
|
selectize.settings.load = function(query, callback) {
|
|
const settings = selectize.settings;
|
|
import_jquery19.default.ajax({
|
|
url: data.url,
|
|
data: {
|
|
query,
|
|
field: JSON.stringify([settings.searchField]),
|
|
value: settings.valueField,
|
|
conju: settings.searchConjunction,
|
|
maxop: settings.maxOptions
|
|
},
|
|
type: "GET",
|
|
error: function() {
|
|
callback();
|
|
},
|
|
success: function(res) {
|
|
import_jquery19.default.each(res, function(index, elem) {
|
|
const optgroupId = elem[settings.optgroupField || "optgroup"];
|
|
const optgroup = {};
|
|
optgroup[settings.optgroupLabelField || "label"] = optgroupId;
|
|
optgroup[settings.optgroupValueField || "value"] = optgroupId;
|
|
selectize.addOptionGroup(optgroupId, optgroup);
|
|
});
|
|
callback(res);
|
|
if (!loaded) {
|
|
if (hasDefinedProperty(data, "value")) {
|
|
selectize.setValue(data.value);
|
|
} else if (settings.maxItems === 1) {
|
|
selectize.setValue(res[0].value);
|
|
}
|
|
}
|
|
loaded = true;
|
|
}
|
|
});
|
|
};
|
|
selectize.load(function(callback) {
|
|
selectize.settings.load.apply(selectize, ["", callback]);
|
|
});
|
|
} else if (hasDefinedProperty(data, "value")) {
|
|
this.setValue(el, data.value);
|
|
}
|
|
await updateLabel(data.label, getLabelNode6(el));
|
|
(0, import_jquery19.default)(el).trigger("change");
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery19.default)(el).on(
|
|
"change.selectInputBinding",
|
|
// event: Event
|
|
() => {
|
|
if (el.nonempty && this.getValue(el) === "") {
|
|
return;
|
|
}
|
|
callback(false);
|
|
}
|
|
);
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery19.default)(el).off(".selectInputBinding");
|
|
}
|
|
initialize(el) {
|
|
this._selectize(el);
|
|
}
|
|
_selectize(el, update = false) {
|
|
if (!import_jquery19.default.fn.selectize) return void 0;
|
|
const $el = (0, import_jquery19.default)(el);
|
|
const config = $el.parent().find('script[data-for="' + $escape(el.id) + '"]');
|
|
if (config.length === 0) return void 0;
|
|
let options = import_jquery19.default.extend(
|
|
{
|
|
labelField: "label",
|
|
valueField: "value",
|
|
searchField: ["label"]
|
|
},
|
|
JSON.parse(config.html())
|
|
);
|
|
options = this._addShinyRemoveButton(options, el.hasAttribute("multiple"));
|
|
if (typeof config.data("nonempty") !== "undefined") {
|
|
el.nonempty = true;
|
|
options = import_jquery19.default.extend(options, {
|
|
onItemRemove: function(value) {
|
|
if (this.getValue() === "")
|
|
(0, import_jquery19.default)("select#" + $escape(el.id)).empty().append(
|
|
(0, import_jquery19.default)("<option/>", {
|
|
value,
|
|
selected: true
|
|
})
|
|
).trigger("change");
|
|
},
|
|
onDropdownClose: (
|
|
// $dropdown: any
|
|
function() {
|
|
if (this.getValue() === "") {
|
|
this.setValue((0, import_jquery19.default)("select#" + $escape(el.id)).val());
|
|
}
|
|
}
|
|
)
|
|
});
|
|
} else {
|
|
el.nonempty = false;
|
|
}
|
|
if (config.data("eval") instanceof Array)
|
|
import_jquery19.default.each(config.data("eval"), function(i5, x2) {
|
|
options[x2] = indirectEval("(" + options[x2] + ")");
|
|
});
|
|
let control = $el.selectize(options)[0].selectize;
|
|
if (update) {
|
|
const settings = import_jquery19.default.extend(control.settings, options);
|
|
control.destroy();
|
|
control = $el.selectize(settings)[0].selectize;
|
|
}
|
|
return control;
|
|
}
|
|
// Translate shinyRemoveButton option into selectize plugins
|
|
_addShinyRemoveButton(options, multiple) {
|
|
let removeButton = options.shinyRemoveButton;
|
|
if (removeButton === void 0) {
|
|
return options;
|
|
}
|
|
if (removeButton === "none") {
|
|
removeButton = multiple ? "true" : "false";
|
|
}
|
|
if (removeButton === "false") {
|
|
return options;
|
|
}
|
|
const plugins = [];
|
|
if (removeButton === "both") {
|
|
plugins.push("remove_button", "clear_button");
|
|
} else if (removeButton === "true") {
|
|
plugins.push(multiple ? "remove_button" : "clear_button");
|
|
}
|
|
return {
|
|
...options,
|
|
plugins: Array.from(
|
|
/* @__PURE__ */ new Set([
|
|
...Array.isArray(options.plugins) ? options.plugins : [],
|
|
...plugins
|
|
])
|
|
)
|
|
};
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/slider.ts
|
|
var import_jquery20 = __toESM(require_jquery());
|
|
function forceIonSliderUpdate(slider) {
|
|
if (slider.$cache && slider.$cache.input)
|
|
slider.$cache.input.trigger("change");
|
|
else console.log("Couldn't force ion slider to update");
|
|
}
|
|
function getTypePrettifyer(dataType, timeFormat, timezone) {
|
|
let timeFormatter;
|
|
let prettify;
|
|
if (dataType === "date") {
|
|
timeFormatter = window.strftime.utc();
|
|
prettify = function(num) {
|
|
return timeFormatter(timeFormat, new Date(num));
|
|
};
|
|
} else if (dataType === "datetime") {
|
|
if (timezone) timeFormatter = window.strftime.timezone(timezone);
|
|
else timeFormatter = window.strftime;
|
|
prettify = function(num) {
|
|
return timeFormatter(timeFormat, new Date(num));
|
|
};
|
|
} else {
|
|
prettify = function(num) {
|
|
return formatNumber(num, this.prettify_separator);
|
|
};
|
|
}
|
|
return prettify;
|
|
}
|
|
function getLabelNode7(el) {
|
|
return (0, import_jquery20.default)(el).parent().find('label[for="' + $escape(el.id) + '"]');
|
|
}
|
|
function numValues(el) {
|
|
if ((0, import_jquery20.default)(el).data("ionRangeSlider").options.type === "double") return 2;
|
|
else return 1;
|
|
}
|
|
var SliderInputBinding = class extends TextInputBindingBase {
|
|
find(scope) {
|
|
if (!import_jquery20.default.fn.ionRangeSlider) {
|
|
return (0, import_jquery20.default)();
|
|
}
|
|
return (0, import_jquery20.default)(scope).find("input.js-range-slider");
|
|
}
|
|
getType(el) {
|
|
const dataType = (0, import_jquery20.default)(el).data("data-type");
|
|
if (dataType === "date") return "shiny.date";
|
|
else if (dataType === "datetime") return "shiny.datetime";
|
|
else return null;
|
|
}
|
|
getValue(el) {
|
|
const $el = (0, import_jquery20.default)(el);
|
|
const result = (0, import_jquery20.default)(el).data("ionRangeSlider").result;
|
|
let convert;
|
|
const dataType = $el.data("data-type");
|
|
if (dataType === "date") {
|
|
convert = function(val) {
|
|
return formatDateUTC(new Date(Number(val)));
|
|
};
|
|
} else if (dataType === "datetime") {
|
|
convert = function(val) {
|
|
return Number(val) / 1e3;
|
|
};
|
|
} else {
|
|
convert = function(val) {
|
|
return Number(val);
|
|
};
|
|
}
|
|
if (numValues(el) === 2) {
|
|
return [convert(result.from), convert(result.to)];
|
|
} else {
|
|
return convert(result.from);
|
|
}
|
|
}
|
|
setValue(el, value) {
|
|
const $el = (0, import_jquery20.default)(el);
|
|
const slider = $el.data("ionRangeSlider");
|
|
$el.data("immediate", true);
|
|
try {
|
|
if (numValues(el) === 2 && value instanceof Array) {
|
|
slider.update({ from: value[0], to: value[1] });
|
|
} else {
|
|
slider.update({ from: value });
|
|
}
|
|
forceIonSliderUpdate(slider);
|
|
} finally {
|
|
$el.data("immediate", false);
|
|
}
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery20.default)(el).on("change.sliderInputBinding", function() {
|
|
callback(!(0, import_jquery20.default)(el).data("immediate") && !(0, import_jquery20.default)(el).data("animating"));
|
|
});
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery20.default)(el).off(".sliderInputBinding");
|
|
}
|
|
async receiveMessage(el, data) {
|
|
const $el = (0, import_jquery20.default)(el);
|
|
const slider = $el.data("ionRangeSlider");
|
|
const msg = {};
|
|
if (hasDefinedProperty(data, "value")) {
|
|
if (numValues(el) === 2 && data.value instanceof Array) {
|
|
msg.from = data.value[0];
|
|
msg.to = data.value[1];
|
|
} else {
|
|
if (Array.isArray(data.value)) {
|
|
const errorReason = [
|
|
"an empty array.",
|
|
"a single-value array.",
|
|
"an array with more than two values."
|
|
];
|
|
throw "Slider requires two values to update with an array, but message value was " + errorReason[Math.min(data.value.length, 2)];
|
|
}
|
|
msg.from = data.value;
|
|
}
|
|
}
|
|
const sliderFeatures = [
|
|
"min",
|
|
"max",
|
|
"step"
|
|
];
|
|
for (let i5 = 0; i5 < sliderFeatures.length; i5++) {
|
|
const feats = sliderFeatures[i5];
|
|
if (hasDefinedProperty(data, feats)) {
|
|
msg[feats] = data[feats];
|
|
}
|
|
}
|
|
await updateLabel(data.label, getLabelNode7(el));
|
|
const domElements = [
|
|
"data-type",
|
|
"time-format",
|
|
"timezone"
|
|
];
|
|
for (let i5 = 0; i5 < domElements.length; i5++) {
|
|
const elem = domElements[i5];
|
|
if (hasDefinedProperty(data, elem)) {
|
|
$el.data(elem, data[elem]);
|
|
}
|
|
}
|
|
const dataType = $el.data("data-type");
|
|
const timeFormat = $el.data("time-format");
|
|
const timezone = $el.data("timezone");
|
|
msg.prettify = getTypePrettifyer(dataType, timeFormat, timezone);
|
|
$el.data("immediate", true);
|
|
try {
|
|
slider.update(msg);
|
|
forceIonSliderUpdate(slider);
|
|
} finally {
|
|
$el.data("immediate", false);
|
|
}
|
|
}
|
|
getRatePolicy(el) {
|
|
return {
|
|
policy: "debounce",
|
|
delay: 250
|
|
};
|
|
el;
|
|
}
|
|
// TODO-barret Why not implemented?
|
|
getState(el) {
|
|
return;
|
|
el;
|
|
}
|
|
initialize(el) {
|
|
const $el = (0, import_jquery20.default)(el);
|
|
const dataType = $el.data("data-type");
|
|
const timeFormat = $el.data("time-format");
|
|
const timezone = $el.data("timezone");
|
|
const opts = {
|
|
prettify: getTypePrettifyer(dataType, timeFormat, timezone)
|
|
};
|
|
$el.ionRangeSlider(opts);
|
|
}
|
|
};
|
|
function formatNumber(num, thousandSep = ",", decimalSep = ".") {
|
|
const parts = num.toString().split(".");
|
|
parts[0] = parts[0].replace(
|
|
/(\d{1,3}(?=(?:\d\d\d)+(?!\d)))/g,
|
|
"$1" + thousandSep
|
|
);
|
|
if (parts.length === 1) return parts[0];
|
|
else if (parts.length === 2) return parts[0] + decimalSep + parts[1];
|
|
else return "";
|
|
}
|
|
(0, import_jquery20.default)(document).on("click", ".slider-animate-button", function(evt) {
|
|
evt.preventDefault();
|
|
const self = (0, import_jquery20.default)(this);
|
|
const target = (0, import_jquery20.default)("#" + $escape(self.attr("data-target-id")));
|
|
const startLabel = "Play";
|
|
const stopLabel = "Pause";
|
|
const loop = self.attr("data-loop") !== void 0 && !/^\s*false\s*$/i.test(self.attr("data-loop"));
|
|
let animInterval = self.attr("data-interval");
|
|
if (isNaN(animInterval)) animInterval = 1500;
|
|
else animInterval = Number(animInterval);
|
|
if (!target.data("animTimer")) {
|
|
let timer;
|
|
if (target.hasClass("jslider")) {
|
|
const slider = target.slider();
|
|
if (!slider.canStepNext()) slider.resetToStart();
|
|
timer = setInterval(function() {
|
|
if (loop && !slider.canStepNext()) {
|
|
slider.resetToStart();
|
|
} else {
|
|
slider.stepNext();
|
|
if (!loop && !slider.canStepNext()) {
|
|
self.click();
|
|
}
|
|
}
|
|
}, animInterval);
|
|
} else {
|
|
const slider = target.data("ionRangeSlider");
|
|
const sliderCanStep = function() {
|
|
if (slider.options.type === "double")
|
|
return slider.result.to < slider.result.max;
|
|
else return slider.result.from < slider.result.max;
|
|
};
|
|
const sliderReset = function() {
|
|
const val = { from: slider.result.min };
|
|
if (slider.options.type === "double")
|
|
val.to = val.from + (slider.result.to - slider.result.from);
|
|
slider.update(val);
|
|
forceIonSliderUpdate(slider);
|
|
};
|
|
const sliderStep = function() {
|
|
const val = {
|
|
from: Math.min(
|
|
slider.result.max,
|
|
slider.result.from + slider.options.step
|
|
)
|
|
};
|
|
if (slider.options.type === "double")
|
|
val.to = Math.min(
|
|
slider.result.max,
|
|
slider.result.to + slider.options.step
|
|
);
|
|
slider.update(val);
|
|
forceIonSliderUpdate(slider);
|
|
};
|
|
if (!sliderCanStep()) sliderReset();
|
|
timer = setInterval(function() {
|
|
if (loop && !sliderCanStep()) {
|
|
sliderReset();
|
|
} else {
|
|
sliderStep();
|
|
if (!loop && !sliderCanStep()) {
|
|
self.click();
|
|
}
|
|
}
|
|
}, animInterval);
|
|
}
|
|
target.data("animTimer", timer);
|
|
self.attr("title", stopLabel);
|
|
self.addClass("playing");
|
|
target.data("animating", true);
|
|
} else {
|
|
clearTimeout(target.data("animTimer"));
|
|
target.removeData("animTimer");
|
|
self.attr("title", startLabel);
|
|
self.removeClass("playing");
|
|
target.removeData("animating");
|
|
}
|
|
});
|
|
|
|
// srcts/src/bindings/input/tabinput.ts
|
|
var import_jquery21 = __toESM(require_jquery());
|
|
function getTabName(anchor) {
|
|
return anchor.attr("data-value") || anchor.text();
|
|
}
|
|
var BootstrapTabInputBinding = class extends InputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery21.default)(scope).find("ul.nav.shiny-tab-input");
|
|
}
|
|
getValue(el) {
|
|
const anchor = isBS3() ? (0, import_jquery21.default)(el).find("li:not(.dropdown).active > a") : (0, import_jquery21.default)(el).find(
|
|
".nav-link:not(.dropdown-toggle).active, .dropdown-menu .dropdown-item.active"
|
|
);
|
|
if (anchor.length === 1) return getTabName(anchor);
|
|
return null;
|
|
}
|
|
setValue(el, value) {
|
|
let success = false;
|
|
if (value) {
|
|
const anchors = isBS3() ? (0, import_jquery21.default)(el).find("li:not(.dropdown) > a") : (0, import_jquery21.default)(el).find(
|
|
".nav-link:not(.dropdown-toggle), .dropdown-menu .dropdown-item"
|
|
);
|
|
anchors.each(function() {
|
|
if (getTabName((0, import_jquery21.default)(this)) === value) {
|
|
(0, import_jquery21.default)(this).tab("show");
|
|
success = true;
|
|
return false;
|
|
}
|
|
return;
|
|
});
|
|
}
|
|
if (!success) {
|
|
(0, import_jquery21.default)(el).trigger("change");
|
|
}
|
|
}
|
|
getState(el) {
|
|
return { value: this.getValue(el) };
|
|
}
|
|
receiveMessage(el, data) {
|
|
if (hasDefinedProperty(data, "value")) this.setValue(el, data.value);
|
|
(0, import_jquery21.default)(el).trigger("change");
|
|
}
|
|
subscribe(el, callback) {
|
|
(0, import_jquery21.default)(el).on(
|
|
"change shown.bootstrapTabInputBinding shown.bs.tab.bootstrapTabInputBinding",
|
|
// event: Event
|
|
function() {
|
|
callback(false);
|
|
}
|
|
);
|
|
}
|
|
unsubscribe(el) {
|
|
(0, import_jquery21.default)(el).off(".bootstrapTabInputBinding");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/input/textarea.ts
|
|
var import_jquery22 = __toESM(require_jquery());
|
|
var intersectObserver = new IntersectionObserver((entries) => {
|
|
entries.forEach((entry) => {
|
|
if (entry.isIntersecting) {
|
|
updateHeight(entry.target);
|
|
}
|
|
});
|
|
});
|
|
var _inputHandler;
|
|
var TextareaInputBinding = class extends TextInputBinding {
|
|
constructor() {
|
|
super(...arguments);
|
|
__privateAdd(this, _inputHandler, null);
|
|
}
|
|
find(scope) {
|
|
return (0, import_jquery22.default)(scope).find("textarea");
|
|
}
|
|
initialize(el) {
|
|
super.initialize(el);
|
|
updateHeight(el);
|
|
}
|
|
subscribe(el, callback) {
|
|
super.subscribe(el, callback);
|
|
__privateSet(this, _inputHandler, (e4) => updateHeight(e4.target));
|
|
el.addEventListener("input", __privateGet(this, _inputHandler));
|
|
intersectObserver.observe(el);
|
|
}
|
|
unsubscribe(el) {
|
|
super.unsubscribe(el);
|
|
if (__privateGet(this, _inputHandler)) el.removeEventListener("input", __privateGet(this, _inputHandler));
|
|
intersectObserver.unobserve(el);
|
|
}
|
|
};
|
|
_inputHandler = new WeakMap();
|
|
function updateHeight(el) {
|
|
if (!el.classList.contains("textarea-autoresize")) {
|
|
return;
|
|
}
|
|
if (el.scrollHeight == 0) {
|
|
return;
|
|
}
|
|
el.style.height = "auto";
|
|
el.style.height = el.scrollHeight + "px";
|
|
}
|
|
|
|
// srcts/src/bindings/input/index.ts
|
|
function initInputBindings() {
|
|
const inputBindings = new BindingRegistry();
|
|
inputBindings.register(new TextInputBinding(), "shiny.textInput");
|
|
inputBindings.register(new TextareaInputBinding(), "shiny.textareaInput");
|
|
inputBindings.register(new PasswordInputBinding(), "shiny.passwordInput");
|
|
inputBindings.register(new NumberInputBinding(), "shiny.numberInput");
|
|
inputBindings.register(new CheckboxInputBinding(), "shiny.checkboxInput");
|
|
inputBindings.register(
|
|
new CheckboxGroupInputBinding(),
|
|
"shiny.checkboxGroupInput"
|
|
);
|
|
inputBindings.register(new RadioInputBinding(), "shiny.radioInput");
|
|
inputBindings.register(new SliderInputBinding(), "shiny.sliderInput");
|
|
inputBindings.register(new DateInputBinding(), "shiny.dateInput");
|
|
inputBindings.register(new DateRangeInputBinding(), "shiny.dateRangeInput");
|
|
inputBindings.register(new SelectInputBinding(), "shiny.selectInput");
|
|
inputBindings.register(
|
|
new ActionButtonInputBinding(),
|
|
"shiny.actionButtonInput"
|
|
);
|
|
inputBindings.register(
|
|
new BootstrapTabInputBinding(),
|
|
"shiny.bootstrapTabInput"
|
|
);
|
|
const fileInputBinding2 = new FileInputBinding();
|
|
inputBindings.register(fileInputBinding2, "shiny.fileInputBinding");
|
|
return { inputBindings, fileInputBinding: fileInputBinding2 };
|
|
}
|
|
|
|
// srcts/src/bindings/output/datatable.ts
|
|
var import_jquery24 = __toESM(require_jquery());
|
|
|
|
// srcts/src/bindings/output/outputBinding.ts
|
|
var import_jquery23 = __toESM(require_jquery());
|
|
var OutputBinding = class {
|
|
// Returns a jQuery object or element array that contains the
|
|
// descendants of scope that match this binding
|
|
find(scope) {
|
|
throw "Not implemented";
|
|
scope;
|
|
}
|
|
renderValue(el, data) {
|
|
throw "Not implemented";
|
|
el;
|
|
data;
|
|
}
|
|
getId(el) {
|
|
return el.getAttribute("data-input-id") || el.id;
|
|
}
|
|
async onValueChange(el, data) {
|
|
this.clearError(el);
|
|
await this.renderValue(el, data);
|
|
}
|
|
onValueError(el, err) {
|
|
this.renderError(el, err);
|
|
}
|
|
renderError(el, err) {
|
|
this.clearError(el);
|
|
if (err.message === "") {
|
|
(0, import_jquery23.default)(el).empty();
|
|
return;
|
|
}
|
|
let errClass = "shiny-output-error";
|
|
if (err.type !== null) {
|
|
errClass = errClass + " " + import_jquery23.default.map(asArray(err.type), function(type) {
|
|
return errClass + "-" + type;
|
|
}).join(" ");
|
|
}
|
|
(0, import_jquery23.default)(el).addClass(errClass).text(err.message);
|
|
}
|
|
clearError(el) {
|
|
(0, import_jquery23.default)(el).attr("class", function(i5, c4) {
|
|
return c4.replace(/(^|\s)shiny-output-error\S*/g, "");
|
|
});
|
|
}
|
|
showProgress(el, show3) {
|
|
const recalcClass = "recalculating";
|
|
if (show3) (0, import_jquery23.default)(el).addClass(recalcClass);
|
|
else (0, import_jquery23.default)(el).removeClass(recalcClass);
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/output/datatable.ts
|
|
var DatatableOutputBinding = class extends OutputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery24.default)(scope).find(".shiny-datatable-output");
|
|
}
|
|
onValueError(el, err) {
|
|
shinyUnbindAll(el);
|
|
this.renderError(el, err);
|
|
}
|
|
renderValue(el, data) {
|
|
const $el = (0, import_jquery24.default)(el).empty();
|
|
if (!data || !data.colnames) return;
|
|
const colnames = import_jquery24.default.makeArray(data.colnames);
|
|
let header = import_jquery24.default.map(colnames, function(x2) {
|
|
return "<th>" + x2 + "</th>";
|
|
}).join("");
|
|
header = "<thead><tr>" + header + "</tr></thead>";
|
|
let footer = "";
|
|
if (data.options?.searching ?? true) {
|
|
footer = import_jquery24.default.map(colnames, function(x2) {
|
|
return '<th><input type="text" placeholder="' + escapeHTML(x2.replace(/(<([^>]+)>)/gi, "")) + '" /></th>';
|
|
}).join("");
|
|
footer = "<tfoot>" + footer + "</tfoot>";
|
|
}
|
|
const content = '<table class="table table-striped table-hover">' + header + footer + "</table>";
|
|
$el.append(content);
|
|
if (data.evalOptions) {
|
|
import_jquery24.default.each(data.evalOptions, function(i5, x2) {
|
|
data.options[x2] = indirectEval("(" + data.options[x2] + ")");
|
|
});
|
|
}
|
|
const searchCI = data.options?.search?.caseInsensitive !== false;
|
|
const oTable = (0, import_jquery24.default)(el).children("table").DataTable(
|
|
import_jquery24.default.extend(
|
|
{
|
|
processing: true,
|
|
serverSide: true,
|
|
order: [],
|
|
orderClasses: false,
|
|
pageLength: 25,
|
|
ajax: {
|
|
url: data.action,
|
|
type: "POST",
|
|
data: function(d3) {
|
|
if (!d3.search) {
|
|
d3.search = {};
|
|
}
|
|
d3.search.caseInsensitive = searchCI;
|
|
d3.escape = data.escape;
|
|
}
|
|
}
|
|
},
|
|
data.options
|
|
)
|
|
);
|
|
if (typeof data.callback === "string") {
|
|
const callback = indirectEval("(" + data.callback + ")");
|
|
if (typeof callback === "function") callback(oTable);
|
|
}
|
|
$el.find("label input").first().unbind("keyup").keyup(
|
|
debounce(data.searchDelay, function() {
|
|
oTable.search(this.value).draw();
|
|
})
|
|
);
|
|
const searchInputs = $el.find("tfoot input");
|
|
if (searchInputs.length > 0) {
|
|
import_jquery24.default.each(oTable.settings()[0].aoColumns, function(i5, x2) {
|
|
if (!x2.bSearchable) searchInputs.eq(i5).hide();
|
|
});
|
|
searchInputs.keyup(
|
|
debounce(data.searchDelay, function() {
|
|
oTable.column(searchInputs.index(this)).search(this.value).draw();
|
|
})
|
|
);
|
|
}
|
|
$el.parents(".tab-content").css("overflow", "visible");
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/output/downloadlink.ts
|
|
var import_jquery25 = __toESM(require_jquery());
|
|
var DownloadLinkOutputBinding = class extends OutputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery25.default)(scope).find("a.shiny-download-link");
|
|
}
|
|
renderValue(el, data) {
|
|
el.setAttribute("href", data);
|
|
el.classList.remove("disabled");
|
|
el.removeAttribute("aria-disabled");
|
|
el.removeAttribute("tabindex");
|
|
}
|
|
// Progress shouldn't be shown on the download button
|
|
// (progress will be shown as a page level pulse instead)
|
|
showProgress(el, show3) {
|
|
return;
|
|
el;
|
|
show3;
|
|
}
|
|
};
|
|
(0, import_jquery25.default)(document).on(
|
|
"click.shinyDownloadLink",
|
|
"a.shiny-download-link",
|
|
function(e4) {
|
|
const evt = import_jquery25.default.Event("shiny:filedownload");
|
|
evt.name = this.id;
|
|
evt.href = this.href;
|
|
(0, import_jquery25.default)(document).trigger(evt);
|
|
return;
|
|
e4;
|
|
}
|
|
);
|
|
|
|
// srcts/src/bindings/output/html.ts
|
|
var import_jquery26 = __toESM(require_jquery());
|
|
var HtmlOutputBinding = class extends OutputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery26.default)(scope).find(".shiny-html-output");
|
|
}
|
|
onValueError(el, err) {
|
|
shinyUnbindAll(el);
|
|
this.renderError(el, err);
|
|
}
|
|
async renderValue(el, data) {
|
|
await renderContentAsync(el, data);
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/output/image.ts
|
|
var import_jquery32 = __toESM(require_jquery());
|
|
|
|
// srcts/src/imageutils/createBrush.ts
|
|
var import_jquery28 = __toESM(require_jquery());
|
|
|
|
// srcts/src/imageutils/initCoordmap.ts
|
|
var import_jquery27 = __toESM(require_jquery());
|
|
|
|
// srcts/src/imageutils/initPanelScales.ts
|
|
function mapLinear(x2, domainMin, domainMax, rangeMin, rangeMax, clip = true) {
|
|
clip = clip || true;
|
|
const factor = (rangeMax - rangeMin) / (domainMax - domainMin);
|
|
const val = x2 - domainMin;
|
|
let newval = val * factor + rangeMin;
|
|
if (clip) {
|
|
const max = Math.max(rangeMax, rangeMin);
|
|
const min = Math.min(rangeMax, rangeMin);
|
|
if (newval > max) newval = max;
|
|
else if (newval < min) newval = min;
|
|
}
|
|
return newval;
|
|
}
|
|
function scaler1D(domainMin, domainMax, rangeMin, rangeMax, logbase) {
|
|
return {
|
|
scale: function(val, clip) {
|
|
if (logbase) val = Math.log(val) / Math.log(logbase);
|
|
return mapLinear(val, domainMin, domainMax, rangeMin, rangeMax, clip);
|
|
},
|
|
scaleInv: function(val, clip) {
|
|
let res = mapLinear(val, rangeMin, rangeMax, domainMin, domainMax, clip);
|
|
if (logbase) res = Math.pow(logbase, res);
|
|
return res;
|
|
}
|
|
};
|
|
}
|
|
function addScaleFuns(panel_) {
|
|
const panel = panel_;
|
|
const d3 = panel.domain;
|
|
const r4 = panel.range;
|
|
const xlog = panel.log && panel.log.x ? panel.log.x : null;
|
|
const ylog = panel.log && panel.log.y ? panel.log.y : null;
|
|
const xscaler = scaler1D(d3.left, d3.right, r4.left, r4.right, xlog);
|
|
const yscaler = scaler1D(d3.bottom, d3.top, r4.bottom, r4.top, ylog);
|
|
function scaleDataToImg(val, clip) {
|
|
return mapValues(val, (value, key) => {
|
|
const prefix = key.substring(0, 1);
|
|
if (prefix === "x") {
|
|
return xscaler.scale(value, clip);
|
|
} else if (prefix === "y") {
|
|
return yscaler.scale(value, clip);
|
|
}
|
|
return null;
|
|
});
|
|
}
|
|
panel.scaleDataToImg = scaleDataToImg;
|
|
function scaleImgToData(val, clip) {
|
|
return mapValues(val, (value, key) => {
|
|
const prefix = key.substring(0, 1);
|
|
if (prefix === "x") {
|
|
return xscaler.scaleInv(value, clip);
|
|
} else if (prefix === "y") {
|
|
return yscaler.scaleInv(value, clip);
|
|
}
|
|
return null;
|
|
});
|
|
}
|
|
panel.scaleImgToData = scaleImgToData;
|
|
panel.clipImg = function(offsetImg) {
|
|
const newOffset = {
|
|
x: offsetImg.x,
|
|
y: offsetImg.y
|
|
};
|
|
const bounds = panel.range;
|
|
if (offsetImg.x > bounds.right) newOffset.x = bounds.right;
|
|
else if (offsetImg.x < bounds.left) newOffset.x = bounds.left;
|
|
if (offsetImg.y > bounds.bottom) newOffset.y = bounds.bottom;
|
|
else if (offsetImg.y < bounds.top) newOffset.y = bounds.top;
|
|
return newOffset;
|
|
};
|
|
return panel;
|
|
}
|
|
function initPanelScales(panels) {
|
|
return panels.map((panel) => addScaleFuns(panel));
|
|
}
|
|
|
|
// srcts/src/imageutils/initCoordmap.ts
|
|
function findScalingRatio($el) {
|
|
const boundingRect = $el[0].getBoundingClientRect();
|
|
return {
|
|
x: boundingRect.width / $el.outerWidth(),
|
|
y: boundingRect.height / $el.outerHeight()
|
|
};
|
|
}
|
|
function findOrigin($el) {
|
|
const offset = $el.offset();
|
|
const scalingRatio = findScalingRatio($el);
|
|
const paddingBorder = {
|
|
left: parseInt($el.css("border-left-width")) + parseInt($el.css("padding-left")),
|
|
top: parseInt($el.css("border-top-width")) + parseInt($el.css("padding-top"))
|
|
};
|
|
return {
|
|
x: offset.left + scalingRatio.x * paddingBorder.left,
|
|
y: offset.top + scalingRatio.y * paddingBorder.top
|
|
};
|
|
}
|
|
function findDims($el) {
|
|
const contentRatio = {
|
|
x: $el.width() / $el.outerWidth(),
|
|
y: $el.height() / $el.outerHeight()
|
|
};
|
|
const boundingRect = $el[0].getBoundingClientRect();
|
|
return {
|
|
x: contentRatio.x * boundingRect.width,
|
|
y: contentRatio.y * boundingRect.height
|
|
};
|
|
}
|
|
function initCoordmap($el, coordmap_) {
|
|
const $img = $el.find("img");
|
|
const img = $img[0];
|
|
if (coordmap_.panels.length === 0) {
|
|
const bounds = {
|
|
top: 0,
|
|
left: 0,
|
|
right: img.naturalWidth - 1,
|
|
bottom: img.naturalHeight - 1
|
|
};
|
|
coordmap_.panels[0] = {
|
|
domain: bounds,
|
|
range: bounds,
|
|
mapping: {}
|
|
};
|
|
}
|
|
const coordmap = coordmap_;
|
|
coordmap.dims.height = coordmap.dims.height || img.naturalHeight;
|
|
coordmap.dims.width = coordmap.dims.width || img.naturalWidth;
|
|
coordmap.panels = initPanelScales(coordmap_.panels);
|
|
coordmap.mouseOffsetCss = function(mouseEvent) {
|
|
const imgOrigin = findOrigin($img);
|
|
return {
|
|
x: mouseEvent.pageX - imgOrigin.x,
|
|
y: mouseEvent.pageY - imgOrigin.y
|
|
};
|
|
};
|
|
function scaleCssToImg(offsetCss) {
|
|
const pixelScaling = coordmap.imgToCssScalingRatio();
|
|
const result = mapValues(offsetCss, (value, key) => {
|
|
const prefix = key.substring(0, 1);
|
|
if (prefix === "x") {
|
|
return offsetCss[key] / pixelScaling.x;
|
|
} else if (prefix === "y") {
|
|
return offsetCss[key] / pixelScaling.y;
|
|
}
|
|
return null;
|
|
});
|
|
return result;
|
|
}
|
|
coordmap.scaleCssToImg = scaleCssToImg;
|
|
function scaleImgToCss(offsetImg) {
|
|
const pixelScaling = coordmap.imgToCssScalingRatio();
|
|
const result = mapValues(offsetImg, (value, key) => {
|
|
const prefix = key.substring(0, 1);
|
|
if (prefix === "x") {
|
|
return offsetImg[key] * pixelScaling.x;
|
|
} else if (prefix === "y") {
|
|
return offsetImg[key] * pixelScaling.y;
|
|
}
|
|
return null;
|
|
});
|
|
return result;
|
|
}
|
|
coordmap.scaleImgToCss = scaleImgToCss;
|
|
coordmap.imgToCssScalingRatio = function() {
|
|
const imgDims = findDims($img);
|
|
return {
|
|
x: imgDims.x / coordmap.dims.width,
|
|
y: imgDims.y / coordmap.dims.height
|
|
};
|
|
};
|
|
coordmap.cssToImgScalingRatio = function() {
|
|
const res = coordmap.imgToCssScalingRatio();
|
|
return {
|
|
x: 1 / res.x,
|
|
y: 1 / res.y
|
|
};
|
|
};
|
|
coordmap.getPanelCss = function(offsetCss, expand = 0) {
|
|
const offsetImg = coordmap.scaleCssToImg(offsetCss);
|
|
const x2 = offsetImg.x;
|
|
const y3 = offsetImg.y;
|
|
const cssToImgRatio = coordmap.cssToImgScalingRatio();
|
|
const expandImg = {
|
|
x: expand * cssToImgRatio.x,
|
|
y: expand * cssToImgRatio.y
|
|
};
|
|
const matches = [];
|
|
const dists = [];
|
|
let i5;
|
|
for (i5 = 0; i5 < coordmap.panels.length; i5++) {
|
|
const b3 = coordmap.panels[i5].range;
|
|
if (x2 <= b3.right + expandImg.x && x2 >= b3.left - expandImg.x && y3 <= b3.bottom + expandImg.y && y3 >= b3.top - expandImg.y) {
|
|
matches.push(coordmap.panels[i5]);
|
|
let xdist = 0;
|
|
let ydist = 0;
|
|
if (x2 > b3.right && x2 <= b3.right + expandImg.x) {
|
|
xdist = x2 - b3.right;
|
|
} else if (x2 < b3.left && x2 >= b3.left - expandImg.x) {
|
|
xdist = x2 - b3.left;
|
|
}
|
|
if (y3 > b3.bottom && y3 <= b3.bottom + expandImg.y) {
|
|
ydist = y3 - b3.bottom;
|
|
} else if (y3 < b3.top && y3 >= b3.top - expandImg.y) {
|
|
ydist = y3 - b3.top;
|
|
}
|
|
dists.push(Math.sqrt(Math.pow(xdist, 2) + Math.pow(ydist, 2)));
|
|
}
|
|
}
|
|
if (matches.length) {
|
|
const minDist = Math.min.apply(null, dists);
|
|
for (i5 = 0; i5 < matches.length; i5++) {
|
|
if (dists[i5] === minDist) {
|
|
return matches[i5];
|
|
}
|
|
}
|
|
}
|
|
return null;
|
|
};
|
|
coordmap.isInPanelCss = function(offsetCss, expand = 0) {
|
|
if (coordmap.getPanelCss(offsetCss, expand)) return true;
|
|
return false;
|
|
};
|
|
coordmap.mouseCoordinateSender = function(inputId, clip = true, nullOutside = false) {
|
|
return function(e4) {
|
|
if (e4 === null) {
|
|
shinySetInputValue(inputId, null);
|
|
return;
|
|
}
|
|
const coordsCss = coordmap.mouseOffsetCss(e4);
|
|
if (!coordmap.isInPanelCss(coordsCss)) {
|
|
if (nullOutside) {
|
|
shinySetInputValue(inputId, null);
|
|
return;
|
|
}
|
|
if (clip) return;
|
|
const coords2 = {
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
coords_css: coordsCss,
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
coords_img: coordmap.scaleCssToImg(coordsCss)
|
|
};
|
|
shinySetInputValue(inputId, coords2, { priority: "event" });
|
|
return;
|
|
}
|
|
const panel = coordmap.getPanelCss(coordsCss);
|
|
const coordsImg = coordmap.scaleCssToImg(coordsCss);
|
|
const coordsData = panel.scaleImgToData(coordsImg);
|
|
const coords = {
|
|
x: coordsData?.x,
|
|
y: coordsData?.y,
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
coords_css: coordsCss,
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
coords_img: coordsImg,
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
img_css_ratio: coordmap.cssToImgScalingRatio()
|
|
};
|
|
import_jquery27.default.extend(coords, panel.panel_vars);
|
|
coords.mapping = panel.mapping;
|
|
coords.domain = panel.domain;
|
|
coords.range = panel.range;
|
|
coords.log = panel.log;
|
|
shinySetInputValue(inputId, coords, { priority: "event" });
|
|
};
|
|
};
|
|
return coordmap;
|
|
}
|
|
|
|
// srcts/src/imageutils/findbox.ts
|
|
function findBox(offset1, offset2) {
|
|
return {
|
|
xmin: Math.min(offset1.x, offset2.x),
|
|
xmax: Math.max(offset1.x, offset2.x),
|
|
ymin: Math.min(offset1.y, offset2.y),
|
|
ymax: Math.max(offset1.y, offset2.y)
|
|
};
|
|
}
|
|
|
|
// srcts/src/imageutils/shiftToRange.ts
|
|
function shiftToRange(vals, min, max) {
|
|
if (!(vals instanceof Array)) vals = [vals];
|
|
const maxval = Math.max.apply(null, vals);
|
|
const minval = Math.min.apply(null, vals);
|
|
let shiftAmount = 0;
|
|
if (maxval > max) {
|
|
shiftAmount = max - maxval;
|
|
} else if (minval < min) {
|
|
shiftAmount = min - minval;
|
|
}
|
|
const newvals = [];
|
|
for (let i5 = 0; i5 < vals.length; i5++) {
|
|
newvals[i5] = vals[i5] + shiftAmount;
|
|
}
|
|
return newvals;
|
|
}
|
|
|
|
// srcts/src/imageutils/createBrush.ts
|
|
function createBrush($el, opts, coordmap, expandPixels) {
|
|
const resizeExpand = 10;
|
|
const el = $el[0];
|
|
let $div = null;
|
|
const state = {};
|
|
const cssToImg = coordmap.scaleCssToImg;
|
|
const imgToCss = coordmap.scaleImgToCss;
|
|
reset();
|
|
function reset() {
|
|
state.brushing = false;
|
|
state.dragging = false;
|
|
state.resizing = false;
|
|
state.down = { x: NaN, y: NaN };
|
|
state.up = { x: NaN, y: NaN };
|
|
state.resizeSides = {
|
|
left: false,
|
|
right: false,
|
|
top: false,
|
|
bottom: false
|
|
};
|
|
state.boundsCss = {
|
|
xmin: NaN,
|
|
xmax: NaN,
|
|
ymin: NaN,
|
|
ymax: NaN
|
|
};
|
|
state.boundsData = {
|
|
xmin: NaN,
|
|
xmax: NaN,
|
|
ymin: NaN,
|
|
ymax: NaN
|
|
};
|
|
state.panel = null;
|
|
state.changeStartBounds = {
|
|
xmin: NaN,
|
|
xmax: NaN,
|
|
ymin: NaN,
|
|
ymax: NaN
|
|
};
|
|
if ($div) $div.remove();
|
|
}
|
|
function hasOldBrush() {
|
|
const oldDiv = $el.find("#" + el.id + "_brush");
|
|
return oldDiv.length > 0;
|
|
}
|
|
function importOldBrush() {
|
|
const oldDiv = $el.find("#" + el.id + "_brush");
|
|
if (oldDiv.length === 0) return;
|
|
const oldBoundsData = oldDiv.data("bounds-data");
|
|
const oldPanel = oldDiv.data("panel");
|
|
if (!oldBoundsData || !oldPanel) return;
|
|
for (let i5 = 0; i5 < coordmap.panels.length; i5++) {
|
|
const curPanel = coordmap.panels[i5];
|
|
if (equal(oldPanel.mapping, curPanel.mapping) && equal(oldPanel.panel_vars, curPanel.panel_vars)) {
|
|
state.panel = coordmap.panels[i5];
|
|
break;
|
|
}
|
|
}
|
|
if (state.panel === null) {
|
|
oldDiv.remove();
|
|
return;
|
|
}
|
|
$div = oldDiv;
|
|
boundsData(oldBoundsData);
|
|
updateDiv();
|
|
}
|
|
function onResize() {
|
|
const boundsDataVal = boundsData();
|
|
if (Object.values(boundsDataVal).some(isnan)) return;
|
|
boundsData(boundsDataVal);
|
|
updateDiv();
|
|
}
|
|
function isInsideBrush(offsetCss) {
|
|
const bounds = state.boundsCss;
|
|
return offsetCss.x <= bounds.xmax && offsetCss.x >= bounds.xmin && offsetCss.y <= bounds.ymax && offsetCss.y >= bounds.ymin;
|
|
}
|
|
function isInResizeArea(offsetCss) {
|
|
const sides = whichResizeSides(offsetCss);
|
|
return sides.left || sides.right || sides.top || sides.bottom;
|
|
}
|
|
function whichResizeSides(offsetCss) {
|
|
const b3 = state.boundsCss;
|
|
const e4 = {
|
|
xmin: b3.xmin - resizeExpand,
|
|
xmax: b3.xmax + resizeExpand,
|
|
ymin: b3.ymin - resizeExpand,
|
|
ymax: b3.ymax + resizeExpand
|
|
};
|
|
const res = {
|
|
left: false,
|
|
right: false,
|
|
top: false,
|
|
bottom: false
|
|
};
|
|
if ((opts.brushDirection === "xy" || opts.brushDirection === "x") && offsetCss.y <= e4.ymax && offsetCss.y >= e4.ymin) {
|
|
if (offsetCss.x < b3.xmin && offsetCss.x >= e4.xmin) res.left = true;
|
|
else if (offsetCss.x > b3.xmax && offsetCss.x <= e4.xmax) res.right = true;
|
|
}
|
|
if ((opts.brushDirection === "xy" || opts.brushDirection === "y") && offsetCss.x <= e4.xmax && offsetCss.x >= e4.xmin) {
|
|
if (offsetCss.y < b3.ymin && offsetCss.y >= e4.ymin) res.top = true;
|
|
else if (offsetCss.y > b3.ymax && offsetCss.y <= e4.ymax) res.bottom = true;
|
|
}
|
|
return res;
|
|
}
|
|
function boundsCss(boxCss) {
|
|
if (boxCss === void 0) {
|
|
return { ...state.boundsCss };
|
|
}
|
|
let minCss = { x: boxCss.xmin, y: boxCss.ymin };
|
|
let maxCss = { x: boxCss.xmax, y: boxCss.ymax };
|
|
const panel = state.panel;
|
|
const panelBoundsImg = panel.range;
|
|
if (opts.brushClip) {
|
|
minCss = imgToCss(panel.clipImg(cssToImg(minCss)));
|
|
maxCss = imgToCss(panel.clipImg(cssToImg(maxCss)));
|
|
}
|
|
if (opts.brushDirection === "xy") {
|
|
} else if (opts.brushDirection === "x") {
|
|
minCss.y = imgToCss({ y: panelBoundsImg.top }).y;
|
|
maxCss.y = imgToCss({ y: panelBoundsImg.bottom }).y;
|
|
} else if (opts.brushDirection === "y") {
|
|
minCss.x = imgToCss({ x: panelBoundsImg.left }).x;
|
|
maxCss.x = imgToCss({ x: panelBoundsImg.right }).x;
|
|
}
|
|
state.boundsCss = {
|
|
xmin: minCss.x,
|
|
xmax: maxCss.x,
|
|
ymin: minCss.y,
|
|
ymax: maxCss.y
|
|
};
|
|
const minData = panel.scaleImgToData(cssToImg(minCss));
|
|
const maxData = panel.scaleImgToData(cssToImg(maxCss));
|
|
state.boundsData = findBox(minData, maxData);
|
|
state.boundsData = mapValues(
|
|
state.boundsData,
|
|
(val) => roundSignif(val, 14)
|
|
);
|
|
$div.data("bounds-data", state.boundsData);
|
|
$div.data("panel", state.panel);
|
|
return void 0;
|
|
}
|
|
function boundsData(boxData) {
|
|
if (typeof boxData === "undefined") {
|
|
return { ...state.boundsData };
|
|
}
|
|
let boxCss = imgToCss(state.panel.scaleDataToImg(boxData));
|
|
boxCss = mapValues(boxCss, (val) => roundSignif(val, 13));
|
|
boundsCss({
|
|
xmin: Math.min(boxCss.xmin, boxCss.xmax),
|
|
xmax: Math.max(boxCss.xmin, boxCss.xmax),
|
|
ymin: Math.min(boxCss.ymin, boxCss.ymax),
|
|
ymax: Math.max(boxCss.ymin, boxCss.ymax)
|
|
});
|
|
return void 0;
|
|
}
|
|
function getPanel2() {
|
|
return state.panel;
|
|
}
|
|
function addDiv() {
|
|
if ($div) $div.remove();
|
|
$div = (0, import_jquery28.default)(document.createElement("div")).attr("id", el.id + "_brush").css({
|
|
"background-color": opts.brushFill,
|
|
opacity: opts.brushOpacity,
|
|
"pointer-events": "none",
|
|
position: "absolute"
|
|
}).hide();
|
|
const borderStyle = "1px solid " + opts.brushStroke;
|
|
if (opts.brushDirection === "xy") {
|
|
$div.css({
|
|
border: borderStyle
|
|
});
|
|
} else if (opts.brushDirection === "x") {
|
|
$div.css({
|
|
"border-left": borderStyle,
|
|
"border-right": borderStyle
|
|
});
|
|
} else if (opts.brushDirection === "y") {
|
|
$div.css({
|
|
"border-top": borderStyle,
|
|
"border-bottom": borderStyle
|
|
});
|
|
}
|
|
$el.append($div);
|
|
$div.offset(
|
|
// @ts-expect-error; This is a jQuery Typing issue
|
|
{ x: 0, y: 0 }
|
|
).width(0).outerHeight(0);
|
|
}
|
|
function updateDiv() {
|
|
const imgOffsetCss = findOrigin($el.find("img"));
|
|
const b3 = state.boundsCss;
|
|
$div.offset({
|
|
top: imgOffsetCss.y + b3.ymin,
|
|
left: imgOffsetCss.x + b3.xmin
|
|
}).outerWidth(b3.xmax - b3.xmin + 1).outerHeight(b3.ymax - b3.ymin + 1);
|
|
}
|
|
function down(offsetCss) {
|
|
if (offsetCss === void 0) return state.down;
|
|
state.down = offsetCss;
|
|
return void 0;
|
|
}
|
|
function up(offsetCss) {
|
|
if (offsetCss === void 0) return state.up;
|
|
state.up = offsetCss;
|
|
return void 0;
|
|
}
|
|
function isBrushing() {
|
|
return state.brushing;
|
|
}
|
|
function startBrushing() {
|
|
state.brushing = true;
|
|
addDiv();
|
|
state.panel = coordmap.getPanelCss(state.down, expandPixels);
|
|
boundsCss(findBox(state.down, state.down));
|
|
updateDiv();
|
|
}
|
|
function brushTo(offsetCss) {
|
|
boundsCss(findBox(state.down, offsetCss));
|
|
$div.show();
|
|
updateDiv();
|
|
}
|
|
function stopBrushing() {
|
|
state.brushing = false;
|
|
boundsCss(findBox(state.down, state.up));
|
|
}
|
|
function isDragging() {
|
|
return state.dragging;
|
|
}
|
|
function startDragging() {
|
|
state.dragging = true;
|
|
state.changeStartBounds = { ...state.boundsCss };
|
|
}
|
|
function dragTo(offsetCss) {
|
|
const dx = offsetCss.x - state.down.x;
|
|
const dy = offsetCss.y - state.down.y;
|
|
const start = state.changeStartBounds;
|
|
let newBoundsCss = {
|
|
xmin: start.xmin + dx,
|
|
xmax: start.xmax + dx,
|
|
ymin: start.ymin + dy,
|
|
ymax: start.ymax + dy
|
|
};
|
|
if (opts.brushClip) {
|
|
const panel = state.panel;
|
|
const panelBoundsImg = panel.range;
|
|
const newBoundsImg = cssToImg(newBoundsCss);
|
|
let xvalsImg = [newBoundsImg.xmin, newBoundsImg.xmax];
|
|
let yvalsImg = [newBoundsImg.ymin, newBoundsImg.ymax];
|
|
xvalsImg = shiftToRange(
|
|
xvalsImg,
|
|
panelBoundsImg.left,
|
|
panelBoundsImg.right
|
|
);
|
|
yvalsImg = shiftToRange(
|
|
yvalsImg,
|
|
panelBoundsImg.top,
|
|
panelBoundsImg.bottom
|
|
);
|
|
newBoundsCss = imgToCss({
|
|
xmin: xvalsImg[0],
|
|
xmax: xvalsImg[1],
|
|
ymin: yvalsImg[0],
|
|
ymax: yvalsImg[1]
|
|
});
|
|
}
|
|
boundsCss(newBoundsCss);
|
|
updateDiv();
|
|
}
|
|
function stopDragging() {
|
|
state.dragging = false;
|
|
}
|
|
function isResizing() {
|
|
return state.resizing;
|
|
}
|
|
function startResizing() {
|
|
state.resizing = true;
|
|
state.changeStartBounds = { ...state.boundsCss };
|
|
state.resizeSides = whichResizeSides(state.down);
|
|
}
|
|
function resizeTo(offsetCss) {
|
|
const dCss = {
|
|
x: offsetCss.x - state.down.x,
|
|
y: offsetCss.y - state.down.y
|
|
};
|
|
const dImg = cssToImg(dCss);
|
|
const bImg = cssToImg(state.changeStartBounds);
|
|
const panel = state.panel;
|
|
const panelBoundsImg = panel.range;
|
|
if (state.resizeSides.left) {
|
|
const xminImg = shiftToRange(
|
|
bImg.xmin + dImg.x,
|
|
panelBoundsImg.left,
|
|
bImg.xmax
|
|
)[0];
|
|
bImg.xmin = xminImg;
|
|
} else if (state.resizeSides.right) {
|
|
const xmaxImg = shiftToRange(
|
|
bImg.xmax + dImg.x,
|
|
bImg.xmin,
|
|
panelBoundsImg.right
|
|
)[0];
|
|
bImg.xmax = xmaxImg;
|
|
}
|
|
if (state.resizeSides.top) {
|
|
const yminImg = shiftToRange(
|
|
bImg.ymin + dImg.y,
|
|
panelBoundsImg.top,
|
|
bImg.ymax
|
|
)[0];
|
|
bImg.ymin = yminImg;
|
|
} else if (state.resizeSides.bottom) {
|
|
const ymaxImg = shiftToRange(
|
|
bImg.ymax + dImg.y,
|
|
bImg.ymin,
|
|
panelBoundsImg.bottom
|
|
)[0];
|
|
bImg.ymax = ymaxImg;
|
|
}
|
|
boundsCss(imgToCss(bImg));
|
|
updateDiv();
|
|
}
|
|
function stopResizing() {
|
|
state.resizing = false;
|
|
}
|
|
return {
|
|
reset,
|
|
hasOldBrush,
|
|
importOldBrush,
|
|
isInsideBrush,
|
|
isInResizeArea,
|
|
whichResizeSides,
|
|
onResize,
|
|
// A callback when the wrapper div or img is resized.
|
|
boundsCss,
|
|
boundsData,
|
|
getPanel: getPanel2,
|
|
down,
|
|
up,
|
|
isBrushing,
|
|
startBrushing,
|
|
brushTo,
|
|
stopBrushing,
|
|
isDragging,
|
|
startDragging,
|
|
dragTo,
|
|
stopDragging,
|
|
isResizing,
|
|
startResizing,
|
|
resizeTo,
|
|
stopResizing
|
|
};
|
|
}
|
|
|
|
// srcts/src/imageutils/createClickInfo.ts
|
|
var import_jquery29 = __toESM(require_jquery());
|
|
function createClickInfo($el, dblclickId, dblclickDelay) {
|
|
let clickTimer = void 0;
|
|
let pendingE = null;
|
|
function triggerEvent(newEventType, e4) {
|
|
const e22 = import_jquery29.default.Event(newEventType, {
|
|
which: e4.which,
|
|
pageX: e4.pageX,
|
|
pageY: e4.pageY
|
|
});
|
|
$el.trigger(e22);
|
|
}
|
|
function triggerPendingMousedown2() {
|
|
if (pendingE) {
|
|
triggerEvent("mousedown2", pendingE);
|
|
pendingE = null;
|
|
}
|
|
}
|
|
function scheduleMousedown2(e4) {
|
|
pendingE = e4;
|
|
clickTimer = window.setTimeout(function() {
|
|
triggerPendingMousedown2();
|
|
}, dblclickDelay);
|
|
}
|
|
function mousedown(e4) {
|
|
if (e4.which !== 1) return;
|
|
if (!dblclickId) {
|
|
triggerEvent("mousedown2", e4);
|
|
return;
|
|
}
|
|
if (pendingE === null) {
|
|
scheduleMousedown2(e4);
|
|
} else {
|
|
clearTimeout(clickTimer);
|
|
if (pendingE && Math.abs(pendingE.pageX - e4.pageX) > 2 || Math.abs(pendingE.pageY - e4.pageY) > 2) {
|
|
triggerPendingMousedown2();
|
|
scheduleMousedown2(e4);
|
|
} else {
|
|
pendingE = null;
|
|
triggerEvent("dblclick2", e4);
|
|
}
|
|
}
|
|
}
|
|
function dblclickIE8(e4) {
|
|
e4.which = 1;
|
|
triggerEvent("dblclick2", e4);
|
|
}
|
|
return {
|
|
mousedown,
|
|
dblclickIE8
|
|
};
|
|
}
|
|
|
|
// srcts/src/imageutils/createHandlers.ts
|
|
var import_jquery31 = __toESM(require_jquery());
|
|
|
|
// srcts/src/imageutils/imageBindingUtils.ts
|
|
var import_jquery30 = __toESM(require_jquery());
|
|
function findImageOutputs(scope = document.documentElement) {
|
|
return (0, import_jquery30.default)(scope).find(".shiny-image-output, .shiny-plot-output");
|
|
}
|
|
|
|
// srcts/src/imageutils/createHandlers.ts
|
|
function createClickHandler(inputId, clip, coordmap) {
|
|
const clickInfoSender = coordmap.mouseCoordinateSender(inputId, clip);
|
|
clickInfoSender(null);
|
|
return {
|
|
mousedown: function(e4) {
|
|
if (e4.which !== 1) return;
|
|
clickInfoSender(e4);
|
|
},
|
|
onResetImg: function() {
|
|
clickInfoSender(null);
|
|
},
|
|
onResize: null
|
|
};
|
|
}
|
|
function createHoverHandler(inputId, delay, delayType, clip, nullOutside, coordmap) {
|
|
const sendHoverInfo = coordmap.mouseCoordinateSender(
|
|
inputId,
|
|
clip,
|
|
nullOutside
|
|
);
|
|
let hoverInfoSender;
|
|
if (delayType === "throttle")
|
|
hoverInfoSender = new Throttler(null, sendHoverInfo, delay);
|
|
else hoverInfoSender = new Debouncer(null, sendHoverInfo, delay);
|
|
hoverInfoSender.immediateCall(null);
|
|
let mouseout;
|
|
if (nullOutside)
|
|
mouseout = function() {
|
|
hoverInfoSender.normalCall(null);
|
|
};
|
|
else
|
|
mouseout = function() {
|
|
};
|
|
return {
|
|
mousemove: function(e4) {
|
|
hoverInfoSender.normalCall(e4);
|
|
},
|
|
mouseout,
|
|
onResetImg: function() {
|
|
hoverInfoSender.immediateCall(null);
|
|
},
|
|
onResize: null
|
|
};
|
|
}
|
|
function createBrushHandler(inputId, $el, opts, coordmap, outputId) {
|
|
const expandPixels = 20;
|
|
const brush = createBrush($el, opts, coordmap, expandPixels);
|
|
$el.on("shiny-internal:brushed.image_output", function(e4, coords) {
|
|
if (coords.brushId === inputId && coords.outputId !== outputId) {
|
|
$el.data("mostRecentBrush", false);
|
|
brush.reset();
|
|
}
|
|
});
|
|
function setCursorStyle(style) {
|
|
$el.removeClass(
|
|
"crosshair grabbable grabbing ns-resize ew-resize nesw-resize nwse-resize"
|
|
);
|
|
if (style) $el.addClass(style);
|
|
}
|
|
function sendBrushInfo() {
|
|
const coords = brush.boundsData();
|
|
if (isNaN(coords.xmin)) {
|
|
shinySetInputValue(inputId, null);
|
|
findImageOutputs(document.documentElement).trigger(
|
|
"shiny-internal:brushed",
|
|
{
|
|
brushId: inputId,
|
|
outputId: null
|
|
}
|
|
);
|
|
return;
|
|
}
|
|
const panel = brush.getPanel();
|
|
import_jquery31.default.extend(coords, panel.panel_vars);
|
|
coords.coords_css = brush.boundsCss();
|
|
coords.coords_img = coordmap.scaleCssToImg(coords.coords_css);
|
|
coords.img_css_ratio = coordmap.cssToImgScalingRatio();
|
|
coords.mapping = panel.mapping;
|
|
coords.domain = panel.domain;
|
|
coords.range = panel.range;
|
|
coords.log = panel.log;
|
|
coords.direction = opts.brushDirection;
|
|
coords.brushId = inputId;
|
|
coords.outputId = outputId;
|
|
shinySetInputValue(inputId, coords);
|
|
$el.data("mostRecentBrush", true);
|
|
findImageOutputs(document.documentElement).trigger(
|
|
"shiny-internal:brushed",
|
|
coords
|
|
);
|
|
}
|
|
let brushInfoSender;
|
|
if (opts.brushDelayType === "throttle") {
|
|
brushInfoSender = new Throttler(null, sendBrushInfo, opts.brushDelay);
|
|
} else {
|
|
brushInfoSender = new Debouncer(null, sendBrushInfo, opts.brushDelay);
|
|
}
|
|
if (!brush.hasOldBrush()) {
|
|
brushInfoSender.immediateCall();
|
|
}
|
|
function mousedown(e4) {
|
|
if (brush.isBrushing() || brush.isDragging() || brush.isResizing()) return;
|
|
if (e4.which !== 1) return;
|
|
const offsetCss = coordmap.mouseOffsetCss(e4);
|
|
if (opts.brushClip && !coordmap.isInPanelCss(offsetCss, expandPixels))
|
|
return;
|
|
brush.up({ x: NaN, y: NaN });
|
|
brush.down(offsetCss);
|
|
if (brush.isInResizeArea(offsetCss)) {
|
|
brush.startResizing(offsetCss);
|
|
(0, import_jquery31.default)(document).on("mousemove.image_brush", mousemoveResizing).on("mouseup.image_brush", mouseupResizing);
|
|
} else if (brush.isInsideBrush(offsetCss)) {
|
|
brush.startDragging(offsetCss);
|
|
setCursorStyle("grabbing");
|
|
(0, import_jquery31.default)(document).on("mousemove.image_brush", mousemoveDragging).on("mouseup.image_brush", mouseupDragging);
|
|
} else {
|
|
const panel = coordmap.getPanelCss(offsetCss, expandPixels);
|
|
brush.startBrushing(panel.clipImg(coordmap.scaleCssToImg(offsetCss)));
|
|
(0, import_jquery31.default)(document).on("mousemove.image_brush", mousemoveBrushing).on("mouseup.image_brush", mouseupBrushing);
|
|
}
|
|
}
|
|
function mousemove(e4) {
|
|
const offsetCss = coordmap.mouseOffsetCss(e4);
|
|
if (!(brush.isBrushing() || brush.isDragging() || brush.isResizing())) {
|
|
if (brush.isInResizeArea(offsetCss)) {
|
|
const r4 = brush.whichResizeSides(offsetCss);
|
|
if (r4.left && r4.top || r4.right && r4.bottom) {
|
|
setCursorStyle("nwse-resize");
|
|
} else if (r4.left && r4.bottom || r4.right && r4.top) {
|
|
setCursorStyle("nesw-resize");
|
|
} else if (r4.left || r4.right) {
|
|
setCursorStyle("ew-resize");
|
|
} else if (r4.top || r4.bottom) {
|
|
setCursorStyle("ns-resize");
|
|
}
|
|
} else if (brush.isInsideBrush(offsetCss)) {
|
|
setCursorStyle("grabbable");
|
|
} else if (coordmap.isInPanelCss(offsetCss, expandPixels)) {
|
|
setCursorStyle("crosshair");
|
|
} else {
|
|
setCursorStyle(null);
|
|
}
|
|
}
|
|
}
|
|
function mousemoveBrushing(e4) {
|
|
brush.brushTo(coordmap.mouseOffsetCss(e4));
|
|
brushInfoSender.normalCall();
|
|
}
|
|
function mousemoveDragging(e4) {
|
|
brush.dragTo(coordmap.mouseOffsetCss(e4));
|
|
brushInfoSender.normalCall();
|
|
}
|
|
function mousemoveResizing(e4) {
|
|
brush.resizeTo(coordmap.mouseOffsetCss(e4));
|
|
brushInfoSender.normalCall();
|
|
}
|
|
function mouseupBrushing(e4) {
|
|
if (e4.which !== 1) return;
|
|
(0, import_jquery31.default)(document).off("mousemove.image_brush").off("mouseup.image_brush");
|
|
brush.up(coordmap.mouseOffsetCss(e4));
|
|
brush.stopBrushing();
|
|
setCursorStyle("crosshair");
|
|
if (brush.down().x === brush.up().x && brush.down().y === brush.up().y) {
|
|
brush.reset();
|
|
brushInfoSender.immediateCall();
|
|
return;
|
|
}
|
|
if (brushInfoSender.isPending()) brushInfoSender.immediateCall();
|
|
}
|
|
function mouseupDragging(e4) {
|
|
if (e4.which !== 1) return;
|
|
(0, import_jquery31.default)(document).off("mousemove.image_brush").off("mouseup.image_brush");
|
|
brush.up(coordmap.mouseOffsetCss(e4));
|
|
brush.stopDragging();
|
|
setCursorStyle("grabbable");
|
|
if (brushInfoSender.isPending()) brushInfoSender.immediateCall();
|
|
}
|
|
function mouseupResizing(e4) {
|
|
if (e4.which !== 1) return;
|
|
(0, import_jquery31.default)(document).off("mousemove.image_brush").off("mouseup.image_brush");
|
|
brush.up(coordmap.mouseOffsetCss(e4));
|
|
brush.stopResizing();
|
|
if (brushInfoSender.isPending()) brushInfoSender.immediateCall();
|
|
}
|
|
function onResetImg() {
|
|
if (opts.brushResetOnNew) {
|
|
if ($el.data("mostRecentBrush")) {
|
|
brush.reset();
|
|
brushInfoSender.immediateCall();
|
|
}
|
|
}
|
|
}
|
|
if (!opts.brushResetOnNew) {
|
|
if ($el.data("mostRecentBrush")) {
|
|
brush.importOldBrush();
|
|
brushInfoSender.immediateCall();
|
|
}
|
|
}
|
|
function onResize() {
|
|
brush.onResize();
|
|
brushInfoSender.immediateCall();
|
|
}
|
|
return {
|
|
mousedown,
|
|
mousemove,
|
|
onResetImg,
|
|
onResize
|
|
};
|
|
}
|
|
|
|
// srcts/src/imageutils/disableDrag.ts
|
|
function disableDrag($el, $img) {
|
|
$img.css("-webkit-user-drag", "none");
|
|
$img.off("dragstart.image_output");
|
|
$img.on("dragstart.image_output", function() {
|
|
return false;
|
|
});
|
|
$el.off("selectstart.image_output");
|
|
$el.on("selectstart.image_output", function() {
|
|
return false;
|
|
});
|
|
}
|
|
|
|
// srcts/src/bindings/output/image.ts
|
|
var ImageOutputBinding = class extends OutputBinding {
|
|
find(scope) {
|
|
return findImageOutputs(scope);
|
|
}
|
|
renderValue(el, data) {
|
|
const outputId = this.getId(el);
|
|
const $el = (0, import_jquery32.default)(el);
|
|
let img;
|
|
let $img = $el.find("img");
|
|
if ($img.length === 0) {
|
|
img = document.createElement("img");
|
|
$el.append(img);
|
|
$img = (0, import_jquery32.default)(img);
|
|
} else {
|
|
img = $img[0];
|
|
$img.trigger("reset");
|
|
}
|
|
if (!data) {
|
|
$el.empty();
|
|
return;
|
|
}
|
|
const opts = {
|
|
clickId: $el.data("click-id"),
|
|
clickClip: ifUndefined(strToBool($el.data("click-clip")), true),
|
|
dblclickId: $el.data("dblclick-id"),
|
|
dblclickClip: ifUndefined(strToBool($el.data("dblclick-clip")), true),
|
|
dblclickDelay: ifUndefined($el.data("dblclick-delay"), 400),
|
|
hoverId: $el.data("hover-id"),
|
|
hoverClip: ifUndefined(strToBool($el.data("hover-clip")), true),
|
|
hoverDelayType: ifUndefined($el.data("hover-delay-type"), "debounce"),
|
|
hoverDelay: ifUndefined($el.data("hover-delay"), 300),
|
|
hoverNullOutside: ifUndefined(
|
|
strToBool($el.data("hover-null-outside")),
|
|
false
|
|
),
|
|
brushId: $el.data("brush-id"),
|
|
brushClip: ifUndefined(strToBool($el.data("brush-clip")), true),
|
|
brushDelayType: ifUndefined($el.data("brush-delay-type"), "debounce"),
|
|
brushDelay: ifUndefined($el.data("brush-delay"), 300),
|
|
brushFill: ifUndefined($el.data("brush-fill"), "#666"),
|
|
brushStroke: ifUndefined($el.data("brush-stroke"), "#000"),
|
|
brushOpacity: ifUndefined($el.data("brush-opacity"), 0.3),
|
|
brushDirection: ifUndefined($el.data("brush-direction"), "xy"),
|
|
brushResetOnNew: ifUndefined(
|
|
strToBool($el.data("brush-reset-on-new")),
|
|
false
|
|
),
|
|
coordmap: data.coordmap
|
|
};
|
|
if (opts.brushFill === "auto") {
|
|
opts.brushFill = getComputedLinkColor($el[0]);
|
|
}
|
|
if (opts.brushStroke === "auto") {
|
|
opts.brushStroke = getStyle($el[0], "color");
|
|
}
|
|
import_jquery32.default.each(data, function(key, value) {
|
|
if (value === null || key === "coordmap") {
|
|
return;
|
|
}
|
|
if (key === "src" && value === img.getAttribute("src")) {
|
|
img.removeAttribute("src");
|
|
}
|
|
img.setAttribute(key, value);
|
|
});
|
|
for (let i5 = 0; i5 < img.attributes.length; i5++) {
|
|
const attrib = img.attributes[i5];
|
|
if (attrib.specified && !hasOwnProperty(data, attrib.name)) {
|
|
img.removeAttribute(attrib.name);
|
|
}
|
|
}
|
|
if (!opts.coordmap) {
|
|
opts.coordmap = {
|
|
panels: [],
|
|
dims: {
|
|
// These values be set to the naturalWidth and naturalHeight once the image has loaded
|
|
height: null,
|
|
width: null
|
|
}
|
|
};
|
|
}
|
|
$el.off(".image_output");
|
|
$img.off(".image_output");
|
|
$img.off("load.shiny_image_interaction");
|
|
$img.one("load.shiny_image_interaction", function() {
|
|
const optsCoordmap = opts.coordmap = initCoordmap($el, opts.coordmap);
|
|
const clickInfo = createClickInfo(
|
|
$el,
|
|
opts.dblclickId,
|
|
opts.dblclickDelay
|
|
);
|
|
$el.on("mousedown.image_output", clickInfo.mousedown);
|
|
if (isIE() && IEVersion() === 8) {
|
|
$el.on("dblclick.image_output", clickInfo.dblclickIE8);
|
|
}
|
|
if (opts.clickId) {
|
|
disableDrag($el, $img);
|
|
const clickHandler = createClickHandler(
|
|
opts.clickId,
|
|
opts.clickClip,
|
|
optsCoordmap
|
|
);
|
|
$el.on("mousedown2.image_output", clickHandler.mousedown);
|
|
$el.on("resize.image_output", clickHandler.onResize);
|
|
$img.on("reset.image_output", clickHandler.onResetImg);
|
|
}
|
|
if (opts.dblclickId) {
|
|
disableDrag($el, $img);
|
|
const dblclickHandler = createClickHandler(
|
|
opts.dblclickId,
|
|
opts.clickClip,
|
|
optsCoordmap
|
|
);
|
|
$el.on("dblclick2.image_output", dblclickHandler.mousedown);
|
|
$el.on("resize.image_output", dblclickHandler.onResize);
|
|
$img.on("reset.image_output", dblclickHandler.onResetImg);
|
|
}
|
|
if (opts.hoverId) {
|
|
disableDrag($el, $img);
|
|
const hoverHandler = createHoverHandler(
|
|
opts.hoverId,
|
|
opts.hoverDelay,
|
|
opts.hoverDelayType,
|
|
opts.hoverClip,
|
|
opts.hoverNullOutside,
|
|
optsCoordmap
|
|
);
|
|
$el.on("mousemove.image_output", hoverHandler.mousemove);
|
|
$el.on("mouseout.image_output", hoverHandler.mouseout);
|
|
$el.on("resize.image_output", hoverHandler.onResize);
|
|
$img.on("reset.image_output", hoverHandler.onResetImg);
|
|
}
|
|
if (opts.brushId) {
|
|
disableDrag($el, $img);
|
|
const brushHandler = createBrushHandler(
|
|
opts.brushId,
|
|
$el,
|
|
opts,
|
|
optsCoordmap,
|
|
outputId
|
|
);
|
|
$el.on("mousedown.image_output", brushHandler.mousedown);
|
|
$el.on("mousemove.image_output", brushHandler.mousemove);
|
|
$el.on("resize.image_output", brushHandler.onResize);
|
|
$img.on("reset.image_output", brushHandler.onResetImg);
|
|
}
|
|
if (opts.clickId || opts.dblclickId || opts.hoverId || opts.brushId) {
|
|
$el.addClass("crosshair");
|
|
}
|
|
if (data.error)
|
|
console.log("Error on server extracting coordmap: " + data.error);
|
|
});
|
|
}
|
|
renderError(el, err) {
|
|
(0, import_jquery32.default)(el).find("img").trigger("reset");
|
|
OutputBinding.prototype.renderError.call(this, el, err);
|
|
}
|
|
clearError(el) {
|
|
(0, import_jquery32.default)(el).contents().filter(function() {
|
|
return !(this instanceof HTMLElement && (this.tagName === "IMG" || this.id === el.id + "_brush"));
|
|
}).remove();
|
|
OutputBinding.prototype.clearError.call(this, el);
|
|
}
|
|
resize(el, width, height) {
|
|
(0, import_jquery32.default)(el).find("img").trigger("resize");
|
|
return;
|
|
width;
|
|
height;
|
|
}
|
|
};
|
|
var imageOutputBinding = new ImageOutputBinding();
|
|
|
|
// srcts/src/bindings/output/text.ts
|
|
var import_jquery33 = __toESM(require_jquery());
|
|
var TextOutputBinding = class extends OutputBinding {
|
|
find(scope) {
|
|
return (0, import_jquery33.default)(scope).find(".shiny-text-output");
|
|
}
|
|
renderValue(el, data) {
|
|
(0, import_jquery33.default)(el).text(data);
|
|
}
|
|
};
|
|
|
|
// srcts/src/bindings/output/index.ts
|
|
function initOutputBindings() {
|
|
const outputBindings = new BindingRegistry();
|
|
outputBindings.register(new TextOutputBinding(), "shiny.textOutput");
|
|
outputBindings.register(
|
|
new DownloadLinkOutputBinding(),
|
|
"shiny.downloadLink"
|
|
);
|
|
outputBindings.register(
|
|
new DatatableOutputBinding(),
|
|
"shiny.datatableOutput"
|
|
);
|
|
outputBindings.register(new HtmlOutputBinding(), "shiny.htmlOutput");
|
|
outputBindings.register(imageOutputBinding, "shiny.imageOutput");
|
|
return { outputBindings };
|
|
}
|
|
|
|
// node_modules/@lit/reactive-element/css-tag.js
|
|
var t = globalThis;
|
|
var e = t.ShadowRoot && (void 0 === t.ShadyCSS || t.ShadyCSS.nativeShadow) && "adoptedStyleSheets" in Document.prototype && "replace" in CSSStyleSheet.prototype;
|
|
var s = Symbol();
|
|
var o = /* @__PURE__ */ new WeakMap();
|
|
var n = class {
|
|
constructor(t3, e4, o5) {
|
|
if (this._$cssResult$ = true, o5 !== s) throw Error("CSSResult is not constructable. Use `unsafeCSS` or `css` instead.");
|
|
this.cssText = t3, this.t = e4;
|
|
}
|
|
get styleSheet() {
|
|
let t3 = this.o;
|
|
const s4 = this.t;
|
|
if (e && void 0 === t3) {
|
|
const e4 = void 0 !== s4 && 1 === s4.length;
|
|
e4 && (t3 = o.get(s4)), void 0 === t3 && ((this.o = t3 = new CSSStyleSheet()).replaceSync(this.cssText), e4 && o.set(s4, t3));
|
|
}
|
|
return t3;
|
|
}
|
|
toString() {
|
|
return this.cssText;
|
|
}
|
|
};
|
|
var r = (t3) => new n("string" == typeof t3 ? t3 : t3 + "", void 0, s);
|
|
var i = (t3, ...e4) => {
|
|
const o5 = 1 === t3.length ? t3[0] : e4.reduce((e5, s4, o6) => e5 + ((t4) => {
|
|
if (true === t4._$cssResult$) return t4.cssText;
|
|
if ("number" == typeof t4) return t4;
|
|
throw Error("Value passed to 'css' function must be a 'css' function result: " + t4 + ". Use 'unsafeCSS' to pass non-literal values, but take care to ensure page security.");
|
|
})(s4) + t3[o6 + 1], t3[0]);
|
|
return new n(o5, t3, s);
|
|
};
|
|
var S = (s4, o5) => {
|
|
if (e) s4.adoptedStyleSheets = o5.map((t3) => t3 instanceof CSSStyleSheet ? t3 : t3.styleSheet);
|
|
else for (const e4 of o5) {
|
|
const o6 = document.createElement("style"), n4 = t.litNonce;
|
|
void 0 !== n4 && o6.setAttribute("nonce", n4), o6.textContent = e4.cssText, s4.appendChild(o6);
|
|
}
|
|
};
|
|
var c = e ? (t3) => t3 : (t3) => t3 instanceof CSSStyleSheet ? ((t4) => {
|
|
let e4 = "";
|
|
for (const s4 of t4.cssRules) e4 += s4.cssText;
|
|
return r(e4);
|
|
})(t3) : t3;
|
|
|
|
// node_modules/@lit/reactive-element/reactive-element.js
|
|
var { is: i2, defineProperty: e2, getOwnPropertyDescriptor: h, getOwnPropertyNames: r2, getOwnPropertySymbols: o2, getPrototypeOf: n2 } = Object;
|
|
var a = globalThis;
|
|
var c2 = a.trustedTypes;
|
|
var l = c2 ? c2.emptyScript : "";
|
|
var p = a.reactiveElementPolyfillSupport;
|
|
var d = (t3, s4) => t3;
|
|
var u = { toAttribute(t3, s4) {
|
|
switch (s4) {
|
|
case Boolean:
|
|
t3 = t3 ? l : null;
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
t3 = null == t3 ? t3 : JSON.stringify(t3);
|
|
}
|
|
return t3;
|
|
}, fromAttribute(t3, s4) {
|
|
let i5 = t3;
|
|
switch (s4) {
|
|
case Boolean:
|
|
i5 = null !== t3;
|
|
break;
|
|
case Number:
|
|
i5 = null === t3 ? null : Number(t3);
|
|
break;
|
|
case Object:
|
|
case Array:
|
|
try {
|
|
i5 = JSON.parse(t3);
|
|
} catch (t4) {
|
|
i5 = null;
|
|
}
|
|
}
|
|
return i5;
|
|
} };
|
|
var f = (t3, s4) => !i2(t3, s4);
|
|
var b = { attribute: true, type: String, converter: u, reflect: false, useDefault: false, hasChanged: f };
|
|
Symbol.metadata ??= Symbol("metadata"), a.litPropertyMetadata ??= /* @__PURE__ */ new WeakMap();
|
|
var y = class extends HTMLElement {
|
|
static addInitializer(t3) {
|
|
this._$Ei(), (this.l ??= []).push(t3);
|
|
}
|
|
static get observedAttributes() {
|
|
return this.finalize(), this._$Eh && [...this._$Eh.keys()];
|
|
}
|
|
static createProperty(t3, s4 = b) {
|
|
if (s4.state && (s4.attribute = false), this._$Ei(), this.prototype.hasOwnProperty(t3) && ((s4 = Object.create(s4)).wrapped = true), this.elementProperties.set(t3, s4), !s4.noAccessor) {
|
|
const i5 = Symbol(), h3 = this.getPropertyDescriptor(t3, i5, s4);
|
|
void 0 !== h3 && e2(this.prototype, t3, h3);
|
|
}
|
|
}
|
|
static getPropertyDescriptor(t3, s4, i5) {
|
|
const { get: e4, set: r4 } = h(this.prototype, t3) ?? { get() {
|
|
return this[s4];
|
|
}, set(t4) {
|
|
this[s4] = t4;
|
|
} };
|
|
return { get: e4, set(s5) {
|
|
const h3 = e4?.call(this);
|
|
r4?.call(this, s5), this.requestUpdate(t3, h3, i5);
|
|
}, configurable: true, enumerable: true };
|
|
}
|
|
static getPropertyOptions(t3) {
|
|
return this.elementProperties.get(t3) ?? b;
|
|
}
|
|
static _$Ei() {
|
|
if (this.hasOwnProperty(d("elementProperties"))) return;
|
|
const t3 = n2(this);
|
|
t3.finalize(), void 0 !== t3.l && (this.l = [...t3.l]), this.elementProperties = new Map(t3.elementProperties);
|
|
}
|
|
static finalize() {
|
|
if (this.hasOwnProperty(d("finalized"))) return;
|
|
if (this.finalized = true, this._$Ei(), this.hasOwnProperty(d("properties"))) {
|
|
const t4 = this.properties, s4 = [...r2(t4), ...o2(t4)];
|
|
for (const i5 of s4) this.createProperty(i5, t4[i5]);
|
|
}
|
|
const t3 = this[Symbol.metadata];
|
|
if (null !== t3) {
|
|
const s4 = litPropertyMetadata.get(t3);
|
|
if (void 0 !== s4) for (const [t4, i5] of s4) this.elementProperties.set(t4, i5);
|
|
}
|
|
this._$Eh = /* @__PURE__ */ new Map();
|
|
for (const [t4, s4] of this.elementProperties) {
|
|
const i5 = this._$Eu(t4, s4);
|
|
void 0 !== i5 && this._$Eh.set(i5, t4);
|
|
}
|
|
this.elementStyles = this.finalizeStyles(this.styles);
|
|
}
|
|
static finalizeStyles(s4) {
|
|
const i5 = [];
|
|
if (Array.isArray(s4)) {
|
|
const e4 = new Set(s4.flat(1 / 0).reverse());
|
|
for (const s5 of e4) i5.unshift(c(s5));
|
|
} else void 0 !== s4 && i5.push(c(s4));
|
|
return i5;
|
|
}
|
|
static _$Eu(t3, s4) {
|
|
const i5 = s4.attribute;
|
|
return false === i5 ? void 0 : "string" == typeof i5 ? i5 : "string" == typeof t3 ? t3.toLowerCase() : void 0;
|
|
}
|
|
constructor() {
|
|
super(), this._$Ep = void 0, this.isUpdatePending = false, this.hasUpdated = false, this._$Em = null, this._$Ev();
|
|
}
|
|
_$Ev() {
|
|
this._$ES = new Promise((t3) => this.enableUpdating = t3), this._$AL = /* @__PURE__ */ new Map(), this._$E_(), this.requestUpdate(), this.constructor.l?.forEach((t3) => t3(this));
|
|
}
|
|
addController(t3) {
|
|
(this._$EO ??= /* @__PURE__ */ new Set()).add(t3), void 0 !== this.renderRoot && this.isConnected && t3.hostConnected?.();
|
|
}
|
|
removeController(t3) {
|
|
this._$EO?.delete(t3);
|
|
}
|
|
_$E_() {
|
|
const t3 = /* @__PURE__ */ new Map(), s4 = this.constructor.elementProperties;
|
|
for (const i5 of s4.keys()) this.hasOwnProperty(i5) && (t3.set(i5, this[i5]), delete this[i5]);
|
|
t3.size > 0 && (this._$Ep = t3);
|
|
}
|
|
createRenderRoot() {
|
|
const t3 = this.shadowRoot ?? this.attachShadow(this.constructor.shadowRootOptions);
|
|
return S(t3, this.constructor.elementStyles), t3;
|
|
}
|
|
connectedCallback() {
|
|
this.renderRoot ??= this.createRenderRoot(), this.enableUpdating(true), this._$EO?.forEach((t3) => t3.hostConnected?.());
|
|
}
|
|
enableUpdating(t3) {
|
|
}
|
|
disconnectedCallback() {
|
|
this._$EO?.forEach((t3) => t3.hostDisconnected?.());
|
|
}
|
|
attributeChangedCallback(t3, s4, i5) {
|
|
this._$AK(t3, i5);
|
|
}
|
|
_$ET(t3, s4) {
|
|
const i5 = this.constructor.elementProperties.get(t3), e4 = this.constructor._$Eu(t3, i5);
|
|
if (void 0 !== e4 && true === i5.reflect) {
|
|
const h3 = (void 0 !== i5.converter?.toAttribute ? i5.converter : u).toAttribute(s4, i5.type);
|
|
this._$Em = t3, null == h3 ? this.removeAttribute(e4) : this.setAttribute(e4, h3), this._$Em = null;
|
|
}
|
|
}
|
|
_$AK(t3, s4) {
|
|
const i5 = this.constructor, e4 = i5._$Eh.get(t3);
|
|
if (void 0 !== e4 && this._$Em !== e4) {
|
|
const t4 = i5.getPropertyOptions(e4), h3 = "function" == typeof t4.converter ? { fromAttribute: t4.converter } : void 0 !== t4.converter?.fromAttribute ? t4.converter : u;
|
|
this._$Em = e4;
|
|
const r4 = h3.fromAttribute(s4, t4.type);
|
|
this[e4] = r4 ?? this._$Ej?.get(e4) ?? r4, this._$Em = null;
|
|
}
|
|
}
|
|
requestUpdate(t3, s4, i5) {
|
|
if (void 0 !== t3) {
|
|
const e4 = this.constructor, h3 = this[t3];
|
|
if (i5 ??= e4.getPropertyOptions(t3), !((i5.hasChanged ?? f)(h3, s4) || i5.useDefault && i5.reflect && h3 === this._$Ej?.get(t3) && !this.hasAttribute(e4._$Eu(t3, i5)))) return;
|
|
this.C(t3, s4, i5);
|
|
}
|
|
false === this.isUpdatePending && (this._$ES = this._$EP());
|
|
}
|
|
C(t3, s4, { useDefault: i5, reflect: e4, wrapped: h3 }, r4) {
|
|
i5 && !(this._$Ej ??= /* @__PURE__ */ new Map()).has(t3) && (this._$Ej.set(t3, r4 ?? s4 ?? this[t3]), true !== h3 || void 0 !== r4) || (this._$AL.has(t3) || (this.hasUpdated || i5 || (s4 = void 0), this._$AL.set(t3, s4)), true === e4 && this._$Em !== t3 && (this._$Eq ??= /* @__PURE__ */ new Set()).add(t3));
|
|
}
|
|
async _$EP() {
|
|
this.isUpdatePending = true;
|
|
try {
|
|
await this._$ES;
|
|
} catch (t4) {
|
|
Promise.reject(t4);
|
|
}
|
|
const t3 = this.scheduleUpdate();
|
|
return null != t3 && await t3, !this.isUpdatePending;
|
|
}
|
|
scheduleUpdate() {
|
|
return this.performUpdate();
|
|
}
|
|
performUpdate() {
|
|
if (!this.isUpdatePending) return;
|
|
if (!this.hasUpdated) {
|
|
if (this.renderRoot ??= this.createRenderRoot(), this._$Ep) {
|
|
for (const [t5, s5] of this._$Ep) this[t5] = s5;
|
|
this._$Ep = void 0;
|
|
}
|
|
const t4 = this.constructor.elementProperties;
|
|
if (t4.size > 0) for (const [s5, i5] of t4) {
|
|
const { wrapped: t5 } = i5, e4 = this[s5];
|
|
true !== t5 || this._$AL.has(s5) || void 0 === e4 || this.C(s5, void 0, i5, e4);
|
|
}
|
|
}
|
|
let t3 = false;
|
|
const s4 = this._$AL;
|
|
try {
|
|
t3 = this.shouldUpdate(s4), t3 ? (this.willUpdate(s4), this._$EO?.forEach((t4) => t4.hostUpdate?.()), this.update(s4)) : this._$EM();
|
|
} catch (s5) {
|
|
throw t3 = false, this._$EM(), s5;
|
|
}
|
|
t3 && this._$AE(s4);
|
|
}
|
|
willUpdate(t3) {
|
|
}
|
|
_$AE(t3) {
|
|
this._$EO?.forEach((t4) => t4.hostUpdated?.()), this.hasUpdated || (this.hasUpdated = true, this.firstUpdated(t3)), this.updated(t3);
|
|
}
|
|
_$EM() {
|
|
this._$AL = /* @__PURE__ */ new Map(), this.isUpdatePending = false;
|
|
}
|
|
get updateComplete() {
|
|
return this.getUpdateComplete();
|
|
}
|
|
getUpdateComplete() {
|
|
return this._$ES;
|
|
}
|
|
shouldUpdate(t3) {
|
|
return true;
|
|
}
|
|
update(t3) {
|
|
this._$Eq &&= this._$Eq.forEach((t4) => this._$ET(t4, this[t4])), this._$EM();
|
|
}
|
|
updated(t3) {
|
|
}
|
|
firstUpdated(t3) {
|
|
}
|
|
};
|
|
y.elementStyles = [], y.shadowRootOptions = { mode: "open" }, y[d("elementProperties")] = /* @__PURE__ */ new Map(), y[d("finalized")] = /* @__PURE__ */ new Map(), p?.({ ReactiveElement: y }), (a.reactiveElementVersions ??= []).push("2.1.1");
|
|
|
|
// node_modules/lit-html/lit-html.js
|
|
var t2 = globalThis;
|
|
var i3 = t2.trustedTypes;
|
|
var s2 = i3 ? i3.createPolicy("lit-html", { createHTML: (t3) => t3 }) : void 0;
|
|
var e3 = "$lit$";
|
|
var h2 = `lit$${Math.random().toFixed(9).slice(2)}$`;
|
|
var o3 = "?" + h2;
|
|
var n3 = `<${o3}>`;
|
|
var r3 = document;
|
|
var l2 = () => r3.createComment("");
|
|
var c3 = (t3) => null === t3 || "object" != typeof t3 && "function" != typeof t3;
|
|
var a2 = Array.isArray;
|
|
var u2 = (t3) => a2(t3) || "function" == typeof t3?.[Symbol.iterator];
|
|
var d2 = "[ \n\f\r]";
|
|
var f2 = /<(?:(!--|\/[^a-zA-Z])|(\/?[a-zA-Z][^>\s]*)|(\/?$))/g;
|
|
var v = /-->/g;
|
|
var _ = />/g;
|
|
var m = RegExp(`>|${d2}(?:([^\\s"'>=/]+)(${d2}*=${d2}*(?:[^
|
|
\f\r"'\`<>=]|("|')|))|$)`, "g");
|
|
var p2 = /'/g;
|
|
var g = /"/g;
|
|
var $34 = /^(?:script|style|textarea|title)$/i;
|
|
var y2 = (t3) => (i5, ...s4) => ({ _$litType$: t3, strings: i5, values: s4 });
|
|
var x = y2(1);
|
|
var b2 = y2(2);
|
|
var w = y2(3);
|
|
var T = Symbol.for("lit-noChange");
|
|
var E = Symbol.for("lit-nothing");
|
|
var A = /* @__PURE__ */ new WeakMap();
|
|
var C = r3.createTreeWalker(r3, 129);
|
|
function P(t3, i5) {
|
|
if (!a2(t3) || !t3.hasOwnProperty("raw")) throw Error("invalid template strings array");
|
|
return void 0 !== s2 ? s2.createHTML(i5) : i5;
|
|
}
|
|
var V = (t3, i5) => {
|
|
const s4 = t3.length - 1, o5 = [];
|
|
let r4, l3 = 2 === i5 ? "<svg>" : 3 === i5 ? "<math>" : "", c4 = f2;
|
|
for (let i6 = 0; i6 < s4; i6++) {
|
|
const s5 = t3[i6];
|
|
let a3, u3, d3 = -1, y3 = 0;
|
|
for (; y3 < s5.length && (c4.lastIndex = y3, u3 = c4.exec(s5), null !== u3); ) y3 = c4.lastIndex, c4 === f2 ? "!--" === u3[1] ? c4 = v : void 0 !== u3[1] ? c4 = _ : void 0 !== u3[2] ? ($34.test(u3[2]) && (r4 = RegExp("</" + u3[2], "g")), c4 = m) : void 0 !== u3[3] && (c4 = m) : c4 === m ? ">" === u3[0] ? (c4 = r4 ?? f2, d3 = -1) : void 0 === u3[1] ? d3 = -2 : (d3 = c4.lastIndex - u3[2].length, a3 = u3[1], c4 = void 0 === u3[3] ? m : '"' === u3[3] ? g : p2) : c4 === g || c4 === p2 ? c4 = m : c4 === v || c4 === _ ? c4 = f2 : (c4 = m, r4 = void 0);
|
|
const x2 = c4 === m && t3[i6 + 1].startsWith("/>") ? " " : "";
|
|
l3 += c4 === f2 ? s5 + n3 : d3 >= 0 ? (o5.push(a3), s5.slice(0, d3) + e3 + s5.slice(d3) + h2 + x2) : s5 + h2 + (-2 === d3 ? i6 : x2);
|
|
}
|
|
return [P(t3, l3 + (t3[s4] || "<?>") + (2 === i5 ? "</svg>" : 3 === i5 ? "</math>" : "")), o5];
|
|
};
|
|
var N = class _N {
|
|
constructor({ strings: t3, _$litType$: s4 }, n4) {
|
|
let r4;
|
|
this.parts = [];
|
|
let c4 = 0, a3 = 0;
|
|
const u3 = t3.length - 1, d3 = this.parts, [f3, v2] = V(t3, s4);
|
|
if (this.el = _N.createElement(f3, n4), C.currentNode = this.el.content, 2 === s4 || 3 === s4) {
|
|
const t4 = this.el.content.firstChild;
|
|
t4.replaceWith(...t4.childNodes);
|
|
}
|
|
for (; null !== (r4 = C.nextNode()) && d3.length < u3; ) {
|
|
if (1 === r4.nodeType) {
|
|
if (r4.hasAttributes()) for (const t4 of r4.getAttributeNames()) if (t4.endsWith(e3)) {
|
|
const i5 = v2[a3++], s5 = r4.getAttribute(t4).split(h2), e4 = /([.?@])?(.*)/.exec(i5);
|
|
d3.push({ type: 1, index: c4, name: e4[2], strings: s5, ctor: "." === e4[1] ? H : "?" === e4[1] ? I : "@" === e4[1] ? L : k }), r4.removeAttribute(t4);
|
|
} else t4.startsWith(h2) && (d3.push({ type: 6, index: c4 }), r4.removeAttribute(t4));
|
|
if ($34.test(r4.tagName)) {
|
|
const t4 = r4.textContent.split(h2), s5 = t4.length - 1;
|
|
if (s5 > 0) {
|
|
r4.textContent = i3 ? i3.emptyScript : "";
|
|
for (let i5 = 0; i5 < s5; i5++) r4.append(t4[i5], l2()), C.nextNode(), d3.push({ type: 2, index: ++c4 });
|
|
r4.append(t4[s5], l2());
|
|
}
|
|
}
|
|
} else if (8 === r4.nodeType) if (r4.data === o3) d3.push({ type: 2, index: c4 });
|
|
else {
|
|
let t4 = -1;
|
|
for (; -1 !== (t4 = r4.data.indexOf(h2, t4 + 1)); ) d3.push({ type: 7, index: c4 }), t4 += h2.length - 1;
|
|
}
|
|
c4++;
|
|
}
|
|
}
|
|
static createElement(t3, i5) {
|
|
const s4 = r3.createElement("template");
|
|
return s4.innerHTML = t3, s4;
|
|
}
|
|
};
|
|
function S2(t3, i5, s4 = t3, e4) {
|
|
if (i5 === T) return i5;
|
|
let h3 = void 0 !== e4 ? s4._$Co?.[e4] : s4._$Cl;
|
|
const o5 = c3(i5) ? void 0 : i5._$litDirective$;
|
|
return h3?.constructor !== o5 && (h3?._$AO?.(false), void 0 === o5 ? h3 = void 0 : (h3 = new o5(t3), h3._$AT(t3, s4, e4)), void 0 !== e4 ? (s4._$Co ??= [])[e4] = h3 : s4._$Cl = h3), void 0 !== h3 && (i5 = S2(t3, h3._$AS(t3, i5.values), h3, e4)), i5;
|
|
}
|
|
var M = class {
|
|
constructor(t3, i5) {
|
|
this._$AV = [], this._$AN = void 0, this._$AD = t3, this._$AM = i5;
|
|
}
|
|
get parentNode() {
|
|
return this._$AM.parentNode;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
u(t3) {
|
|
const { el: { content: i5 }, parts: s4 } = this._$AD, e4 = (t3?.creationScope ?? r3).importNode(i5, true);
|
|
C.currentNode = e4;
|
|
let h3 = C.nextNode(), o5 = 0, n4 = 0, l3 = s4[0];
|
|
for (; void 0 !== l3; ) {
|
|
if (o5 === l3.index) {
|
|
let i6;
|
|
2 === l3.type ? i6 = new R(h3, h3.nextSibling, this, t3) : 1 === l3.type ? i6 = new l3.ctor(h3, l3.name, l3.strings, this, t3) : 6 === l3.type && (i6 = new z(h3, this, t3)), this._$AV.push(i6), l3 = s4[++n4];
|
|
}
|
|
o5 !== l3?.index && (h3 = C.nextNode(), o5++);
|
|
}
|
|
return C.currentNode = r3, e4;
|
|
}
|
|
p(t3) {
|
|
let i5 = 0;
|
|
for (const s4 of this._$AV) void 0 !== s4 && (void 0 !== s4.strings ? (s4._$AI(t3, s4, i5), i5 += s4.strings.length - 2) : s4._$AI(t3[i5])), i5++;
|
|
}
|
|
};
|
|
var R = class _R {
|
|
get _$AU() {
|
|
return this._$AM?._$AU ?? this._$Cv;
|
|
}
|
|
constructor(t3, i5, s4, e4) {
|
|
this.type = 2, this._$AH = E, this._$AN = void 0, this._$AA = t3, this._$AB = i5, this._$AM = s4, this.options = e4, this._$Cv = e4?.isConnected ?? true;
|
|
}
|
|
get parentNode() {
|
|
let t3 = this._$AA.parentNode;
|
|
const i5 = this._$AM;
|
|
return void 0 !== i5 && 11 === t3?.nodeType && (t3 = i5.parentNode), t3;
|
|
}
|
|
get startNode() {
|
|
return this._$AA;
|
|
}
|
|
get endNode() {
|
|
return this._$AB;
|
|
}
|
|
_$AI(t3, i5 = this) {
|
|
t3 = S2(this, t3, i5), c3(t3) ? t3 === E || null == t3 || "" === t3 ? (this._$AH !== E && this._$AR(), this._$AH = E) : t3 !== this._$AH && t3 !== T && this._(t3) : void 0 !== t3._$litType$ ? this.$(t3) : void 0 !== t3.nodeType ? this.T(t3) : u2(t3) ? this.k(t3) : this._(t3);
|
|
}
|
|
O(t3) {
|
|
return this._$AA.parentNode.insertBefore(t3, this._$AB);
|
|
}
|
|
T(t3) {
|
|
this._$AH !== t3 && (this._$AR(), this._$AH = this.O(t3));
|
|
}
|
|
_(t3) {
|
|
this._$AH !== E && c3(this._$AH) ? this._$AA.nextSibling.data = t3 : this.T(r3.createTextNode(t3)), this._$AH = t3;
|
|
}
|
|
$(t3) {
|
|
const { values: i5, _$litType$: s4 } = t3, e4 = "number" == typeof s4 ? this._$AC(t3) : (void 0 === s4.el && (s4.el = N.createElement(P(s4.h, s4.h[0]), this.options)), s4);
|
|
if (this._$AH?._$AD === e4) this._$AH.p(i5);
|
|
else {
|
|
const t4 = new M(e4, this), s5 = t4.u(this.options);
|
|
t4.p(i5), this.T(s5), this._$AH = t4;
|
|
}
|
|
}
|
|
_$AC(t3) {
|
|
let i5 = A.get(t3.strings);
|
|
return void 0 === i5 && A.set(t3.strings, i5 = new N(t3)), i5;
|
|
}
|
|
k(t3) {
|
|
a2(this._$AH) || (this._$AH = [], this._$AR());
|
|
const i5 = this._$AH;
|
|
let s4, e4 = 0;
|
|
for (const h3 of t3) e4 === i5.length ? i5.push(s4 = new _R(this.O(l2()), this.O(l2()), this, this.options)) : s4 = i5[e4], s4._$AI(h3), e4++;
|
|
e4 < i5.length && (this._$AR(s4 && s4._$AB.nextSibling, e4), i5.length = e4);
|
|
}
|
|
_$AR(t3 = this._$AA.nextSibling, i5) {
|
|
for (this._$AP?.(false, true, i5); t3 !== this._$AB; ) {
|
|
const i6 = t3.nextSibling;
|
|
t3.remove(), t3 = i6;
|
|
}
|
|
}
|
|
setConnected(t3) {
|
|
void 0 === this._$AM && (this._$Cv = t3, this._$AP?.(t3));
|
|
}
|
|
};
|
|
var k = class {
|
|
get tagName() {
|
|
return this.element.tagName;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
constructor(t3, i5, s4, e4, h3) {
|
|
this.type = 1, this._$AH = E, this._$AN = void 0, this.element = t3, this.name = i5, this._$AM = e4, this.options = h3, s4.length > 2 || "" !== s4[0] || "" !== s4[1] ? (this._$AH = Array(s4.length - 1).fill(new String()), this.strings = s4) : this._$AH = E;
|
|
}
|
|
_$AI(t3, i5 = this, s4, e4) {
|
|
const h3 = this.strings;
|
|
let o5 = false;
|
|
if (void 0 === h3) t3 = S2(this, t3, i5, 0), o5 = !c3(t3) || t3 !== this._$AH && t3 !== T, o5 && (this._$AH = t3);
|
|
else {
|
|
const e5 = t3;
|
|
let n4, r4;
|
|
for (t3 = h3[0], n4 = 0; n4 < h3.length - 1; n4++) r4 = S2(this, e5[s4 + n4], i5, n4), r4 === T && (r4 = this._$AH[n4]), o5 ||= !c3(r4) || r4 !== this._$AH[n4], r4 === E ? t3 = E : t3 !== E && (t3 += (r4 ?? "") + h3[n4 + 1]), this._$AH[n4] = r4;
|
|
}
|
|
o5 && !e4 && this.j(t3);
|
|
}
|
|
j(t3) {
|
|
t3 === E ? this.element.removeAttribute(this.name) : this.element.setAttribute(this.name, t3 ?? "");
|
|
}
|
|
};
|
|
var H = class extends k {
|
|
constructor() {
|
|
super(...arguments), this.type = 3;
|
|
}
|
|
j(t3) {
|
|
this.element[this.name] = t3 === E ? void 0 : t3;
|
|
}
|
|
};
|
|
var I = class extends k {
|
|
constructor() {
|
|
super(...arguments), this.type = 4;
|
|
}
|
|
j(t3) {
|
|
this.element.toggleAttribute(this.name, !!t3 && t3 !== E);
|
|
}
|
|
};
|
|
var L = class extends k {
|
|
constructor(t3, i5, s4, e4, h3) {
|
|
super(t3, i5, s4, e4, h3), this.type = 5;
|
|
}
|
|
_$AI(t3, i5 = this) {
|
|
if ((t3 = S2(this, t3, i5, 0) ?? E) === T) return;
|
|
const s4 = this._$AH, e4 = t3 === E && s4 !== E || t3.capture !== s4.capture || t3.once !== s4.once || t3.passive !== s4.passive, h3 = t3 !== E && (s4 === E || e4);
|
|
e4 && this.element.removeEventListener(this.name, this, s4), h3 && this.element.addEventListener(this.name, this, t3), this._$AH = t3;
|
|
}
|
|
handleEvent(t3) {
|
|
"function" == typeof this._$AH ? this._$AH.call(this.options?.host ?? this.element, t3) : this._$AH.handleEvent(t3);
|
|
}
|
|
};
|
|
var z = class {
|
|
constructor(t3, i5, s4) {
|
|
this.element = t3, this.type = 6, this._$AN = void 0, this._$AM = i5, this.options = s4;
|
|
}
|
|
get _$AU() {
|
|
return this._$AM._$AU;
|
|
}
|
|
_$AI(t3) {
|
|
S2(this, t3);
|
|
}
|
|
};
|
|
var j = t2.litHtmlPolyfillSupport;
|
|
j?.(N, R), (t2.litHtmlVersions ??= []).push("3.3.1");
|
|
var B = (t3, i5, s4) => {
|
|
const e4 = s4?.renderBefore ?? i5;
|
|
let h3 = e4._$litPart$;
|
|
if (void 0 === h3) {
|
|
const t4 = s4?.renderBefore ?? null;
|
|
e4._$litPart$ = h3 = new R(i5.insertBefore(l2(), t4), t4, void 0, s4 ?? {});
|
|
}
|
|
return h3._$AI(t3), h3;
|
|
};
|
|
|
|
// node_modules/lit-element/lit-element.js
|
|
var s3 = globalThis;
|
|
var i4 = class extends y {
|
|
constructor() {
|
|
super(...arguments), this.renderOptions = { host: this }, this._$Do = void 0;
|
|
}
|
|
createRenderRoot() {
|
|
const t3 = super.createRenderRoot();
|
|
return this.renderOptions.renderBefore ??= t3.firstChild, t3;
|
|
}
|
|
update(t3) {
|
|
const r4 = this.render();
|
|
this.hasUpdated || (this.renderOptions.isConnected = this.isConnected), super.update(t3), this._$Do = B(r4, this.renderRoot, this.renderOptions);
|
|
}
|
|
connectedCallback() {
|
|
super.connectedCallback(), this._$Do?.setConnected(true);
|
|
}
|
|
disconnectedCallback() {
|
|
super.disconnectedCallback(), this._$Do?.setConnected(false);
|
|
}
|
|
render() {
|
|
return T;
|
|
}
|
|
};
|
|
i4._$litElement$ = true, i4["finalized"] = true, s3.litElementHydrateSupport?.({ LitElement: i4 });
|
|
var o4 = s3.litElementPolyfillSupport;
|
|
o4?.({ LitElement: i4 });
|
|
(s3.litElementVersions ??= []).push("4.2.1");
|
|
|
|
// srcts/src/shiny/error.ts
|
|
var ShinyClientError = class extends Error {
|
|
constructor({ headline, message }) {
|
|
super(message);
|
|
this.name = "ShinyClientError";
|
|
this.headline = headline;
|
|
}
|
|
};
|
|
|
|
// srcts/src/components/errorConsole.ts
|
|
var buttonStyles = i`
|
|
button {
|
|
background-color: transparent;
|
|
outline: none;
|
|
border-style: none;
|
|
padding: var(--space-3);
|
|
border-radius: var(--space-1);
|
|
font-size: var(--font-lg);
|
|
background-color: inherit;
|
|
display: block;
|
|
}
|
|
|
|
button > svg {
|
|
display: block;
|
|
}
|
|
`;
|
|
var _ShinyErrorConsole = class _ShinyErrorConsole extends i4 {
|
|
toggleCollapsed() {
|
|
this.classList.toggle("collapsed");
|
|
this.querySelector(".toggle-button")?.blur();
|
|
}
|
|
handleDismissAll() {
|
|
this.classList.add("leaving");
|
|
this.addEventListener("animationend", () => {
|
|
this.remove();
|
|
});
|
|
}
|
|
static createClientMessageElement({ headline, message }) {
|
|
const msg = document.createElement("shiny-error-message");
|
|
msg.setAttribute("headline", headline || "");
|
|
msg.setAttribute("message", message);
|
|
return msg;
|
|
}
|
|
appendConsoleMessage({ headline, message }) {
|
|
const content = this.shadowRoot?.querySelector("slot.content");
|
|
if (content) {
|
|
const nodeKey = (node) => {
|
|
const headline2 = node.getAttribute("headline") || "";
|
|
const message2 = node.getAttribute("message") || "";
|
|
return `${headline2}::${message2}`;
|
|
};
|
|
const newKey = `${headline}::${message}`;
|
|
for (const node of content.assignedElements()) {
|
|
if (node.tagName.toLowerCase() === "shiny-error-message") {
|
|
if (nodeKey(node) === newKey) {
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.appendChild(
|
|
_ShinyErrorConsole.createClientMessageElement({ headline, message })
|
|
);
|
|
return;
|
|
}
|
|
render() {
|
|
return x` <div class="header">
|
|
<span class="title"> Shiny Client Errors </span>
|
|
<button
|
|
class="close-button"
|
|
@click=${this.handleDismissAll}
|
|
title="Dismiss all console messages and close console"
|
|
>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
height="1em"
|
|
width="1em"
|
|
stroke="currentColor"
|
|
class="close-icon"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M6 18L18 6M6 6l12 12"
|
|
/>
|
|
</svg>
|
|
Dismiss all
|
|
</button>
|
|
<button class="toggle-button" @click=${this.toggleCollapsed}>
|
|
<svg
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
height="1em"
|
|
width="1em"
|
|
stroke="currentColor"
|
|
class="toggle-icon"
|
|
>
|
|
<path
|
|
class="collapse"
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M4.5 19.5l15-15m0 0H8.25m11.25 0v11.25"
|
|
/>
|
|
</svg>
|
|
</button>
|
|
</div>
|
|
<slot class="content"></slot>`;
|
|
}
|
|
};
|
|
_ShinyErrorConsole.styles = [
|
|
i`
|
|
:host {
|
|
/* We declare hard pixel values here to avoid body font size changes
|
|
messing up the size of the console. This was an issue with bslib setting
|
|
the body font-size at 16px relative to base shiny's 14px. */
|
|
--font-md: 14px;
|
|
--font-lg: 16px;
|
|
--font-xl: 18px;
|
|
|
|
/* These are all taken from open-props */
|
|
--space-1: 6px;
|
|
--space-2: calc(var(--space-1) * 2);
|
|
--space-3: calc(var(--space-1) * 3);
|
|
--space-4: calc(var(--space-1) * 4);
|
|
--space-8: calc(var(--space-1) * 8);
|
|
|
|
--red-2: #ffc9c9;
|
|
--red-6: #fa5252;
|
|
--red-7: #f03e3e;
|
|
--red-8: #e03131;
|
|
--red-10: #b02525;
|
|
--red-11: #962020;
|
|
--red-12: #7d1a1a;
|
|
|
|
--gray-1: #f8f9fa;
|
|
--gray-2: #e9ecef;
|
|
--gray-3: #dee2e6;
|
|
--gray-4: #ced4da;
|
|
--gray-6: #868e96;
|
|
--gray-8: #6c757d;
|
|
|
|
--green-8: #51cf66;
|
|
|
|
--shadow-color: 220 3% 15%;
|
|
--shadow-strength: 1%;
|
|
--shadow-3:
|
|
0 -1px 3px 0
|
|
hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
|
|
0 1px 2px -5px
|
|
hsl(var(--shadow-color) / calc(var(--shadow-strength) + 2%)),
|
|
0 2px 5px -5px
|
|
hsl(var(--shadow-color) / calc(var(--shadow-strength) + 4%)),
|
|
0 4px 12px -5px
|
|
hsl(var(--shadow-color) / calc(var(--shadow-strength) + 5%)),
|
|
0 12px 15px -5px
|
|
hsl(var(--shadow-color) / calc(var(--shadow-strength) + 7%));
|
|
|
|
--ring-shadow: 0 0 0 1px var(--gray-2);
|
|
|
|
/* How fast should the message pop in and out of the screen? */
|
|
--animation-speed: 500ms;
|
|
|
|
/* Taken from open-props */
|
|
--ease-3: cubic-bezier(0.25, 0, 0.3, 1);
|
|
--animation-slide-in-left: slide-in-left var(--animation-speed)
|
|
var(--ease-3);
|
|
|
|
--animation-slide-out-left: slide-out-left var(--animation-speed)
|
|
var(--ease-3);
|
|
--modal-bg-color: white;
|
|
|
|
position: fixed;
|
|
top: var(--space-1);
|
|
right: var(--space-1);
|
|
z-index: 1000;
|
|
|
|
display: flex;
|
|
flex-direction: column;
|
|
|
|
background-color: var(--modal-bg-color);
|
|
border-radius: var(--space-1);
|
|
|
|
animation: var(--animation-slide-in-left);
|
|
box-shadow: var(--shadow-3), var(--ring-shadow);
|
|
|
|
/* Dont let the error console burst out of the viewport */
|
|
max-height: calc(100vh - 2 * var(--space-1));
|
|
}
|
|
|
|
@keyframes slide-in-left {
|
|
from {
|
|
transform: translateX(100%);
|
|
}
|
|
}
|
|
@keyframes slide-out-left {
|
|
to {
|
|
transform: translateX(100%);
|
|
}
|
|
}
|
|
|
|
:host(.leaving) {
|
|
animation: var(--animation-slide-out-left);
|
|
}
|
|
|
|
.header {
|
|
display: flex;
|
|
justify-content: flex-end;
|
|
align-items: flex-start;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.title {
|
|
font-size: var(--font-xl);
|
|
margin-right: auto;
|
|
padding: var(--space-3);
|
|
line-height: 1;
|
|
font-weight: 600;
|
|
color: var(--red-12);
|
|
}
|
|
|
|
${buttonStyles}
|
|
|
|
button:hover {
|
|
background-color: var(--gray-2);
|
|
}
|
|
|
|
.toggle-button {
|
|
width: fit-content;
|
|
border: none;
|
|
aspect-ratio: 1;
|
|
border-color: var(--gray-4);
|
|
}
|
|
|
|
.close-button {
|
|
display: flex;
|
|
align-items: center;
|
|
color: var(--red-11);
|
|
}
|
|
|
|
.close-button > svg {
|
|
margin-right: 3px;
|
|
}
|
|
|
|
.toggle-button:focus {
|
|
outline: 1px solid black;
|
|
}
|
|
|
|
.toggle-icon {
|
|
transition: transform var(--animation-speed) ease-in-out;
|
|
}
|
|
|
|
:host(.collapsed) .toggle-icon {
|
|
transform: scaleX(-1) scaleY(-1);
|
|
}
|
|
|
|
:host(.collapsed) .close-button {
|
|
display: none;
|
|
}
|
|
|
|
.content {
|
|
display: block;
|
|
padding-inline: var(--space-4);
|
|
padding-block-start: 0;
|
|
padding-block-end: var(--space-4);
|
|
max-height: 100%;
|
|
overflow: auto;
|
|
}
|
|
|
|
:host(.collapsed) .content {
|
|
display: none;
|
|
}
|
|
`
|
|
];
|
|
var ShinyErrorConsole = _ShinyErrorConsole;
|
|
customElements.define("shiny-error-console", ShinyErrorConsole);
|
|
var ShinyErrorMessage = class extends i4 {
|
|
constructor() {
|
|
super(...arguments);
|
|
this.headline = "";
|
|
this.message = "";
|
|
}
|
|
async copyErrorToClipboard() {
|
|
await navigator.clipboard.writeText(this.message);
|
|
this.classList.add("copy-success");
|
|
setTimeout(() => {
|
|
this.classList.remove("copy-success");
|
|
}, 1e3);
|
|
}
|
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
render() {
|
|
return x`
|
|
<div class="container">
|
|
<div class="decoration-container">
|
|
<div class="vertical-line"></div>
|
|
<div class="dot"></div>
|
|
</div>
|
|
<div class="contents">
|
|
<h3>${this.headline}</h3>
|
|
<pre class="error-message">${this.message}</pre>
|
|
</div>
|
|
|
|
<div class="actions">
|
|
<button
|
|
class="copy-button"
|
|
@click=${this.copyErrorToClipboard}
|
|
title="Copy error to clipboard"
|
|
>
|
|
<div class="copy-button-inner">
|
|
<svg
|
|
class="front"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
stroke="currentColor"
|
|
height="1em"
|
|
width="1em"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M15.666 3.888A2.25 2.25 0 0013.5 2.25h-3c-1.03 0-1.9.693-2.166 1.638m7.332 0c.055.194.084.4.084.612v0a.75.75 0 01-.75.75H9a.75.75 0 01-.75-.75v0c0-.212.03-.418.084-.612m7.332 0c.646.049 1.288.11 1.927.184 1.1.128 1.907 1.077 1.907 2.185V19.5a2.25 2.25 0 01-2.25 2.25H6.75A2.25 2.25 0 014.5 19.5V6.257c0-1.108.806-2.057 1.907-2.185a48.208 48.208 0 011.927-.184"
|
|
/>
|
|
</svg>
|
|
|
|
<svg
|
|
class="back"
|
|
xmlns="http://www.w3.org/2000/svg"
|
|
fill="none"
|
|
viewBox="0 0 24 24"
|
|
stroke-width="1.5"
|
|
stroke="currentColor"
|
|
height="1em"
|
|
width="1em"
|
|
>
|
|
<path
|
|
stroke-linecap="round"
|
|
stroke-linejoin="round"
|
|
d="M9 12.75L11.25 15 15 9.75M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
|
|
/>
|
|
</svg>
|
|
</div>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
`;
|
|
}
|
|
};
|
|
ShinyErrorMessage.properties = {
|
|
headline: {},
|
|
message: {}
|
|
};
|
|
ShinyErrorMessage.styles = [
|
|
i`
|
|
:host {
|
|
color: var(--red-11);
|
|
display: block;
|
|
font-size: var(--font-md);
|
|
|
|
position: relative;
|
|
--icon-size: var(--font-lg) /* Reset box sizing */
|
|
box-sizing: border-box;
|
|
}
|
|
|
|
.container {
|
|
display: flex;
|
|
gap: var(--space-2);
|
|
}
|
|
|
|
.contents {
|
|
width: 40ch;
|
|
display: flex;
|
|
flex-direction: column;
|
|
gap: var(--space-1);
|
|
padding-block-start: 0;
|
|
padding-block-end: var(--space-3);
|
|
overflow: auto;
|
|
}
|
|
|
|
:host(:last-of-type) .contents {
|
|
padding-block-end: var(--space-1);
|
|
}
|
|
|
|
.contents > h3 {
|
|
font-size: 1em;
|
|
font-weight: 500;
|
|
color: var(--red-12);
|
|
}
|
|
|
|
.contents > * {
|
|
margin-block: 0;
|
|
}
|
|
|
|
.error-message {
|
|
font-family: "Courier New", Courier, monospace;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.decoration-container {
|
|
flex-shrink: 0;
|
|
position: relative;
|
|
|
|
--line-w: 2px;
|
|
--dot-size: 11px;
|
|
}
|
|
|
|
:host(:hover) .decoration-container {
|
|
--scale: 1.25;
|
|
}
|
|
|
|
.vertical-line {
|
|
margin-inline: auto;
|
|
width: var(--line-w);
|
|
height: 100%;
|
|
|
|
background-color: var(--red-10);
|
|
}
|
|
|
|
:host(:first-of-type) .vertical-line {
|
|
height: calc(100% - var(--dot-size));
|
|
margin-top: var(--dot-size);
|
|
}
|
|
|
|
.dot {
|
|
position: absolute;
|
|
width: var(--dot-size);
|
|
height: var(--dot-size);
|
|
top: calc(-1px + var(--dot-size) / 2);
|
|
left: calc(50% - var(--dot-size) / 2);
|
|
border-radius: 100%;
|
|
transform: scale(var(--scale, 1));
|
|
|
|
color: var(--red-6);
|
|
background-color: var(--red-10);
|
|
}
|
|
|
|
.actions {
|
|
transform: scaleX(0);
|
|
transition: transform calc(var(--animation-speed) / 2) ease-in-out;
|
|
display: flex;
|
|
justify-content: center;
|
|
flex-direction: column;
|
|
}
|
|
|
|
/* Delay transition on mouseout so the buttons don't jump away if the user
|
|
overshoots them with their mouse */
|
|
:host(:not(:hover)) .actions {
|
|
transition-delay: 0.15s;
|
|
}
|
|
|
|
:host(:hover) .actions {
|
|
transform: scaleX(1);
|
|
}
|
|
|
|
${buttonStyles}
|
|
|
|
.copy-button {
|
|
padding: 0;
|
|
width: var(--space-8);
|
|
height: var(--space-8);
|
|
position: relative;
|
|
--pad: var(--space-2);
|
|
}
|
|
|
|
.copy-button-inner {
|
|
position: relative;
|
|
width: 100%;
|
|
height: 100%;
|
|
border-radius: inherit;
|
|
transition: transform 0.5s;
|
|
transform-style: preserve-3d;
|
|
}
|
|
|
|
/* Animate flipping to the other side when the .copy-success class is
|
|
added to the host */
|
|
:host(.copy-success) .copy-button-inner {
|
|
transform: rotateY(180deg);
|
|
}
|
|
|
|
/* Position the front and back side */
|
|
.copy-button .front,
|
|
.copy-button .back {
|
|
--side: calc(100% - 2 * var(--pad));
|
|
position: absolute;
|
|
inset: var(--pad);
|
|
height: var(--side);
|
|
width: var(--side);
|
|
-webkit-backface-visibility: hidden; /* Safari */
|
|
backface-visibility: hidden;
|
|
}
|
|
|
|
.copy-button:hover .copy-button-inner {
|
|
background-color: var(--gray-2);
|
|
}
|
|
|
|
/* Style the back side */
|
|
.copy-button .back {
|
|
--pad: var(--space-1);
|
|
color: var(--green-8);
|
|
transform: rotateY(180deg);
|
|
}
|
|
`
|
|
];
|
|
customElements.define("shiny-error-message", ShinyErrorMessage);
|
|
function showShinyClientMessage({
|
|
headline = "",
|
|
message,
|
|
status = "warning"
|
|
}) {
|
|
const consoleMessage = `[shiny] ${headline}${headline ? " - " : ""}${message}`;
|
|
switch (status) {
|
|
case "error":
|
|
console.error(consoleMessage);
|
|
break;
|
|
case "warning":
|
|
console.warn(consoleMessage);
|
|
break;
|
|
default:
|
|
console.log(consoleMessage);
|
|
break;
|
|
}
|
|
if (!isShinyInDevMode()) {
|
|
return;
|
|
}
|
|
let sec = document.querySelector("shiny-error-console");
|
|
if (!sec) {
|
|
sec = document.createElement("shiny-error-console");
|
|
document.body.appendChild(sec);
|
|
}
|
|
sec.appendConsoleMessage({ headline, message });
|
|
}
|
|
function showErrorInClientConsole(e4) {
|
|
let errorMsg = null;
|
|
let headline = "Error on client while running Shiny app";
|
|
if (typeof e4 === "string") {
|
|
errorMsg = e4;
|
|
} else if (e4 instanceof ShinyClientError) {
|
|
errorMsg = e4.message;
|
|
headline = e4.headline;
|
|
} else if (e4 instanceof Error) {
|
|
errorMsg = e4.message;
|
|
} else {
|
|
errorMsg = "Unknown error";
|
|
}
|
|
showShinyClientMessage({ headline, message: errorMsg, status: "error" });
|
|
}
|
|
var ShinyClientMessageEvent = class extends CustomEvent {
|
|
constructor(detail) {
|
|
super("shiny:client-message", { detail, bubbles: true, cancelable: true });
|
|
}
|
|
};
|
|
window.addEventListener("shiny:client-message", (ev) => {
|
|
if (!(ev instanceof CustomEvent)) {
|
|
throw new Error("[shiny] shiny:client-message expected a CustomEvent");
|
|
}
|
|
const { headline, message, status } = ev.detail;
|
|
if (!message) {
|
|
throw new Error(
|
|
"[shiny] shiny:client-message expected a `message` property in `event.detail`."
|
|
);
|
|
}
|
|
showShinyClientMessage({ headline, message, status });
|
|
});
|
|
|
|
// srcts/src/imageutils/resetBrush.ts
|
|
function resetBrush(brushId) {
|
|
shinySetInputValue(brushId, null);
|
|
imageOutputBinding.find(document.documentElement).trigger("shiny-internal:brushed", {
|
|
brushId,
|
|
outputId: null
|
|
});
|
|
}
|
|
|
|
// srcts/src/inputPolicies/inputBatchSender.ts
|
|
var InputBatchSender = class {
|
|
constructor(shinyapp) {
|
|
this.pendingData = {};
|
|
this.reentrant = false;
|
|
this.sendIsEnqueued = false;
|
|
this.lastChanceCallback = [];
|
|
this.shinyapp = shinyapp;
|
|
}
|
|
setInput(nameType, value, opts) {
|
|
this.pendingData[nameType] = value;
|
|
if (!this.reentrant) {
|
|
if (opts.priority === "event") {
|
|
this._sendNow();
|
|
} else if (!this.sendIsEnqueued) {
|
|
this.shinyapp.taskQueue.enqueue(() => {
|
|
this.sendIsEnqueued = false;
|
|
this._sendNow();
|
|
});
|
|
}
|
|
}
|
|
}
|
|
_sendNow() {
|
|
if (this.reentrant) {
|
|
console.trace("Unexpected reentrancy in InputBatchSender!");
|
|
}
|
|
this.reentrant = true;
|
|
try {
|
|
this.lastChanceCallback.forEach((callback) => callback());
|
|
const currentData = this.pendingData;
|
|
this.pendingData = {};
|
|
this.shinyapp.sendInput(currentData);
|
|
} finally {
|
|
this.reentrant = false;
|
|
}
|
|
}
|
|
};
|
|
|
|
// srcts/src/inputPolicies/inputDeferDecorator.ts
|
|
var InputDeferDecorator = class {
|
|
constructor(target) {
|
|
this.pendingInput = {};
|
|
this.target = target;
|
|
}
|
|
setInput(nameType, value, opts) {
|
|
if (/^\./.test(nameType)) this.target.setInput(nameType, value, opts);
|
|
else this.pendingInput[nameType] = { value, opts };
|
|
}
|
|
submit() {
|
|
for (const nameType in this.pendingInput) {
|
|
if (hasDefinedProperty(this.pendingInput, nameType)) {
|
|
const { value, opts } = this.pendingInput[nameType];
|
|
this.target.setInput(nameType, value, opts);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
// srcts/src/inputPolicies/inputEventDecorator.ts
|
|
var import_jquery34 = __toESM(require_jquery());
|
|
|
|
// srcts/src/inputPolicies/splitInputNameType.ts
|
|
function splitInputNameType(nameType) {
|
|
const name2 = nameType.split(":");
|
|
return {
|
|
name: name2[0],
|
|
inputType: name2.length > 1 ? name2[1] : ""
|
|
};
|
|
}
|
|
|
|
// srcts/src/inputPolicies/inputEventDecorator.ts
|
|
var InputEventDecorator = class {
|
|
constructor(target) {
|
|
this.target = target;
|
|
}
|
|
setInput(nameType, value, opts) {
|
|
const evt = import_jquery34.default.Event("shiny:inputchanged");
|
|
const input = splitInputNameType(nameType);
|
|
evt.name = input.name;
|
|
evt.inputType = input.inputType;
|
|
evt.value = value;
|
|
evt.binding = opts.binding || null;
|
|
evt.el = opts.el || null;
|
|
evt.priority = opts.priority;
|
|
(0, import_jquery34.default)(opts.el || window.document).trigger(evt);
|
|
if (!evt.isDefaultPrevented()) {
|
|
let name = evt.name;
|
|
if (evt.inputType !== "") name += ":" + evt.inputType;
|
|
this.target.setInput(name, evt.value, { priority: opts.priority });
|
|
}
|
|
}
|
|
};
|
|
|
|
// srcts/src/inputPolicies/inputNoResendDecorator.ts
|
|
var InputNoResendDecorator = class {
|
|
constructor(target, initialValues = {}) {
|
|
this.lastSentValues = {};
|
|
this.target = target;
|
|
this.reset(initialValues);
|
|
}
|
|
setInput(nameType, value, opts) {
|
|
const { name: inputName, inputType } = splitInputNameType(nameType);
|
|
const jsonValue = JSON.stringify(value);
|
|
if (opts.priority !== "event" && this.lastSentValues[inputName] && this.lastSentValues[inputName].jsonValue === jsonValue && this.lastSentValues[inputName].inputType === inputType) {
|
|
return;
|
|
}
|
|
this.lastSentValues[inputName] = { jsonValue, inputType };
|
|
this.target.setInput(nameType, value, opts);
|
|
}
|
|
reset(values = {}) {
|
|
const cacheValues = {};
|
|
for (const inputName in values) {
|
|
if (hasDefinedProperty(values, inputName)) {
|
|
const { name, inputType } = splitInputNameType(inputName);
|
|
cacheValues[name] = {
|
|
jsonValue: JSON.stringify(values[inputName]),
|
|
inputType
|
|
};
|
|
}
|
|
}
|
|
this.lastSentValues = cacheValues;
|
|
}
|
|
forget(name) {
|
|
delete this.lastSentValues[name];
|
|
}
|
|
};
|
|
|
|
// srcts/src/inputPolicies/inputRateDecorator.ts
|
|
var InputRateDecorator = class {
|
|
constructor(target) {
|
|
this.inputRatePolicies = {};
|
|
this.target = target;
|
|
}
|
|
// Note that the first argument of setInput() and setRatePolicy()
|
|
// are passed both the input name (i.e., inputId) and type.
|
|
// https://github.com/rstudio/shiny/blob/67d3a/srcjs/init_shiny.js#L111-L126
|
|
// However, $ensureInit() and $doSetInput() are meant to be passed just
|
|
// the input name (i.e., inputId), which is why we distinguish between
|
|
// nameType and name.
|
|
setInput(nameType, value, opts) {
|
|
const { name: inputName } = splitInputNameType(nameType);
|
|
this._ensureInit(inputName);
|
|
if (opts.priority !== "deferred")
|
|
this.inputRatePolicies[inputName].immediateCall(nameType, value, opts);
|
|
else this.inputRatePolicies[inputName].normalCall(nameType, value, opts);
|
|
}
|
|
setRatePolicy(nameType, mode, millis) {
|
|
const { name: inputName } = splitInputNameType(nameType);
|
|
if (mode === "direct") {
|
|
this.inputRatePolicies[inputName] = new Invoker(this, this._doSetInput);
|
|
} else if (mode === "debounce") {
|
|
this.inputRatePolicies[inputName] = new Debouncer(
|
|
this,
|
|
this._doSetInput,
|
|
millis
|
|
);
|
|
} else if (mode === "throttle") {
|
|
this.inputRatePolicies[inputName] = new Throttler(
|
|
this,
|
|
this._doSetInput,
|
|
millis
|
|
);
|
|
}
|
|
}
|
|
_ensureInit(name) {
|
|
if (!(name in this.inputRatePolicies)) this.setRatePolicy(name, "direct");
|
|
}
|
|
_doSetInput(nameType, value, opts) {
|
|
this.target.setInput(nameType, value, opts);
|
|
}
|
|
};
|
|
|
|
// srcts/src/inputPolicies/inputValidateDecorator.ts
|
|
function addDefaultInputOpts(opts) {
|
|
const newOpts = {
|
|
priority: "immediate",
|
|
...opts
|
|
};
|
|
switch (newOpts.priority) {
|
|
case "deferred":
|
|
case "immediate":
|
|
case "event":
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
"Unexpected input value mode: '" + newOpts.priority + "'"
|
|
);
|
|
}
|
|
return newOpts;
|
|
}
|
|
var InputValidateDecorator = class {
|
|
constructor(target) {
|
|
this.target = target;
|
|
}
|
|
setInput(nameType, value, opts = {}) {
|
|
if (!nameType) throw "Can't set input with empty name.";
|
|
const newOpts = addDefaultInputOpts(opts);
|
|
this.target.setInput(nameType, value, newOpts);
|
|
}
|
|
};
|
|
|
|
// srcts/src/utils/promise.ts
|
|
function promiseWithResolvers() {
|
|
let resolve;
|
|
let reject;
|
|
const promise = new Promise(
|
|
(res, rej) => {
|
|
resolve = res;
|
|
reject = rej;
|
|
}
|
|
);
|
|
return { promise, resolve, reject };
|
|
}
|
|
function createInitStatus() {
|
|
const { promise, resolve } = promiseWithResolvers();
|
|
let _resolved = false;
|
|
return {
|
|
promise,
|
|
resolve(x2) {
|
|
_resolved = true;
|
|
resolve(x2);
|
|
},
|
|
then: promise.then.bind(promise),
|
|
catch: promise.catch.bind(promise),
|
|
finally: promise.finally.bind(promise),
|
|
[Symbol.toStringTag]: "InitStatus",
|
|
resolved() {
|
|
return _resolved;
|
|
}
|
|
};
|
|
}
|
|
|
|
// srcts/src/shiny/bind.ts
|
|
var import_jquery35 = __toESM(require_jquery());
|
|
|
|
// srcts/src/bindings/outputAdapter.ts
|
|
var OutputBindingAdapter = class {
|
|
constructor(el, binding) {
|
|
this.el = el;
|
|
this.binding = binding;
|
|
if (binding.resize) {
|
|
this.onResize = makeResizeFilter(el, function(width, height) {
|
|
binding.resize(el, width, height);
|
|
});
|
|
}
|
|
}
|
|
getId() {
|
|
return this.binding.getId(this.el);
|
|
}
|
|
async onValueChange(data) {
|
|
await this.binding.onValueChange(this.el, data);
|
|
}
|
|
onValueError(err) {
|
|
this.binding.onValueError(this.el, err);
|
|
}
|
|
showProgress(show3) {
|
|
this.binding.showProgress(this.el, show3);
|
|
}
|
|
onResize() {
|
|
}
|
|
};
|
|
|
|
// srcts/src/shiny/bind.ts
|
|
function isJQuery(value) {
|
|
return Boolean(value && value.jquery);
|
|
}
|
|
function valueChangeCallback(inputs, binding, el, priority) {
|
|
let id = binding.getId(el);
|
|
if (id) {
|
|
const value = binding.getValue(el);
|
|
const type = binding.getType(el);
|
|
if (type) id = id + ":" + type;
|
|
const normalizedPriority = normalizeEventPriority(priority);
|
|
inputs.setInput(id, value, { priority: normalizedPriority, binding, el });
|
|
}
|
|
}
|
|
function normalizeEventPriority(priority) {
|
|
if (priority === false || priority === void 0) {
|
|
return "immediate";
|
|
}
|
|
if (priority === true) {
|
|
return "deferred";
|
|
}
|
|
if (typeof priority === "object" && "priority" in priority) {
|
|
return priority.priority;
|
|
}
|
|
return priority;
|
|
}
|
|
var bindingsRegistry = /* @__PURE__ */ (() => {
|
|
const bindings = /* @__PURE__ */ new Map();
|
|
function checkValidity(scope) {
|
|
if (!isJQuery(scope) && !(scope instanceof HTMLElement)) {
|
|
return;
|
|
}
|
|
const duplicateIds = /* @__PURE__ */ new Map();
|
|
const problems = /* @__PURE__ */ new Set();
|
|
bindings.forEach((idTypes, id) => {
|
|
const counts = { input: 0, output: 0 };
|
|
idTypes.forEach((type) => counts[type] += 1);
|
|
if (counts.input + counts.output < 2) {
|
|
return;
|
|
}
|
|
duplicateIds.set(id, counts);
|
|
if (counts.input > 1) {
|
|
problems.add("input");
|
|
}
|
|
if (counts.output > 1) {
|
|
problems.add("output");
|
|
}
|
|
if (counts.input >= 1 && counts.output >= 1) {
|
|
problems.add("shared");
|
|
}
|
|
});
|
|
if (duplicateIds.size === 0) return;
|
|
const duplicateIdMsg = Array.from(duplicateIds.entries()).map(([id, counts]) => {
|
|
const messages = [
|
|
pluralize(counts.input, "input"),
|
|
pluralize(counts.output, "output")
|
|
].filter((msg) => msg !== "").join(" and ");
|
|
return `- "${id}": ${messages}`;
|
|
}).join("\n");
|
|
let txtVerb = "Duplicate";
|
|
let txtNoun = "input/output";
|
|
if (problems.has("input") && problems.has("output")) {
|
|
} else if (problems.has("input")) {
|
|
txtNoun = "input";
|
|
} else if (problems.has("output")) {
|
|
txtNoun = "output";
|
|
} else if (problems.has("shared")) {
|
|
txtVerb = "Shared";
|
|
}
|
|
const txtIdsWere = duplicateIds.size == 1 ? "ID was" : "IDs were";
|
|
const headline = `${txtVerb} ${txtNoun} ${txtIdsWere} found`;
|
|
const message = `The following ${txtIdsWere} used for more than one ${problems.has("shared") ? "input/output" : txtNoun}:
|
|
${duplicateIdMsg}`;
|
|
const event = new ShinyClientMessageEvent({ headline, message });
|
|
const scopeElement = isJQuery(scope) ? scope.get(0) : scope;
|
|
(scopeElement || window).dispatchEvent(event);
|
|
}
|
|
function addBinding(id, bindingType) {
|
|
const existingBinding = bindings.get(id);
|
|
if (existingBinding) {
|
|
existingBinding.push(bindingType);
|
|
} else {
|
|
bindings.set(id, [bindingType]);
|
|
}
|
|
}
|
|
function removeBinding(id, bindingType) {
|
|
const existingBinding = bindings.get(id);
|
|
if (existingBinding) {
|
|
const index = existingBinding.indexOf(bindingType);
|
|
if (index > -1) {
|
|
existingBinding.splice(index, 1);
|
|
}
|
|
}
|
|
if (existingBinding?.length === 0) {
|
|
bindings.delete(id);
|
|
}
|
|
}
|
|
return {
|
|
addBinding,
|
|
removeBinding,
|
|
checkValidity
|
|
};
|
|
})();
|
|
function pluralize(num, word) {
|
|
if (num === 0) return "";
|
|
if (num === 1) return `${num} ${word}`;
|
|
return `${num} ${word}s`;
|
|
}
|
|
function bindInputs(shinyCtx, scope = document.documentElement) {
|
|
const { inputs, inputsRate, inputBindings } = shinyCtx;
|
|
const bindings = inputBindings.getBindings();
|
|
const inputItems = {};
|
|
for (let i5 = 0; i5 < bindings.length; i5++) {
|
|
const binding = bindings[i5].binding;
|
|
const matches = binding.find(scope) || [];
|
|
for (let j2 = 0; j2 < matches.length; j2++) {
|
|
const el = matches[j2];
|
|
if (el.hasAttribute("data-shiny-no-bind-input")) continue;
|
|
const id = binding.getId(el);
|
|
if (!id || (0, import_jquery35.default)(el).hasClass("shiny-bound-input")) continue;
|
|
const type = binding.getType(el);
|
|
const effectiveId = type ? id + ":" + type : id;
|
|
inputItems[effectiveId] = {
|
|
value: binding.getValue(el),
|
|
opts: {
|
|
immediate: true,
|
|
binding,
|
|
el
|
|
}
|
|
};
|
|
const thisCallback = /* @__PURE__ */ function() {
|
|
const thisBinding = binding;
|
|
const thisEl = el;
|
|
return function(priority) {
|
|
valueChangeCallback(inputs, thisBinding, thisEl, priority);
|
|
};
|
|
}();
|
|
binding.subscribe(el, thisCallback);
|
|
(0, import_jquery35.default)(el).data("shiny-input-binding", binding);
|
|
(0, import_jquery35.default)(el).addClass("shiny-bound-input");
|
|
const ratePolicy = binding.getRatePolicy(el);
|
|
if (ratePolicy !== null) {
|
|
inputsRate.setRatePolicy(
|
|
effectiveId,
|
|
ratePolicy.policy,
|
|
ratePolicy.delay
|
|
);
|
|
}
|
|
bindingsRegistry.addBinding(id, "input");
|
|
(0, import_jquery35.default)(el).trigger({
|
|
type: "shiny:bound",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
binding,
|
|
bindingType: "input"
|
|
});
|
|
}
|
|
}
|
|
return inputItems;
|
|
}
|
|
async function bindOutputs({
|
|
sendOutputHiddenState,
|
|
maybeAddThemeObserver,
|
|
outputBindings,
|
|
outputIsRecalculating
|
|
}, scope = document.documentElement) {
|
|
const $scope = (0, import_jquery35.default)(scope);
|
|
const bindings = outputBindings.getBindings();
|
|
for (let i5 = 0; i5 < bindings.length; i5++) {
|
|
const binding = bindings[i5].binding;
|
|
const matches = binding.find($scope) || [];
|
|
for (let j2 = 0; j2 < matches.length; j2++) {
|
|
const el = matches[j2];
|
|
const id = binding.getId(el);
|
|
if (!id) continue;
|
|
if (!import_jquery35.default.contains(document.documentElement, el)) continue;
|
|
const $el = (0, import_jquery35.default)(el);
|
|
if ($el.hasClass("shiny-bound-output")) {
|
|
continue;
|
|
}
|
|
maybeAddThemeObserver(el);
|
|
const bindingAdapter = new OutputBindingAdapter(el, binding);
|
|
await shinyAppBindOutput(id, bindingAdapter);
|
|
$el.data("shiny-output-binding", bindingAdapter);
|
|
$el.addClass("shiny-bound-output");
|
|
if (!$el.attr("aria-live")) $el.attr("aria-live", "polite");
|
|
if (outputIsRecalculating(id)) {
|
|
bindingAdapter.showProgress(true);
|
|
}
|
|
bindingsRegistry.addBinding(id, "output");
|
|
$el.trigger({
|
|
type: "shiny:bound",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
binding,
|
|
bindingType: "output"
|
|
});
|
|
}
|
|
}
|
|
setTimeout(sendImageSizeFns.regular, 0);
|
|
setTimeout(sendOutputHiddenState, 0);
|
|
}
|
|
function unbindInputs(scope = document.documentElement, includeSelf = false) {
|
|
const inputs = (0, import_jquery35.default)(scope).find(".shiny-bound-input").toArray();
|
|
if (includeSelf && (0, import_jquery35.default)(scope).hasClass("shiny-bound-input")) {
|
|
inputs.push(scope);
|
|
}
|
|
for (let i5 = 0; i5 < inputs.length; i5++) {
|
|
const el = inputs[i5];
|
|
const binding = (0, import_jquery35.default)(el).data("shiny-input-binding");
|
|
if (!binding) continue;
|
|
const id = binding.getId(el);
|
|
(0, import_jquery35.default)(el).removeClass("shiny-bound-input");
|
|
bindingsRegistry.removeBinding(id, "input");
|
|
binding.unsubscribe(el);
|
|
(0, import_jquery35.default)(el).trigger({
|
|
type: "shiny:unbound",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
binding,
|
|
bindingType: "input"
|
|
});
|
|
}
|
|
}
|
|
function unbindOutputs({ sendOutputHiddenState }, scope = document.documentElement, includeSelf = false) {
|
|
const outputs = (0, import_jquery35.default)(scope).find(".shiny-bound-output").toArray();
|
|
if (includeSelf && (0, import_jquery35.default)(scope).hasClass("shiny-bound-output")) {
|
|
outputs.push(scope);
|
|
}
|
|
for (let i5 = 0; i5 < outputs.length; i5++) {
|
|
const $el = (0, import_jquery35.default)(outputs[i5]);
|
|
const bindingAdapter = $el.data("shiny-output-binding");
|
|
if (!bindingAdapter) continue;
|
|
const id = bindingAdapter.binding.getId(outputs[i5]);
|
|
shinyAppUnbindOutput(id, bindingAdapter);
|
|
bindingsRegistry.removeBinding(id, "output");
|
|
$el.removeClass("shiny-bound-output");
|
|
$el.removeData("shiny-output-binding");
|
|
$el.trigger({
|
|
type: "shiny:unbound",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
binding: bindingAdapter.binding,
|
|
bindingType: "output"
|
|
});
|
|
}
|
|
setTimeout(sendImageSizeFns.regular, 0);
|
|
setTimeout(sendOutputHiddenState, 0);
|
|
}
|
|
async function _bindAll(shinyCtx, scope) {
|
|
await bindOutputs(shinyCtx, scope);
|
|
const currentInputs = bindInputs(shinyCtx, scope);
|
|
bindingsRegistry.checkValidity(scope);
|
|
return currentInputs;
|
|
}
|
|
function unbindAll(shinyCtx, scope, includeSelf = false) {
|
|
unbindInputs(scope, includeSelf);
|
|
unbindOutputs(shinyCtx, scope, includeSelf);
|
|
}
|
|
async function bindAll(shinyCtx, scope) {
|
|
const currentInputItems = await _bindAll(shinyCtx, scope);
|
|
const inputs = shinyCtx.inputs;
|
|
import_jquery35.default.each(currentInputItems, function(name, item) {
|
|
inputs.setInput(name, item.value, item.opts);
|
|
});
|
|
shinyCtx.initDeferredIframes();
|
|
}
|
|
|
|
// srcts/src/shiny/modal.ts
|
|
var import_jquery36 = __toESM(require_jquery());
|
|
async function show({
|
|
html = "",
|
|
deps = []
|
|
} = {}) {
|
|
await renderDependenciesAsync(deps);
|
|
(0, import_jquery36.default)(".modal-backdrop").remove();
|
|
let $modal = (0, import_jquery36.default)("#shiny-modal-wrapper");
|
|
if ($modal.length === 0) {
|
|
$modal = (0, import_jquery36.default)('<div id="shiny-modal-wrapper"></div>');
|
|
(0, import_jquery36.default)(document.body).append($modal);
|
|
$modal.on("hidden.bs.modal", function(e4) {
|
|
if (e4.target === (0, import_jquery36.default)("#shiny-modal")[0]) {
|
|
shinyUnbindAll($modal);
|
|
$modal.remove();
|
|
}
|
|
});
|
|
}
|
|
$modal.on("keydown.shinymodal", function(e4) {
|
|
if ((0, import_jquery36.default)("#shiny-modal").data("keyboard") === false) return;
|
|
if (e4.keyCode === 27) {
|
|
e4.stopPropagation();
|
|
e4.preventDefault();
|
|
}
|
|
});
|
|
await renderContentAsync($modal, { html });
|
|
}
|
|
function remove() {
|
|
const $modal = (0, import_jquery36.default)("#shiny-modal-wrapper");
|
|
$modal.off("keydown.shinymodal");
|
|
const $bsModal = $modal.find(".modal");
|
|
if ($bsModal.length > 0) {
|
|
$bsModal.on("shown.bs.modal", () => $bsModal.modal("hide"));
|
|
$bsModal.modal("hide");
|
|
} else {
|
|
shinyUnbindAll($modal);
|
|
$modal.remove();
|
|
}
|
|
}
|
|
|
|
// srcts/src/shiny/notifications.ts
|
|
var import_jquery37 = __toESM(require_jquery());
|
|
var fadeDuration = 250;
|
|
async function show2({
|
|
html = "",
|
|
action = "",
|
|
deps = [],
|
|
duration = 5e3,
|
|
id = null,
|
|
closeButton = true,
|
|
type = null
|
|
} = {}) {
|
|
if (!id) id = randomId();
|
|
await renderDependenciesAsync(deps);
|
|
createPanel();
|
|
let $notificationInit = get(id);
|
|
if ($notificationInit?.length === 0) $notificationInit = create(id);
|
|
const $notification = $notificationInit;
|
|
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");
|
|
await renderContentAsync($content, { html: newHtml });
|
|
const classes = $notification?.attr("class");
|
|
if (classes) {
|
|
const classVal = classes.split(/\s+/).filter((cls) => cls.match(/^shiny-notification-/)).join(" ");
|
|
$notification.removeClass(classVal);
|
|
}
|
|
if (type && type !== "default")
|
|
$notification.addClass("shiny-notification-" + type);
|
|
const $close = $notification.find(".shiny-notification-close");
|
|
if (closeButton && $close.length === 0) {
|
|
$notification.append('<div class="shiny-notification-close">×</div>');
|
|
} else if (!closeButton && $close.length !== 0) {
|
|
$close.remove();
|
|
}
|
|
if (duration) addRemovalCallback(id, duration);
|
|
else clearRemovalCallback(id);
|
|
return id;
|
|
}
|
|
function remove2(id) {
|
|
get(id)?.fadeOut(fadeDuration, function() {
|
|
shinyUnbindAll(this);
|
|
(0, import_jquery37.default)(this).remove();
|
|
if (ids().length === 0) {
|
|
getPanel().remove();
|
|
}
|
|
});
|
|
}
|
|
function get(id) {
|
|
if (!id) return null;
|
|
return getPanel().find("#shiny-notification-" + $escape(id));
|
|
}
|
|
function ids() {
|
|
return getPanel().find(".shiny-notification").map(function() {
|
|
return this.id.replace(/shiny-notification-/, "");
|
|
}).get();
|
|
}
|
|
function getPanel() {
|
|
return (0, import_jquery37.default)("#shiny-notification-panel");
|
|
}
|
|
function createPanel() {
|
|
const $panel = getPanel();
|
|
if ($panel.length > 0) return $panel;
|
|
(0, import_jquery37.default)(document.body).append('<div id="shiny-notification-panel">');
|
|
return $panel;
|
|
}
|
|
function create(id) {
|
|
let $notification = get(id);
|
|
if ($notification?.length === 0) {
|
|
$notification = (0, import_jquery37.default)(
|
|
`<div id="shiny-notification-${id}" class="shiny-notification"><div class="shiny-notification-close">×</div><div class="shiny-notification-content"></div></div>`
|
|
);
|
|
$notification.find(".shiny-notification-close").on("click", (e4) => {
|
|
e4.preventDefault();
|
|
e4.stopPropagation();
|
|
remove2(id);
|
|
});
|
|
getPanel().append($notification);
|
|
}
|
|
return $notification;
|
|
}
|
|
function addRemovalCallback(id, delay) {
|
|
clearRemovalCallback(id);
|
|
const removalCallback = setTimeout(function() {
|
|
remove2(id);
|
|
}, delay);
|
|
get(id)?.data("removalCallback", removalCallback);
|
|
}
|
|
function clearRemovalCallback(id) {
|
|
const $notification = get(id);
|
|
const oldRemovalCallback = $notification?.data("removalCallback");
|
|
if (oldRemovalCallback) {
|
|
clearTimeout(oldRemovalCallback);
|
|
}
|
|
}
|
|
|
|
// srcts/src/shiny/reconnectDialog.ts
|
|
var import_jquery38 = __toESM(require_jquery());
|
|
function updateTime(reconnectTime) {
|
|
const $time = (0, import_jquery38.default)("#shiny-reconnect-time");
|
|
if ($time.length === 0) return;
|
|
const seconds = Math.floor((reconnectTime - (/* @__PURE__ */ new Date()).getTime()) / 1e3);
|
|
if (seconds > 0) {
|
|
$time.text(" in " + seconds + "s");
|
|
} else {
|
|
$time.text("...");
|
|
}
|
|
setTimeout(function() {
|
|
updateTime(reconnectTime);
|
|
}, 1e3);
|
|
}
|
|
async function showReconnectDialog(delay) {
|
|
const reconnectTime = (/* @__PURE__ */ new Date()).getTime() + delay;
|
|
if ((0, import_jquery38.default)("#shiny-reconnect-text").length > 0) return;
|
|
const html = '<span id="shiny-reconnect-text">Attempting to reconnect</span><span id="shiny-reconnect-time"></span>';
|
|
const action = '<a id="shiny-reconnect-now" href="#" onclick="Shiny.shinyapp.reconnect();">Try now</a>';
|
|
await show2({
|
|
id: "reconnect",
|
|
html,
|
|
action,
|
|
duration: null,
|
|
closeButton: false,
|
|
type: "warning"
|
|
});
|
|
updateTime(reconnectTime);
|
|
}
|
|
function hideReconnectDialog() {
|
|
remove2("reconnect");
|
|
}
|
|
|
|
// srcts/src/shiny/shinyapp.ts
|
|
var import_jquery39 = __toESM(require_jquery());
|
|
|
|
// srcts/src/utils/asyncQueue.ts
|
|
var AsyncQueue = class {
|
|
constructor() {
|
|
this.$promises = [];
|
|
this.$resolvers = [];
|
|
}
|
|
_add() {
|
|
const p3 = new Promise((resolve) => {
|
|
this.$resolvers.push(resolve);
|
|
});
|
|
this.$promises.push(p3);
|
|
}
|
|
enqueue(x2) {
|
|
if (!this.$resolvers.length) this._add();
|
|
const resolve = this.$resolvers.shift();
|
|
resolve(x2);
|
|
}
|
|
async dequeue() {
|
|
if (!this.$promises.length) this._add();
|
|
const promise = this.$promises.shift();
|
|
return promise;
|
|
}
|
|
isEmpty() {
|
|
return !this.$promises.length;
|
|
}
|
|
isBlocked() {
|
|
return !!this.$resolvers.length;
|
|
}
|
|
get length() {
|
|
return this.$promises.length - this.$resolvers.length;
|
|
}
|
|
};
|
|
|
|
// srcts/src/shiny/outputProgress.ts
|
|
var _OutputProgressReporter_instances, updateStateFromRecalculating_fn, updateStateFromFlush_fn, updateStateFromProgress_fn, updateStateFromValueOrError_fn, getState_fn, setState_fn;
|
|
var OutputProgressReporter = class {
|
|
constructor() {
|
|
__privateAdd(this, _OutputProgressReporter_instances);
|
|
this.outputStates = /* @__PURE__ */ new Map();
|
|
// A map of outputs that have changed their progress status since the last call to takeChanges().
|
|
// The value is true if the output is recalculating, and false otherwise.
|
|
this.changedOutputs = /* @__PURE__ */ new Map();
|
|
}
|
|
takeChanges() {
|
|
const result = this.changedOutputs;
|
|
this.changedOutputs = /* @__PURE__ */ new Map();
|
|
return result;
|
|
}
|
|
// Returns whether the output is recalculating or not.
|
|
isRecalculating(name) {
|
|
const state = __privateMethod(this, _OutputProgressReporter_instances, getState_fn).call(this, name);
|
|
const recalculatingStates = [
|
|
"initial" /* Initial */,
|
|
"running" /* Running */,
|
|
"idle" /* Idle */,
|
|
"persistent" /* Persistent */,
|
|
"invalidated" /* Invalidated */
|
|
];
|
|
return recalculatingStates.includes(state);
|
|
}
|
|
// Update output state based on the message received from the server.
|
|
// Note that any message can be passed to this method, but only the
|
|
// messages that are relevant to output progress do anything to the state.
|
|
updateStateFromMessage(message) {
|
|
if (isRecalculatingMessage(message)) {
|
|
__privateMethod(this, _OutputProgressReporter_instances, updateStateFromRecalculating_fn).call(this, message);
|
|
}
|
|
if (isFlushMessage(message)) {
|
|
__privateMethod(this, _OutputProgressReporter_instances, updateStateFromFlush_fn).call(this, message);
|
|
}
|
|
if (isProgressMessage(message)) {
|
|
__privateMethod(this, _OutputProgressReporter_instances, updateStateFromProgress_fn).call(this, message);
|
|
}
|
|
}
|
|
};
|
|
_OutputProgressReporter_instances = new WeakSet();
|
|
updateStateFromRecalculating_fn = function(message) {
|
|
const { name, status } = message.recalculating;
|
|
const state = __privateMethod(this, _OutputProgressReporter_instances, getState_fn).call(this, name);
|
|
if (status === "recalculating") {
|
|
switch (state) {
|
|
case "initial" /* Initial */:
|
|
case "invalidated" /* Invalidated */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, name, "running" /* Running */);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server sent a message that the output '${name}' is recalculating,
|
|
but the output is in an unexpected state of: '${state}'.`
|
|
);
|
|
}
|
|
}
|
|
if (status === "recalculated") {
|
|
switch (state) {
|
|
case "running" /* Running */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, name, "idle" /* Idle */);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server sent a message that the output '${name}' has been recalculated,
|
|
but the output is in an unexpected state of: '${state}'.`
|
|
);
|
|
}
|
|
}
|
|
};
|
|
updateStateFromFlush_fn = function(message) {
|
|
for (const name in message.values) {
|
|
__privateMethod(this, _OutputProgressReporter_instances, updateStateFromValueOrError_fn).call(this, name, "value" /* Value */);
|
|
}
|
|
for (const name in message.errors) {
|
|
__privateMethod(this, _OutputProgressReporter_instances, updateStateFromValueOrError_fn).call(this, name, "error" /* Error */);
|
|
}
|
|
for (const [name, state] of this.outputStates) {
|
|
switch (state) {
|
|
case "idle" /* Idle */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, name, "cancel" /* Cancel */);
|
|
break;
|
|
case "value" /* Value */:
|
|
case "error" /* Error */:
|
|
case "cancel" /* Cancel */:
|
|
case "persistent" /* Persistent */:
|
|
case "invalidated" /* Invalidated */:
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server sent a flush message, and after processing the values and errors,
|
|
the output '${name}' has an unexpected ending state of: '${state}'.`
|
|
);
|
|
}
|
|
}
|
|
};
|
|
updateStateFromProgress_fn = function(message) {
|
|
const { id, persistent } = message.progress.message;
|
|
const state = __privateMethod(this, _OutputProgressReporter_instances, getState_fn).call(this, id);
|
|
if (persistent) {
|
|
switch (state) {
|
|
case "running" /* Running */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, id, "persistent" /* Persistent */);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server has sent a 'persistent progress' message for ${id},
|
|
but the output is in an unexpected state of: ${state}`
|
|
);
|
|
}
|
|
} else {
|
|
switch (state) {
|
|
case "value" /* Value */:
|
|
case "error" /* Error */:
|
|
case "cancel" /* Cancel */:
|
|
case "persistent" /* Persistent */:
|
|
case "idle" /* Idle */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, id, "invalidated" /* Invalidated */);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server has sent a progress message for ${id},
|
|
but the output is in an unexpected state of: ${state}`
|
|
);
|
|
}
|
|
}
|
|
};
|
|
// When receiving values/errors as part of a flush message, outputs should generally
|
|
// be moving from Idle to Value/Error state.
|
|
updateStateFromValueOrError_fn = function(name, type) {
|
|
const state = __privateMethod(this, _OutputProgressReporter_instances, getState_fn).call(this, name);
|
|
switch (state) {
|
|
case "idle" /* Idle */:
|
|
__privateMethod(this, _OutputProgressReporter_instances, setState_fn).call(this, name, type);
|
|
break;
|
|
default:
|
|
throw new Error(
|
|
`Shiny server has sent a ${type} for the output '${name}',
|
|
but the output is in an unexpected state of: '${state}'.`
|
|
);
|
|
}
|
|
};
|
|
getState_fn = function(name) {
|
|
return this.outputStates.get(name) ?? "initial" /* Initial */;
|
|
};
|
|
setState_fn = function(name, state) {
|
|
const oldRecalc = this.isRecalculating(name);
|
|
this.outputStates.set(name, state);
|
|
const newRecalc = this.isRecalculating(name);
|
|
if (oldRecalc !== newRecalc) {
|
|
this.changedOutputs.set(name, newRecalc);
|
|
}
|
|
};
|
|
function isRecalculatingMessage(x2) {
|
|
const m2 = x2;
|
|
return m2.recalculating !== void 0;
|
|
}
|
|
function isFlushMessage(x2) {
|
|
const m2 = x2;
|
|
return m2.values !== void 0 && m2.errors !== void 0;
|
|
}
|
|
function isProgressMessage(x2) {
|
|
const m2 = x2;
|
|
return m2.progress !== void 0 && m2.progress.type === "binding";
|
|
}
|
|
|
|
// srcts/src/shiny/shinyapp.ts
|
|
var messageHandlerOrder = [];
|
|
var messageHandlers = {};
|
|
var customMessageHandlerOrder = [];
|
|
var customMessageHandlers = {};
|
|
function addMessageHandler(type, handler) {
|
|
if (messageHandlers[type]) {
|
|
throw 'handler for message of type "' + type + '" already added.';
|
|
}
|
|
if (typeof handler !== "function") {
|
|
throw "handler must be a function.";
|
|
}
|
|
if (handler.length !== 1) {
|
|
throw "handler must be a function that takes one argument.";
|
|
}
|
|
messageHandlerOrder.push(type);
|
|
messageHandlers[type] = handler;
|
|
}
|
|
function addCustomMessageHandler(type, handler) {
|
|
if (customMessageHandlers[type]) {
|
|
const typeIdx = customMessageHandlerOrder.indexOf(type);
|
|
if (typeIdx !== -1) {
|
|
customMessageHandlerOrder.splice(typeIdx, 1);
|
|
delete customMessageHandlers[type];
|
|
}
|
|
}
|
|
if (typeof handler !== "function") {
|
|
throw "handler must be a function.";
|
|
}
|
|
if (handler.length !== 1) {
|
|
throw "handler must be a function that takes one argument.";
|
|
}
|
|
customMessageHandlerOrder.push(type);
|
|
customMessageHandlers[type] = handler;
|
|
}
|
|
var ShinyApp = class {
|
|
constructor() {
|
|
this.$socket = null;
|
|
// An asynchronous queue of functions. This is sort of like an event loop for
|
|
// Shiny, to allow scheduling async callbacks so that they can run in order
|
|
// without overlapping. This is used for handling incoming messages from the
|
|
// server and scheduling outgoing messages to the server, and can be used for
|
|
// other things tasks as well.
|
|
this.taskQueue = new AsyncQueue();
|
|
this.config = null;
|
|
// Cached input values
|
|
this.$inputValues = {};
|
|
// Input values at initialization (and reconnect)
|
|
this.$initialInput = null;
|
|
// Output bindings
|
|
this.$bindings = {};
|
|
// Output progress states
|
|
this.$outputProgress = new OutputProgressReporter();
|
|
// Cached values/errors
|
|
this.$values = {};
|
|
this.$errors = {};
|
|
// Conditional bindings (show/hide element based on expression)
|
|
this.$conditionals = {};
|
|
this.$pendingMessages = [];
|
|
this.$activeRequests = {};
|
|
this.$nextRequestId = 0;
|
|
this.$allowReconnect = false;
|
|
this.scheduledReconnect = void 0;
|
|
// 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.
|
|
this.reconnectDelay = /* @__PURE__ */ function() {
|
|
let attempts = 0;
|
|
const delays = [1500, 1500, 2500, 2500, 5500, 5500, 10500];
|
|
return {
|
|
next: function() {
|
|
let i5 = attempts;
|
|
if (i5 >= delays.length) {
|
|
i5 = delays.length - 1;
|
|
}
|
|
attempts++;
|
|
return delays[i5];
|
|
},
|
|
reset: function() {
|
|
attempts = 0;
|
|
}
|
|
};
|
|
}();
|
|
// Progress reporting ====================================================
|
|
this.progressHandlers = {
|
|
// Progress for a particular object
|
|
binding: function(message) {
|
|
const key = message.id;
|
|
const binding = this.$bindings[key];
|
|
if (binding) {
|
|
(0, import_jquery39.default)(binding.el).trigger({
|
|
type: "shiny:outputinvalidated",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
binding,
|
|
name: key
|
|
});
|
|
}
|
|
this._updateProgress();
|
|
},
|
|
// Open a page-level progress bar
|
|
open: async function(message) {
|
|
if (message.style === "notification") {
|
|
await show2({
|
|
html: `<div id="shiny-progress-${message.id}" class="shiny-progress-notification"><div class="progress active" style="display: none;"><div class="progress-bar"></div></div><div class="progress-text"><span class="progress-message">message</span> <span class="progress-detail"></span></div></div>`,
|
|
id: message.id,
|
|
duration: null
|
|
});
|
|
} else if (message.style === "old") {
|
|
let $container = (0, import_jquery39.default)(".shiny-progress-container");
|
|
if ($container.length === 0) {
|
|
$container = (0, import_jquery39.default)('<div class="shiny-progress-container"></div>');
|
|
(0, import_jquery39.default)(document.body).append($container);
|
|
}
|
|
const depth = (0, import_jquery39.default)(".shiny-progress.open").length;
|
|
const $progress = (0, import_jquery39.default)(
|
|
'<div class="shiny-progress open"><div class="progress active"><div class="progress-bar bar"></div></div><div class="progress-text"><span class="progress-message">message</span><span class="progress-detail"></span></div></div>'
|
|
);
|
|
$progress.attr("id", message.id);
|
|
$container.append($progress);
|
|
const $progressBar = $progress.find(".progress");
|
|
if ($progressBar) {
|
|
$progressBar.css(
|
|
"top",
|
|
depth * $progressBar.height() + "px"
|
|
);
|
|
const $progressText = $progress.find(".progress-text");
|
|
$progressText.css(
|
|
"top",
|
|
3 * $progressBar.height() + depth * $progressText.outerHeight() + "px"
|
|
);
|
|
$progress.hide();
|
|
}
|
|
}
|
|
},
|
|
// Update page-level progress bar
|
|
update: function(message) {
|
|
if (message.style === "notification") {
|
|
const $progress = (0, import_jquery39.default)("#shiny-progress-" + message.id);
|
|
if ($progress.length === 0) return;
|
|
if (typeof message.message !== "undefined") {
|
|
$progress.find(".progress-message").text(message.message);
|
|
}
|
|
if (typeof message.detail !== "undefined") {
|
|
$progress.find(".progress-detail").text(message.detail);
|
|
}
|
|
if (typeof message.value !== "undefined" && message.value !== null) {
|
|
$progress.find(".progress").show();
|
|
$progress.find(".progress-bar").width(message.value * 100 + "%");
|
|
}
|
|
} else if (message.style === "old") {
|
|
const $progress = (0, import_jquery39.default)("#" + message.id + ".shiny-progress");
|
|
if (typeof message.message !== "undefined") {
|
|
$progress.find(".progress-message").text(message.message);
|
|
}
|
|
if (typeof message.detail !== "undefined") {
|
|
$progress.find(".progress-detail").text(message.detail);
|
|
}
|
|
if (typeof message.value !== "undefined" && message.value !== null) {
|
|
$progress.find(".progress").show();
|
|
$progress.find(".bar").width(message.value * 100 + "%");
|
|
}
|
|
$progress.fadeIn();
|
|
}
|
|
},
|
|
// Close page-level progress bar
|
|
close: function(message) {
|
|
if (message.style === "notification") {
|
|
remove2(message.id);
|
|
} else if (message.style === "old") {
|
|
const $progress = (0, import_jquery39.default)("#" + message.id + ".shiny-progress");
|
|
$progress.removeClass("open");
|
|
$progress.fadeOut({
|
|
complete: function() {
|
|
$progress.remove();
|
|
if ((0, import_jquery39.default)(".shiny-progress").length === 0)
|
|
(0, import_jquery39.default)(".shiny-progress-container").remove();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
};
|
|
this._init();
|
|
}
|
|
connect(initialInput) {
|
|
if (this.$socket)
|
|
throw "Connect was already called on this application object";
|
|
this.$socket = this.createSocket();
|
|
this.$initialInput = initialInput;
|
|
import_jquery39.default.extend(this.$inputValues, initialInput);
|
|
this.$updateConditionals();
|
|
}
|
|
isConnected() {
|
|
return !!this.$socket;
|
|
}
|
|
reconnect() {
|
|
clearTimeout(this.scheduledReconnect);
|
|
if (this.isConnected())
|
|
throw "Attempted to reconnect, but already connected.";
|
|
this.$socket = this.createSocket();
|
|
this.$initialInput = import_jquery39.default.extend({}, this.$inputValues);
|
|
this.$updateConditionals();
|
|
}
|
|
createSocket() {
|
|
const createSocketFunc = getShinyCreateWebsocket() || (() => {
|
|
let protocol = "ws:";
|
|
if (window.location.protocol === "https:") protocol = "wss:";
|
|
let defaultPath = window.location.pathname;
|
|
if (!/^([$#!&-;=?-[\]_a-z~]|%[0-9a-fA-F]{2})+$/.test(defaultPath)) {
|
|
defaultPath = encodeURI(defaultPath);
|
|
if (isQt()) {
|
|
defaultPath = encodeURI(defaultPath);
|
|
}
|
|
}
|
|
if (!/\/$/.test(defaultPath)) defaultPath += "/";
|
|
defaultPath += "websocket/";
|
|
const ws = new WebSocket(
|
|
protocol + "//" + window.location.host + defaultPath
|
|
);
|
|
ws.binaryType = "arraybuffer";
|
|
return ws;
|
|
});
|
|
const socket = createSocketFunc();
|
|
let hasOpened = false;
|
|
socket.onopen = () => {
|
|
hasOpened = true;
|
|
(0, import_jquery39.default)(document).trigger({
|
|
type: "shiny:connected",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
socket
|
|
});
|
|
this.onConnected();
|
|
socket.send(
|
|
JSON.stringify({
|
|
method: "init",
|
|
data: this.$initialInput
|
|
})
|
|
);
|
|
while (this.$pendingMessages.length) {
|
|
const msg = this.$pendingMessages.shift();
|
|
socket.send(msg);
|
|
}
|
|
this.startActionQueueLoop();
|
|
};
|
|
socket.onmessage = (e4) => {
|
|
this.taskQueue.enqueue(async () => await this.dispatchMessage(e4.data));
|
|
};
|
|
socket.onclose = (e4) => {
|
|
const restarting = e4.code === 1012;
|
|
if (hasOpened) {
|
|
(0, import_jquery39.default)(document).trigger({
|
|
type: "shiny:disconnected",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
socket
|
|
});
|
|
this.$notifyDisconnected();
|
|
}
|
|
this.onDisconnected(restarting);
|
|
this.$removeSocket();
|
|
};
|
|
return socket;
|
|
}
|
|
async startActionQueueLoop() {
|
|
while (true) {
|
|
try {
|
|
const action = await this.taskQueue.dequeue();
|
|
await action();
|
|
} catch (e4) {
|
|
showErrorInClientConsole(e4);
|
|
console.error(e4);
|
|
}
|
|
}
|
|
}
|
|
sendInput(values) {
|
|
const msg = JSON.stringify({
|
|
method: "update",
|
|
data: values
|
|
});
|
|
this.$sendMsg(msg);
|
|
import_jquery39.default.extend(this.$inputValues, values);
|
|
this.$updateConditionals();
|
|
}
|
|
$notifyDisconnected() {
|
|
if (window.parent) {
|
|
window.parent.postMessage("disconnected", "*");
|
|
}
|
|
}
|
|
$removeSocket() {
|
|
this.$socket = null;
|
|
}
|
|
$scheduleReconnect(delay) {
|
|
this.scheduledReconnect = window.setTimeout(() => {
|
|
this.reconnect();
|
|
}, delay);
|
|
}
|
|
onDisconnected(reloading = false) {
|
|
if ((0, import_jquery39.default)("#shiny-disconnected-overlay").length === 0) {
|
|
(0, import_jquery39.default)(document.body).append('<div id="shiny-disconnected-overlay"></div>');
|
|
}
|
|
(0, import_jquery39.default)("#shiny-disconnected-overlay").toggleClass("reloading", reloading);
|
|
if (this.$allowReconnect === true && this.$socket.allowReconnect === true || this.$allowReconnect === "force") {
|
|
const delay = this.reconnectDelay.next();
|
|
showReconnectDialog(delay);
|
|
this.$scheduleReconnect(delay);
|
|
}
|
|
}
|
|
onConnected() {
|
|
(0, import_jquery39.default)("#shiny-disconnected-overlay").remove();
|
|
hideReconnectDialog();
|
|
this.reconnectDelay.reset();
|
|
}
|
|
// NB: Including blobs will cause IE to break!
|
|
// TODO: Make blobs work with Internet Explorer
|
|
//
|
|
// Websocket messages are normally one-way--i.e. the client passes a
|
|
// message to the server but there is no way for the server to provide
|
|
// a response to that specific message. makeRequest provides a way to
|
|
// do asynchronous RPC over websocket. Each request has a method name
|
|
// and arguments, plus optionally one or more binary blobs can be
|
|
// included as well. The request is tagged with a unique number that
|
|
// the server will use to label the corresponding response.
|
|
//
|
|
// @param method A string that tells the server what logic to run.
|
|
// @param args An array of objects that should also be passed to the
|
|
// server in JSON-ified form.
|
|
// @param onSuccess A function that will be called back if the server
|
|
// responds with success. If the server provides a value in the
|
|
// response, the function will be called with it as the only argument.
|
|
// @param onError A function that will be called back if the server
|
|
// responds with error, or if the request fails for any other reason.
|
|
// The parameter to onError will be a string describing the error.
|
|
// @param blobs Optionally, an array of Blob, ArrayBuffer, or string
|
|
// objects that will be made available to the server as part of the
|
|
// request. Strings will be encoded using UTF-8.
|
|
makeRequest(method, args, onSuccess, onError, blobs) {
|
|
let requestId = this.$nextRequestId;
|
|
while (this.$activeRequests[requestId]) {
|
|
requestId = (requestId + 1) % 1e9;
|
|
}
|
|
this.$nextRequestId = requestId + 1;
|
|
this.$activeRequests[requestId] = {
|
|
onSuccess,
|
|
onError
|
|
};
|
|
let msg = JSON.stringify({
|
|
method,
|
|
args,
|
|
tag: requestId
|
|
});
|
|
if (blobs) {
|
|
const uint32ToBuf = function(val) {
|
|
const buffer = new ArrayBuffer(4);
|
|
const view = new DataView(buffer);
|
|
view.setUint32(0, val, true);
|
|
return buffer;
|
|
};
|
|
const payload = [];
|
|
payload.push(uint32ToBuf(16908802));
|
|
const jsonBuf = new Blob([msg]);
|
|
payload.push(uint32ToBuf(jsonBuf.size));
|
|
payload.push(jsonBuf);
|
|
for (let i5 = 0; i5 < blobs.length; i5++) {
|
|
const blob2 = blobs[i5];
|
|
payload.push(
|
|
uint32ToBuf(
|
|
blob2.byteLength || blob2.size || 0
|
|
)
|
|
);
|
|
payload.push(blob2);
|
|
}
|
|
const blob = new Blob(payload);
|
|
msg = blob;
|
|
}
|
|
this.$sendMsg(msg);
|
|
}
|
|
$sendMsg(msg) {
|
|
if (this.$socket && this.$socket.readyState) {
|
|
this.$socket.send(msg);
|
|
} else {
|
|
this.$pendingMessages.push(msg);
|
|
}
|
|
}
|
|
receiveError(name, error) {
|
|
if (this.$errors[name] === error) return;
|
|
this.$errors[name] = error;
|
|
delete this.$values[name];
|
|
const binding = this.$bindings[name];
|
|
const evt = import_jquery39.default.Event("shiny:error");
|
|
evt.name = name;
|
|
evt.error = error;
|
|
evt.binding = binding;
|
|
(0, import_jquery39.default)(binding ? binding.el : document).trigger(evt);
|
|
if (!evt.isDefaultPrevented() && binding && binding.onValueError) {
|
|
binding.onValueError(evt.error);
|
|
}
|
|
}
|
|
async receiveOutput(name, value) {
|
|
const binding = this.$bindings[name];
|
|
const evt = import_jquery39.default.Event("shiny:value");
|
|
evt.name = name;
|
|
evt.value = value;
|
|
evt.binding = binding;
|
|
if (this.$values[name] === value) {
|
|
(0, import_jquery39.default)(binding ? binding.el : document).trigger(evt);
|
|
return void 0;
|
|
}
|
|
this.$values[name] = value;
|
|
delete this.$errors[name];
|
|
(0, import_jquery39.default)(binding ? binding.el : document).trigger(evt);
|
|
if (!evt.isDefaultPrevented() && binding) {
|
|
await binding.onValueChange(evt.value);
|
|
}
|
|
return value;
|
|
}
|
|
async bindOutput(id, binding) {
|
|
if (!id) throw new Error("Can't bind an element with no ID");
|
|
this.$bindings[id] = binding;
|
|
if (this.$values[id] !== void 0)
|
|
await binding.onValueChange(this.$values[id]);
|
|
else if (this.$errors[id] !== void 0)
|
|
binding.onValueError(this.$errors[id]);
|
|
return binding;
|
|
}
|
|
unbindOutput(id, binding) {
|
|
if (this.$bindings[id] === binding) {
|
|
delete this.$bindings[id];
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
// Narrows a scopeComponent -- an input or output object -- to one constrained
|
|
// by nsPrefix. Returns a new object with keys removed and renamed as
|
|
// necessary.
|
|
_narrowScopeComponent(scopeComponent, nsPrefix) {
|
|
return Object.keys(scopeComponent).filter((k2) => k2.indexOf(nsPrefix) === 0).map((k2) => ({ [k2.substring(nsPrefix.length)]: scopeComponent[k2] })).reduce((obj, pair) => import_jquery39.default.extend(obj, pair), {});
|
|
}
|
|
// Narrows a scope -- an object with input and output "subComponents" -- to
|
|
// one constrained by the nsPrefix string.
|
|
//
|
|
// If nsPrefix is null or empty, returns scope without modification.
|
|
//
|
|
// Otherwise, returns a new object with keys in subComponents removed and
|
|
// renamed as necessary.
|
|
_narrowScope(scope, nsPrefix) {
|
|
if (nsPrefix) {
|
|
return {
|
|
input: this._narrowScopeComponent(scope.input, nsPrefix),
|
|
output: this._narrowScopeComponent(scope.output, nsPrefix)
|
|
};
|
|
}
|
|
return scope;
|
|
}
|
|
$updateConditionals() {
|
|
(0, import_jquery39.default)(document).trigger({
|
|
type: "shiny:conditional"
|
|
});
|
|
const inputs = {};
|
|
for (const name in this.$inputValues) {
|
|
if (hasOwnProperty(this.$inputValues, name)) {
|
|
const shortName = name.replace(/:.*/, "");
|
|
inputs[shortName] = this.$inputValues[name];
|
|
}
|
|
}
|
|
const scope = { input: inputs, output: this.$values };
|
|
const conditionals = (0, import_jquery39.default)(document).find("[data-display-if]");
|
|
for (let i5 = 0; i5 < conditionals.length; i5++) {
|
|
const el = (0, import_jquery39.default)(conditionals[i5]);
|
|
let condFunc = el.data("data-display-if-func");
|
|
if (!condFunc) {
|
|
const condExpr = el.attr("data-display-if");
|
|
condFunc = scopeExprToFunc(condExpr);
|
|
el.data("data-display-if-func", condFunc);
|
|
}
|
|
const nsPrefix = el.attr("data-ns-prefix");
|
|
const nsScope = this._narrowScope(scope, nsPrefix);
|
|
const show3 = Boolean(condFunc(nsScope));
|
|
const showing = el.css("display") !== "none";
|
|
if (show3 !== showing) {
|
|
if (show3) {
|
|
el.trigger("show");
|
|
el.show();
|
|
el.trigger("shown");
|
|
} else {
|
|
el.trigger("hide");
|
|
el.hide();
|
|
el.trigger("hidden");
|
|
}
|
|
}
|
|
}
|
|
}
|
|
// Message handler management functions =================================
|
|
// // Added in shiny init method
|
|
// Shiny.addCustomMessageHandler = addCustomMessageHandler;
|
|
async dispatchMessage(data) {
|
|
let msgObj = {};
|
|
if (typeof data === "string") {
|
|
msgObj = JSON.parse(data);
|
|
} else {
|
|
const len = new DataView(data, 0, 1).getUint8(0);
|
|
const typedv = new DataView(data, 1, len);
|
|
const typebuf = [];
|
|
for (let i5 = 0; i5 < len; i5++) {
|
|
typebuf.push(String.fromCharCode(typedv.getUint8(i5)));
|
|
}
|
|
const type = typebuf.join("");
|
|
data = data.slice(len + 1);
|
|
msgObj.custom = {};
|
|
msgObj.custom[type] = data;
|
|
}
|
|
const evt = import_jquery39.default.Event("shiny:message");
|
|
evt.message = msgObj;
|
|
(0, import_jquery39.default)(document).trigger(evt);
|
|
if (evt.isDefaultPrevented()) return;
|
|
this.$outputProgress.updateStateFromMessage(evt.message);
|
|
await this._sendMessagesToHandlers(
|
|
evt.message,
|
|
messageHandlers,
|
|
messageHandlerOrder
|
|
);
|
|
this.$updateConditionals();
|
|
}
|
|
// Message handlers =====================================================
|
|
// A function for sending messages to the appropriate handlers.
|
|
// - msgObj: the object containing messages, with format {msgObj.foo, msObj.bar
|
|
async _sendMessagesToHandlers(msgObj, handlers, handlerOrder) {
|
|
for (let i5 = 0; i5 < handlerOrder.length; i5++) {
|
|
const msgType = handlerOrder[i5];
|
|
if (hasOwnProperty(msgObj, msgType)) {
|
|
await handlers[msgType].call(this, msgObj[msgType]);
|
|
}
|
|
}
|
|
}
|
|
// Call showProgress() on any output bindings that have changed their
|
|
// recalculating status since the last call to takeChanges().
|
|
// Note that we only need to call this function when a "flush" (i.e. "values")
|
|
// message or a "progress" message is received since these are the only
|
|
// two types of messages that can change the recalculating status. For more,
|
|
// see the state machine diagram in outputProgress.ts.
|
|
_updateProgress() {
|
|
const changed = this.$outputProgress.takeChanges();
|
|
for (const [name, recalculating] of changed.entries()) {
|
|
if (hasOwnProperty(this.$bindings, name)) {
|
|
this.$bindings[name].showProgress(recalculating);
|
|
}
|
|
}
|
|
}
|
|
_init() {
|
|
addMessageHandler("values", async (message) => {
|
|
this._updateProgress();
|
|
for (const key in message) {
|
|
if (hasOwnProperty(message, key)) {
|
|
await this.receiveOutput(key, message[key]);
|
|
}
|
|
}
|
|
});
|
|
addMessageHandler(
|
|
"errors",
|
|
(message) => {
|
|
for (const key in message) {
|
|
if (hasOwnProperty(message, key)) {
|
|
this.receiveError(key, message[key]);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"inputMessages",
|
|
async (message) => {
|
|
for (let i5 = 0; i5 < message.length; i5++) {
|
|
const $obj = (0, import_jquery39.default)(".shiny-bound-input#" + $escape(message[i5].id));
|
|
const inputBinding = $obj.data("shiny-input-binding");
|
|
if ($obj.length > 0) {
|
|
if (!$obj.attr("aria-live")) $obj.attr("aria-live", "polite");
|
|
const el = $obj[0];
|
|
const evt = import_jquery39.default.Event("shiny:updateinput");
|
|
evt.message = message[i5].message;
|
|
evt.binding = inputBinding;
|
|
(0, import_jquery39.default)(el).trigger(evt);
|
|
if (!evt.isDefaultPrevented()) {
|
|
try {
|
|
await inputBinding.receiveMessage(el, evt.message);
|
|
} catch (error) {
|
|
console.error(
|
|
"[shiny] Error in inputBinding.receiveMessage()",
|
|
{ error, binding: inputBinding, message: evt.message }
|
|
);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler("javascript", (message) => {
|
|
indirectEval(message);
|
|
});
|
|
addMessageHandler("console", (message) => {
|
|
for (let i5 = 0; i5 < message.length; i5++) {
|
|
if (console.log) console.log(message[i5]);
|
|
}
|
|
});
|
|
addMessageHandler(
|
|
"progress",
|
|
async (message) => {
|
|
if (message.type && message.message) {
|
|
const handler = await this.progressHandlers[message.type];
|
|
if (handler) handler.call(this, message.message);
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"notification",
|
|
async (message) => {
|
|
if (message.type === "show") await show2(message.message);
|
|
else if (message.type === "remove") remove2(message.message);
|
|
else throw "Unkown notification type: " + message.type;
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"modal",
|
|
async (message) => {
|
|
if (message.type === "show") await show(message.message);
|
|
else if (message.type === "remove") remove();
|
|
else throw "Unkown modal type: " + message.type;
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"response",
|
|
(message) => {
|
|
const requestId = message.tag;
|
|
const request = this.$activeRequests[requestId];
|
|
if (request) {
|
|
delete this.$activeRequests[requestId];
|
|
if ("value" in message)
|
|
request.onSuccess(message.value);
|
|
else request.onError(message.error);
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler("allowReconnect", (message) => {
|
|
switch (message) {
|
|
case true:
|
|
case false:
|
|
case "force":
|
|
this.$allowReconnect = message;
|
|
break;
|
|
default:
|
|
throw "Invalid value for allowReconnect: " + message;
|
|
}
|
|
});
|
|
addMessageHandler("custom", async (message) => {
|
|
const shinyOnCustomMessage = getShinyOnCustomMessage();
|
|
if (shinyOnCustomMessage) await shinyOnCustomMessage(message);
|
|
await this._sendMessagesToHandlers(
|
|
message,
|
|
customMessageHandlers,
|
|
customMessageHandlerOrder
|
|
);
|
|
});
|
|
addMessageHandler(
|
|
"config",
|
|
(message) => {
|
|
this.config = {
|
|
workerId: message.workerId,
|
|
sessionId: message.sessionId
|
|
};
|
|
if (message.user) setShinyUser(message.user);
|
|
(0, import_jquery39.default)(document).trigger("shiny:sessioninitialized");
|
|
}
|
|
);
|
|
addMessageHandler("busy", (message) => {
|
|
if (message === "busy") {
|
|
(0, import_jquery39.default)(document.documentElement).addClass("shiny-busy");
|
|
(0, import_jquery39.default)(document).trigger("shiny:busy");
|
|
} else if (message === "idle") {
|
|
(0, import_jquery39.default)(document.documentElement).removeClass("shiny-busy");
|
|
(0, import_jquery39.default)(document).trigger("shiny:idle");
|
|
}
|
|
});
|
|
addMessageHandler(
|
|
"recalculating",
|
|
(message) => {
|
|
if (hasOwnProperty(message, "name") && hasOwnProperty(message, "status")) {
|
|
const binding = this.$bindings[message.name];
|
|
if (binding) {
|
|
(0, import_jquery39.default)(binding.el).trigger("shiny:" + message.status);
|
|
} else {
|
|
(0, import_jquery39.default)().trigger("shiny:" + message.status);
|
|
}
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler("reload", (message) => {
|
|
window.location.reload();
|
|
return;
|
|
message;
|
|
});
|
|
addMessageHandler(
|
|
"shiny-insert-ui",
|
|
async (message) => {
|
|
const targets = (0, import_jquery39.default)(message.selector);
|
|
if (targets.length === 0) {
|
|
console.warn(
|
|
'The selector you chose ("' + message.selector + '") could not be found in the DOM.'
|
|
);
|
|
await renderHtmlAsync(
|
|
message.content.html,
|
|
(0, import_jquery39.default)([]),
|
|
message.content.deps
|
|
);
|
|
} else {
|
|
for (const target of targets) {
|
|
await renderContentAsync(target, message.content, message.where);
|
|
if (message.multiple === false) break;
|
|
}
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"shiny-remove-ui",
|
|
(message) => {
|
|
const els = (0, import_jquery39.default)(message.selector);
|
|
els.each(function(i5, el) {
|
|
shinyUnbindAll(el, true);
|
|
(0, import_jquery39.default)(el).remove();
|
|
return message.multiple === false ? false : void 0;
|
|
});
|
|
}
|
|
);
|
|
addMessageHandler("frozen", (message) => {
|
|
for (let i5 = 0; i5 < message.ids.length; i5++) {
|
|
shinyForgetLastInputValue(message.ids[i5]);
|
|
}
|
|
});
|
|
function getTabset(id) {
|
|
const $tabset = (0, import_jquery39.default)("#" + $escape(id));
|
|
if ($tabset.length === 0)
|
|
throw "There is no tabsetPanel (or navbarPage or navlistPanel) with id equal to '" + id + "'";
|
|
return $tabset;
|
|
}
|
|
function getTabContent($tabset) {
|
|
const tabsetId = $tabset.attr("data-tabsetid");
|
|
const $tabContent = (0, import_jquery39.default)(
|
|
"div.tab-content[data-tabsetid='" + $escape(tabsetId) + "']"
|
|
);
|
|
return $tabContent;
|
|
}
|
|
function getTargetTabs($tabset, $tabContent, target) {
|
|
const dataValue = "[data-value='" + $escape(target) + "']";
|
|
const $aTag = $tabset.find("a" + dataValue);
|
|
const $liTag = $aTag.parent();
|
|
if ($liTag.length === 0) {
|
|
throw "There is no tabPanel (or navbarMenu) with value (or menuName) equal to '" + target + "'";
|
|
}
|
|
const $liTags = [];
|
|
const $divTags = [];
|
|
if ($aTag.attr("data-toggle") === "dropdown") {
|
|
const $dropdownTabset = $aTag.find("+ ul.dropdown-menu");
|
|
const dropdownId = $dropdownTabset.attr("data-tabsetid");
|
|
const $dropdownLiTags = $dropdownTabset.find("a[data-toggle='tab']").parent("li");
|
|
$dropdownLiTags.each(function(i5, el) {
|
|
$liTags.push((0, import_jquery39.default)(el));
|
|
});
|
|
const selector = "div.tab-pane[id^='tab-" + $escape(dropdownId) + "']";
|
|
const $dropdownDivs = $tabContent.find(selector);
|
|
$dropdownDivs.each(function(i5, el) {
|
|
$divTags.push((0, import_jquery39.default)(el));
|
|
});
|
|
} else {
|
|
$divTags.push($tabContent.find("div" + dataValue));
|
|
}
|
|
return { $liTag, $liTags, $divTags };
|
|
}
|
|
addMessageHandler(
|
|
"shiny-insert-tab",
|
|
async (message) => {
|
|
const $parentTabset = getTabset(message.inputId);
|
|
let $tabset = $parentTabset;
|
|
const $tabContent = getTabContent($tabset);
|
|
let tabsetId = $parentTabset.attr("data-tabsetid");
|
|
const $fragLi = (0, import_jquery39.default)("<div>");
|
|
await renderContentAsync($fragLi, message.liTag, "afterBegin");
|
|
const $liTag = (0, import_jquery39.default)($fragLi).find("> li");
|
|
const $aTag = $liTag.find("> a");
|
|
let $targetLiTag = null;
|
|
if (message.target !== null) {
|
|
const targetInfo = getTargetTabs(
|
|
$tabset,
|
|
$tabContent,
|
|
message.target
|
|
);
|
|
$targetLiTag = targetInfo.$liTag;
|
|
}
|
|
const dropdown = getDropdown();
|
|
if (dropdown !== null) {
|
|
if ($aTag.attr("data-toggle") === "dropdown")
|
|
throw "Cannot insert a navbarMenu inside another one";
|
|
$tabset = dropdown.$tabset;
|
|
tabsetId = dropdown.id;
|
|
$liTag.removeClass("nav-item").find(".nav-link").removeClass("nav-link").addClass("dropdown-item");
|
|
}
|
|
let fixupDivId = "";
|
|
if ($aTag.attr("data-toggle") === "tab") {
|
|
const index = getTabIndex($tabset, tabsetId);
|
|
const tabId = "tab-" + tabsetId + "-" + index;
|
|
$liTag.find("> a").attr("href", "#" + tabId);
|
|
fixupDivId = tabId;
|
|
}
|
|
if (message.position === "before") {
|
|
if ($targetLiTag) {
|
|
$targetLiTag.before($liTag);
|
|
} else {
|
|
$tabset.prepend($liTag);
|
|
}
|
|
} else if (message.position === "after") {
|
|
if ($targetLiTag) {
|
|
$targetLiTag.after($liTag);
|
|
} else {
|
|
$tabset.append($liTag);
|
|
}
|
|
}
|
|
await shinyBindAll($targetLiTag?.parent() || $tabset);
|
|
await renderContentAsync($tabContent[0], message.divTag, "beforeEnd");
|
|
if (fixupDivId) {
|
|
$tabContent.find('[id="tab-tsid-id"]').attr("id", fixupDivId);
|
|
}
|
|
if (message.select) {
|
|
$liTag.find("a").tab("show");
|
|
}
|
|
function getTabIndex($tabset2, tabsetId2) {
|
|
const existingTabIds = [0];
|
|
$tabset2.find("> li").each(function() {
|
|
const $tab = (0, import_jquery39.default)(this).find("> a[data-toggle='tab']");
|
|
if ($tab.length > 0) {
|
|
const href = $tab.attr("href").replace(/.*(?=#[^\s]+$)/, "");
|
|
const index = href.replace("#tab-" + tabsetId2 + "-", "");
|
|
existingTabIds.push(Number(index));
|
|
}
|
|
});
|
|
return Math.max.apply(null, existingTabIds) + 1;
|
|
}
|
|
function getDropdown() {
|
|
if (message.menuName !== null) {
|
|
const $dropdownATag = (0, import_jquery39.default)(
|
|
"a.dropdown-toggle[data-value='" + $escape(message.menuName) + "']"
|
|
);
|
|
if ($dropdownATag.length === 0) {
|
|
throw "There is no navbarMenu with menuName equal to '" + message.menuName + "'";
|
|
}
|
|
const $dropdownTabset = $dropdownATag.find("+ ul.dropdown-menu");
|
|
const dropdownId = $dropdownTabset.attr("data-tabsetid");
|
|
return { $tabset: $dropdownTabset, id: dropdownId };
|
|
} else if (message.target !== null && $targetLiTag !== null) {
|
|
const $uncleTabset = $targetLiTag.parent("ul");
|
|
if ($uncleTabset.hasClass("dropdown-menu")) {
|
|
const uncleId = $uncleTabset.attr("data-tabsetid");
|
|
return { $tabset: $uncleTabset, id: uncleId };
|
|
}
|
|
}
|
|
return null;
|
|
}
|
|
}
|
|
);
|
|
function ensureTabsetHasVisibleTab($tabset) {
|
|
const inputBinding = $tabset.data("shiny-input-binding");
|
|
if (!inputBinding.getValue($tabset)) {
|
|
const destTabValue = getFirstTab($tabset);
|
|
const evt = import_jquery39.default.Event("shiny:updateinput");
|
|
evt.binding = inputBinding;
|
|
$tabset.trigger(evt);
|
|
inputBinding.setValue($tabset[0], destTabValue);
|
|
}
|
|
}
|
|
function getFirstTab($ul) {
|
|
return $ul.find("li:visible a[data-toggle='tab']").first().attr("data-value") || null;
|
|
}
|
|
function tabApplyFunction(target, func, liTags = false) {
|
|
import_jquery39.default.each(target, function(key, el) {
|
|
if (key === "$liTag") {
|
|
func(el);
|
|
} else if (key === "$divTags") {
|
|
import_jquery39.default.each(
|
|
el,
|
|
function(i5, div) {
|
|
func(div);
|
|
}
|
|
);
|
|
} else if (liTags && key === "$liTags") {
|
|
import_jquery39.default.each(
|
|
el,
|
|
function(i5, div) {
|
|
func(div);
|
|
}
|
|
);
|
|
}
|
|
});
|
|
}
|
|
addMessageHandler(
|
|
"shiny-remove-tab",
|
|
(message) => {
|
|
const $tabset = getTabset(message.inputId);
|
|
const $tabContent = getTabContent($tabset);
|
|
const target = getTargetTabs($tabset, $tabContent, message.target);
|
|
tabApplyFunction(target, removeEl);
|
|
ensureTabsetHasVisibleTab($tabset);
|
|
function removeEl($el) {
|
|
shinyUnbindAll($el, true);
|
|
$el.remove();
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"shiny-change-tab-visibility",
|
|
(message) => {
|
|
const $tabset = getTabset(message.inputId);
|
|
const $tabContent = getTabContent($tabset);
|
|
const target = getTargetTabs($tabset, $tabContent, message.target);
|
|
tabApplyFunction(target, changeVisibility, true);
|
|
ensureTabsetHasVisibleTab($tabset);
|
|
function changeVisibility($el) {
|
|
if (message.type === "show") $el.css("display", "");
|
|
else if (message.type === "hide") {
|
|
$el.hide();
|
|
$el.removeClass("active");
|
|
}
|
|
}
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"updateQueryString",
|
|
(message) => {
|
|
if (message.mode === "replace") {
|
|
window.history.replaceState(null, null, message.queryString);
|
|
return;
|
|
}
|
|
let what = null;
|
|
if (message.queryString.charAt(0) === "#") what = "hash";
|
|
else if (message.queryString.charAt(0) === "?") what = "query";
|
|
else
|
|
throw "The 'query' string must start with either '?' (to update the query string) or with '#' (to update the hash).";
|
|
const path = window.location.pathname;
|
|
const oldQS = window.location.search;
|
|
const oldHash = window.location.hash;
|
|
let relURL = path;
|
|
if (what === "query") relURL += message.queryString;
|
|
else relURL += oldQS + message.queryString;
|
|
window.history.pushState(null, null, relURL);
|
|
if (message.queryString.indexOf("#") !== -1) what = "hash";
|
|
if (window.location.hash !== oldHash) what = "hash";
|
|
if (what === "hash") (0, import_jquery39.default)(document).trigger("hashchange");
|
|
}
|
|
);
|
|
addMessageHandler(
|
|
"resetBrush",
|
|
(message) => {
|
|
resetBrush(message.brushId);
|
|
}
|
|
);
|
|
}
|
|
//// 2021/03: TypeScript Conversion
|
|
// Added in `./shiny/init.ts` as there are no instances of progressHandlers being used right away on GitHub
|
|
// Shiny.progressHandlers = this.progressHandlers;
|
|
// Returns a URL which can be queried to get values from inside the server
|
|
// function. This is enabled with `options(shiny.testmode=TRUE)`.
|
|
getTestSnapshotBaseUrl({ fullUrl = true } = {}) {
|
|
const loc = window.location;
|
|
let url = "";
|
|
if (fullUrl) {
|
|
url = loc.origin + loc.pathname.replace(/\/[^/]*$/, "");
|
|
}
|
|
url += "/session/" + encodeURIComponent(this.config.sessionId) + "/dataobj/shinytest?w=" + encodeURIComponent(this.config.workerId) + "&nonce=" + randomId();
|
|
return url;
|
|
}
|
|
};
|
|
|
|
// srcts/src/shiny/index.ts
|
|
var ShinyClass = class {
|
|
constructor() {
|
|
this.version = "1.12.1.9000";
|
|
const { inputBindings, fileInputBinding: fileInputBinding2 } = initInputBindings();
|
|
const { outputBindings } = initOutputBindings();
|
|
setFileInputBinding(fileInputBinding2);
|
|
this.$escape = $escape;
|
|
this.compareVersion = compareVersion;
|
|
this.inputBindings = inputBindings;
|
|
this.InputBinding = InputBinding;
|
|
this.outputBindings = outputBindings;
|
|
this.OutputBinding = OutputBinding;
|
|
this.resetBrush = resetBrush;
|
|
this.notifications = {
|
|
show: show2,
|
|
remove: remove2
|
|
};
|
|
this.modal = { show, remove };
|
|
this.addCustomMessageHandler = addCustomMessageHandler;
|
|
this.showReconnectDialog = showReconnectDialog;
|
|
this.hideReconnectDialog = hideReconnectDialog;
|
|
this.renderDependenciesAsync = renderDependenciesAsync;
|
|
this.renderDependencies = renderDependencies;
|
|
this.renderContentAsync = renderContentAsync;
|
|
this.renderContent = renderContent;
|
|
this.renderHtmlAsync = renderHtmlAsync;
|
|
this.renderHtml = renderHtml2;
|
|
this.initializedPromise = createInitStatus();
|
|
(0, import_jquery40.default)(() => {
|
|
setTimeout(async () => {
|
|
try {
|
|
await this.initialize();
|
|
} catch (e4) {
|
|
showErrorInClientConsole(e4);
|
|
throw e4;
|
|
}
|
|
}, 1);
|
|
});
|
|
}
|
|
/**
|
|
* Method to check if Shiny is running in development mode. By packaging as a
|
|
* method, we can we can avoid needing to look for the `__SHINY_DEV_MODE__`
|
|
* variable in the global scope.
|
|
* @returns `true` if Shiny is running in development mode, `false` otherwise.
|
|
*/
|
|
inDevMode() {
|
|
return isShinyInDevMode();
|
|
}
|
|
async initialize() {
|
|
setShinyObj(this);
|
|
this.shinyapp = new ShinyApp();
|
|
const shinyapp = this.shinyapp;
|
|
this.progressHandlers = shinyapp.progressHandlers;
|
|
const inputBatchSender = new InputBatchSender(shinyapp);
|
|
const inputsNoResend = new InputNoResendDecorator(inputBatchSender);
|
|
const inputsEvent = new InputEventDecorator(inputsNoResend);
|
|
const inputsRate = new InputRateDecorator(inputsEvent);
|
|
const inputsDefer = new InputDeferDecorator(inputsEvent);
|
|
let target;
|
|
if (document.querySelector(".shiny-submit-button")) {
|
|
target = inputsDefer;
|
|
document.querySelectorAll(".shiny-submit-button").forEach(function(x2) {
|
|
x2.addEventListener("click", function(event) {
|
|
event.preventDefault();
|
|
inputsDefer.submit();
|
|
});
|
|
});
|
|
} else {
|
|
target = inputsRate;
|
|
}
|
|
const inputs = new InputValidateDecorator(target);
|
|
this.setInputValue = this.onInputChange = function(name, value, opts = {}) {
|
|
const newOpts = addDefaultInputOpts(opts);
|
|
inputs.setInput(name, value, newOpts);
|
|
};
|
|
this.forgetLastInputValue = function(name) {
|
|
inputsNoResend.forget(name);
|
|
};
|
|
const inputBindings = this.inputBindings;
|
|
const outputBindings = this.outputBindings;
|
|
const shinyBindCtx = () => {
|
|
return {
|
|
inputs,
|
|
inputsRate,
|
|
sendOutputHiddenState,
|
|
maybeAddThemeObserver,
|
|
inputBindings,
|
|
outputBindings,
|
|
initDeferredIframes,
|
|
outputIsRecalculating: (id) => this.shinyapp?.$outputProgress.isRecalculating(id) ?? false
|
|
};
|
|
};
|
|
this.bindAll = async function(scope) {
|
|
await bindAll(shinyBindCtx(), scope);
|
|
};
|
|
this.unbindAll = function(scope, includeSelf = false) {
|
|
unbindAll(shinyBindCtx(), scope, includeSelf);
|
|
};
|
|
function initializeInputs(scope = document.documentElement) {
|
|
const bindings = inputBindings.getBindings();
|
|
for (let i5 = 0; i5 < bindings.length; i5++) {
|
|
const binding = bindings[i5].binding;
|
|
const inputObjects = binding.find(scope);
|
|
if (inputObjects) {
|
|
for (let j2 = 0; j2 < inputObjects.length; j2++) {
|
|
const $inputObjectJ = (0, import_jquery40.default)(inputObjects[j2]);
|
|
if (!$inputObjectJ.data("_shiny_initialized")) {
|
|
$inputObjectJ.data("_shiny_initialized", true);
|
|
binding.initialize(inputObjects[j2]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.initializeInputs = initializeInputs;
|
|
function getIdFromEl(el) {
|
|
const $el = (0, import_jquery40.default)(el);
|
|
const bindingAdapter = $el.data("shiny-output-binding");
|
|
if (!bindingAdapter) return null;
|
|
else return bindingAdapter.getId();
|
|
}
|
|
initializeInputs(document.documentElement);
|
|
const initialValues = mapValues(
|
|
await _bindAll(shinyBindCtx(), document.documentElement),
|
|
(x2) => x2.value
|
|
);
|
|
(0, import_jquery40.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
|
|
function() {
|
|
const id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
|
|
if (rect.width !== 0 || rect.height !== 0) {
|
|
initialValues[".clientdata_output_" + id + "_width"] = rect.width;
|
|
initialValues[".clientdata_output_" + id + "_height"] = rect.height;
|
|
}
|
|
}
|
|
);
|
|
function getComputedBgColor(el) {
|
|
if (!el) {
|
|
return null;
|
|
}
|
|
const bgColor = getStyle(el, "background-color");
|
|
if (!bgColor) return bgColor;
|
|
const m2 = bgColor.match(
|
|
/^rgba\(\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*,\s*([\d.]+)\s*\)$/
|
|
);
|
|
if (bgColor === "transparent" || m2 && parseFloat(m2[4]) === 0) {
|
|
const bgImage = getStyle(el, "background-image");
|
|
if (bgImage && bgImage !== "none") {
|
|
return null;
|
|
} else {
|
|
return getComputedBgColor(el.parentElement);
|
|
}
|
|
}
|
|
return bgColor;
|
|
}
|
|
function getComputedFont(el) {
|
|
const fontFamily = getStyle(el, "font-family");
|
|
const fontSize = getStyle(el, "font-size");
|
|
return {
|
|
families: fontFamily?.replace(/"/g, "").split(", "),
|
|
size: fontSize
|
|
};
|
|
}
|
|
(0, import_jquery40.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-theme").each(
|
|
function() {
|
|
const el = this;
|
|
const id = getIdFromEl(el);
|
|
initialValues[".clientdata_output_" + id + "_bg"] = getComputedBgColor(el);
|
|
initialValues[".clientdata_output_" + id + "_fg"] = getStyle(
|
|
el,
|
|
"color"
|
|
);
|
|
initialValues[".clientdata_output_" + id + "_accent"] = getComputedLinkColor(el);
|
|
initialValues[".clientdata_output_" + id + "_font"] = getComputedFont(el);
|
|
maybeAddThemeObserver(el);
|
|
}
|
|
);
|
|
function maybeAddThemeObserver(el) {
|
|
if (!window.MutationObserver) {
|
|
return;
|
|
}
|
|
const cl = el.classList;
|
|
const reportTheme = cl.contains("shiny-image-output") || cl.contains("shiny-plot-output") || cl.contains("shiny-report-theme");
|
|
if (!reportTheme) {
|
|
return;
|
|
}
|
|
const $el = (0, import_jquery40.default)(el);
|
|
if ($el.data("shiny-theme-observer")) {
|
|
return;
|
|
}
|
|
const observerCallback = new Debouncer(null, () => doSendTheme(el), 100);
|
|
const observer = new MutationObserver(
|
|
() => observerCallback.normalCall()
|
|
);
|
|
const config = { attributes: true, attributeFilter: ["style", "class"] };
|
|
observer.observe(el, config);
|
|
$el.data("shiny-theme-observer", observer);
|
|
}
|
|
function doSendTheme(el) {
|
|
if (el.classList.contains("shiny-output-error")) {
|
|
return;
|
|
}
|
|
const id = getIdFromEl(el);
|
|
inputs.setInput(
|
|
".clientdata_output_" + id + "_bg",
|
|
getComputedBgColor(el)
|
|
);
|
|
inputs.setInput(
|
|
".clientdata_output_" + id + "_fg",
|
|
getStyle(el, "color")
|
|
);
|
|
inputs.setInput(
|
|
".clientdata_output_" + id + "_accent",
|
|
getComputedLinkColor(el)
|
|
);
|
|
inputs.setInput(
|
|
".clientdata_output_" + id + "_font",
|
|
getComputedFont(el)
|
|
);
|
|
}
|
|
function doSendImageSize() {
|
|
(0, import_jquery40.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-size").each(
|
|
function() {
|
|
const id = getIdFromEl(this), rect = getBoundingClientSizeBeforeZoom(this);
|
|
if (rect.width !== 0 || rect.height !== 0) {
|
|
inputs.setInput(".clientdata_output_" + id + "_width", rect.width);
|
|
inputs.setInput(
|
|
".clientdata_output_" + id + "_height",
|
|
rect.height
|
|
);
|
|
}
|
|
}
|
|
);
|
|
(0, import_jquery40.default)(".shiny-image-output, .shiny-plot-output, .shiny-report-theme").each(
|
|
function() {
|
|
doSendTheme(this);
|
|
}
|
|
);
|
|
(0, import_jquery40.default)(".shiny-bound-output").each(function() {
|
|
const $this = (0, import_jquery40.default)(this), binding = $this.data("shiny-output-binding");
|
|
$this.trigger({
|
|
type: "shiny:visualchange",
|
|
// @ts-expect-error; Can not remove info on a established, malformed Event object
|
|
visible: !isHidden(this),
|
|
binding
|
|
});
|
|
binding.onResize();
|
|
});
|
|
}
|
|
sendImageSizeFns.setImageSend(inputBatchSender, doSendImageSize);
|
|
function isHidden(obj) {
|
|
if (obj === null || obj.offsetWidth !== 0 || obj.offsetHeight !== 0) {
|
|
return false;
|
|
} else if (getStyle(obj, "display") === "none") {
|
|
return true;
|
|
} else {
|
|
return isHidden(obj.parentNode);
|
|
}
|
|
}
|
|
let lastKnownVisibleOutputs = {};
|
|
(0, import_jquery40.default)(".shiny-bound-output").each(function() {
|
|
const id = getIdFromEl(this);
|
|
if (isHidden(this)) {
|
|
initialValues[".clientdata_output_" + id + "_hidden"] = true;
|
|
} else {
|
|
lastKnownVisibleOutputs[id] = true;
|
|
initialValues[".clientdata_output_" + id + "_hidden"] = false;
|
|
}
|
|
});
|
|
function doSendOutputHiddenState() {
|
|
const visibleOutputs = {};
|
|
(0, import_jquery40.default)(".shiny-bound-output").each(function() {
|
|
const id = getIdFromEl(this);
|
|
delete lastKnownVisibleOutputs[id];
|
|
const hidden = isHidden(this), evt = {
|
|
type: "shiny:visualchange",
|
|
visible: !hidden
|
|
};
|
|
if (hidden) {
|
|
inputs.setInput(".clientdata_output_" + id + "_hidden", true);
|
|
} else {
|
|
visibleOutputs[id] = true;
|
|
inputs.setInput(".clientdata_output_" + id + "_hidden", false);
|
|
}
|
|
const $this = (0, import_jquery40.default)(this);
|
|
evt.binding = $this.data("shiny-output-binding");
|
|
$this.trigger(evt);
|
|
});
|
|
for (const name in lastKnownVisibleOutputs) {
|
|
if (hasDefinedProperty(lastKnownVisibleOutputs, name))
|
|
inputs.setInput(".clientdata_output_" + name + "_hidden", true);
|
|
}
|
|
lastKnownVisibleOutputs = visibleOutputs;
|
|
}
|
|
const sendOutputHiddenStateDebouncer = new Debouncer(
|
|
null,
|
|
doSendOutputHiddenState,
|
|
0
|
|
);
|
|
function sendOutputHiddenState() {
|
|
sendOutputHiddenStateDebouncer.normalCall();
|
|
}
|
|
inputBatchSender.lastChanceCallback.push(function() {
|
|
if (sendOutputHiddenStateDebouncer.isPending())
|
|
sendOutputHiddenStateDebouncer.immediateCall();
|
|
});
|
|
function filterEventsByNamespace(namespace, handler, ...args) {
|
|
const namespaceArr = namespace.split(".");
|
|
return function(e4) {
|
|
const eventNamespace = e4.namespace?.split(".") ?? [];
|
|
for (let i5 = 0; i5 < namespaceArr.length; i5++) {
|
|
if (eventNamespace.indexOf(namespaceArr[i5]) === -1) return;
|
|
}
|
|
handler.apply(this, [namespaceArr, handler, ...args]);
|
|
};
|
|
}
|
|
(0, import_jquery40.default)(window).resize(debounce(500, sendImageSizeFns.regular));
|
|
const bs3classes = [
|
|
"modal",
|
|
"dropdown",
|
|
"tab",
|
|
"tooltip",
|
|
"popover",
|
|
"collapse"
|
|
];
|
|
import_jquery40.default.each(bs3classes, function(idx, classname) {
|
|
(0, import_jquery40.default)(document.body).on(
|
|
"shown.bs." + classname + ".sendImageSize",
|
|
"*",
|
|
filterEventsByNamespace("bs", sendImageSizeFns.regular)
|
|
);
|
|
(0, import_jquery40.default)(document.body).on(
|
|
"shown.bs." + classname + ".sendOutputHiddenState hidden.bs." + classname + ".sendOutputHiddenState",
|
|
"*",
|
|
filterEventsByNamespace("bs", sendOutputHiddenState)
|
|
);
|
|
});
|
|
(0, import_jquery40.default)(document.body).on("shown.sendImageSize", "*", sendImageSizeFns.regular);
|
|
(0, import_jquery40.default)(document.body).on(
|
|
"shown.sendOutputHiddenState hidden.sendOutputHiddenState",
|
|
"*",
|
|
sendOutputHiddenState
|
|
);
|
|
initialValues[".clientdata_pixelratio"] = pixelRatio();
|
|
(0, import_jquery40.default)(window).resize(function() {
|
|
inputs.setInput(".clientdata_pixelratio", pixelRatio());
|
|
});
|
|
initialValues[".clientdata_url_protocol"] = window.location.protocol;
|
|
initialValues[".clientdata_url_hostname"] = window.location.hostname;
|
|
initialValues[".clientdata_url_port"] = window.location.port;
|
|
initialValues[".clientdata_url_pathname"] = window.location.pathname;
|
|
initialValues[".clientdata_url_search"] = window.location.search;
|
|
(0, import_jquery40.default)(window).on("pushstate", function(e4) {
|
|
inputs.setInput(".clientdata_url_search", window.location.search);
|
|
return;
|
|
e4;
|
|
});
|
|
(0, import_jquery40.default)(window).on("popstate", function(e4) {
|
|
inputs.setInput(".clientdata_url_search", window.location.search);
|
|
return;
|
|
e4;
|
|
});
|
|
initialValues[".clientdata_url_hash_initial"] = window.location.hash;
|
|
initialValues[".clientdata_url_hash"] = window.location.hash;
|
|
(0, import_jquery40.default)(window).on("hashchange", function(e4) {
|
|
inputs.setInput(".clientdata_url_hash", window.location.hash);
|
|
return;
|
|
e4;
|
|
});
|
|
const singletonText = initialValues[".clientdata_singletons"] = (0, import_jquery40.default)(
|
|
'script[type="application/shiny-singletons"]'
|
|
).text();
|
|
registerNames(singletonText.split(/,/));
|
|
const dependencyText = (0, import_jquery40.default)(
|
|
'script[type="application/html-dependencies"]'
|
|
).text();
|
|
import_jquery40.default.each(dependencyText.split(/;/), function(i5, depStr) {
|
|
const match = /\s*^(.+)\[(.+)\]\s*$/.exec(depStr);
|
|
if (match) {
|
|
registerDependency(match[1], match[2]);
|
|
}
|
|
});
|
|
inputsNoResend.reset(initialValues);
|
|
shinyapp.connect(initialValues);
|
|
(0, import_jquery40.default)(document).one("shiny:connected", () => {
|
|
initDeferredIframes();
|
|
});
|
|
(0, import_jquery40.default)(document).one("shiny:sessioninitialized", () => {
|
|
this.initializedPromise.resolve();
|
|
});
|
|
}
|
|
};
|
|
function initDeferredIframes() {
|
|
if (
|
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore; Do not want to define `window.Shiny` as a type to discourage usage of `window.Shiny`;
|
|
// Can not expect error when combining with window available Shiny definition
|
|
!window.Shiny || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore; Do not want to define `window.Shiny` as a type to discourage usage of `window.Shiny`;
|
|
// Can not expect error when combining with window available Shiny definition
|
|
!window.Shiny.shinyapp || // eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
|
// @ts-ignore; Do not want to define `window.Shiny` as a type to discourage usage of `window.Shiny`;
|
|
// Can not expect error when combining with window available Shiny definition
|
|
!window.Shiny.shinyapp.isConnected()
|
|
) {
|
|
return;
|
|
}
|
|
(0, import_jquery40.default)(".shiny-frame-deferred").each(function(i5, el) {
|
|
const $el = (0, import_jquery40.default)(el);
|
|
$el.removeClass("shiny-frame-deferred");
|
|
$el.attr("src", $el.attr("data-deferred-src"));
|
|
$el.attr("data-deferred-src", null);
|
|
});
|
|
}
|
|
|
|
// srcts/src/window/userAgent.ts
|
|
function windowUserAgent() {
|
|
return window.navigator.userAgent;
|
|
}
|
|
|
|
// srcts/src/shiny/reactlog.ts
|
|
var import_jquery41 = __toESM(require_jquery());
|
|
function shinyAppConfig() {
|
|
return shinyShinyApp().config;
|
|
}
|
|
function initReactlog() {
|
|
(0, import_jquery41.default)(document).on("keydown", function(e4) {
|
|
if (e4.which !== 114 || !e4.ctrlKey && !e4.metaKey || e4.shiftKey || e4.altKey)
|
|
return;
|
|
const url = "reactlog?w=" + window.escape(shinyAppConfig().workerId) + "&s=" + window.escape(shinyAppConfig().sessionId);
|
|
window.open(url);
|
|
e4.preventDefault();
|
|
});
|
|
(0, import_jquery41.default)(document).on("keydown", function(e4) {
|
|
if (
|
|
// if not one of the key combos below
|
|
!// cmd/ctrl + fn + f4
|
|
(e4.which === 115 && (e4.ctrlKey || e4.metaKey) && !e4.shiftKey && !e4.altKey || // cmd/ctrl + shift + fn + f3
|
|
e4.which === 114 && (e4.ctrlKey || e4.metaKey) && e4.shiftKey && !e4.altKey)
|
|
) {
|
|
return;
|
|
}
|
|
const url = "reactlog/mark?w=" + window.escape(shinyAppConfig().workerId) + "&s=" + window.escape(shinyAppConfig().sessionId);
|
|
import_jquery41.default.get(url, function(result) {
|
|
if (result !== "marked") return;
|
|
const html = '<span id="shiny-reactlog-mark-text">Marked time point in reactlog</span>';
|
|
show2({
|
|
html,
|
|
closeButton: true
|
|
});
|
|
}).fail(function() {
|
|
window.open(url);
|
|
});
|
|
e4.preventDefault();
|
|
});
|
|
}
|
|
|
|
// srcts/src/initialize/index.ts
|
|
var Shiny;
|
|
function init() {
|
|
if (window.Shiny) {
|
|
throw new Error("Trying to create window.Shiny, but it already exists!");
|
|
}
|
|
Shiny = window.Shiny = new ShinyClass();
|
|
setUserAgent(windowUserAgent());
|
|
determineBrowserInfo();
|
|
trackHistory();
|
|
disableFormSubmission();
|
|
initReactlog();
|
|
}
|
|
|
|
// srcts/src/index.ts
|
|
init();
|
|
})();
|
|
/*! Bundled license information:
|
|
|
|
@lit/reactive-element/css-tag.js:
|
|
(**
|
|
* @license
|
|
* Copyright 2019 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*)
|
|
|
|
@lit/reactive-element/reactive-element.js:
|
|
lit-html/lit-html.js:
|
|
lit-element/lit-element.js:
|
|
(**
|
|
* @license
|
|
* Copyright 2017 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*)
|
|
|
|
lit-html/is-server.js:
|
|
(**
|
|
* @license
|
|
* Copyright 2022 Google LLC
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*)
|
|
*/
|
|
//# sourceMappingURL=shiny.js.map
|