Skip to content

Commit f63825f

Browse files
committed
Add script to restore input values in the browser
1 parent 165f566 commit f63825f

File tree

1 file changed

+86
-1
lines changed

1 file changed

+86
-1
lines changed

shiny/ui/_chat.py

Lines changed: 86 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from __future__ import annotations
22

33
import inspect
4+
import textwrap
45
from contextlib import asynccontextmanager
56
from typing import (
67
TYPE_CHECKING,
@@ -19,13 +20,26 @@
1920
)
2021
from weakref import WeakValueDictionary
2122

22-
from htmltools import HTML, RenderedHTML, Tag, TagAttrValue, TagChild, TagList, css
23+
from htmltools import (
24+
HTML,
25+
RenderedHTML,
26+
Tag,
27+
TagAttrValue,
28+
TagChild,
29+
TagList,
30+
css,
31+
tags,
32+
)
2333

2434
from .. import _utils, reactive
2535
from .._deprecated import warn_deprecated
2636
from .._docstring import add_example
2737
from .._utils import CancelCallback, wrap_async
2838
from ..bookmark import BookmarkState, RestoreState
39+
from ..bookmark._restore_state import (
40+
get_current_restore_context,
41+
has_current_restore_context,
42+
)
2943
from ..bookmark._types import BookmarkStore
3044
from ..module import ResolvedId, resolve_id
3145
from ..session import get_current_session, require_active_session, session_context
@@ -1754,6 +1768,76 @@ def chat_ui(
17541768
)
17551769
)
17561770

1771+
shiny_input_dep: Tag | None = None
1772+
if has_current_restore_context():
1773+
restore_ctx = get_current_restore_context()
1774+
if restore_ctx is None:
1775+
raise RuntimeError("This should not occur.")
1776+
input_dict = restore_ctx.input.as_dict()
1777+
import json
1778+
1779+
# If we're restoring a bookmark, we need to try to set all inner shiny input values.
1780+
shiny_input_dep = tags.script(
1781+
textwrap.dedent(
1782+
"""
1783+
(function() {
1784+
const chatId = "#%s";
1785+
const chatEl = document.querySelector(chatId);
1786+
const inputs = %s;
1787+
console.log("chatEl", chatEl);
1788+
console.log("inputs", inputs);
1789+
console.log(chatEl.querySelectorAll(".shiny-bound-input"));
1790+
1791+
function restoreShinyInput(el) {
1792+
console.log("setValue - start");
1793+
const inputId = el.getAttribute("id");
1794+
console.log("inputId", inputId);
1795+
if (!(inputId in inputs)) return;
1796+
1797+
const inputVal = inputs[inputId];
1798+
console.log("inputVal", inputVal);
1799+
1800+
const inputBinding = $(el).data("shinyInputBinding")
1801+
console.log("inputBinding", inputBinding);
1802+
if (!inputBinding) return;
1803+
1804+
inputBinding.setValue(el, inputVal);
1805+
console.log("setValue - done");
1806+
}
1807+
1808+
if (chatEl) {
1809+
chatEl.querySelectorAll(".shiny-bound-input").forEach(restoreShinyInput);
1810+
}
1811+
1812+
console.log("shiny:bound - added");
1813+
$(document).on("shiny:bound", function(evt) {
1814+
const targetEl = evt.target;
1815+
if (!targetEl) return;
1816+
if (!(targetEl.id in inputs)) return;
1817+
1818+
// If target not within the chat, ignore
1819+
const chatEl = targetEl.closest(chatId);
1820+
console.log("chatEl", chatEl);
1821+
console.log("targetEl", targetEl);
1822+
if (!chatEl) return;
1823+
1824+
console.log("restoreShinyInput - start");
1825+
try {
1826+
restoreShinyInput(targetEl);
1827+
} finally {
1828+
// Remove the input value
1829+
console.log("delete input:", targetEl.id);
1830+
delete inputs[targetEl.id];
1831+
1832+
console.log("restoreShinyInput - done");
1833+
}
1834+
});
1835+
})();
1836+
"""
1837+
% (id, json.dumps(input_dict))
1838+
)
1839+
)
1840+
17571841
res = Tag(
17581842
"shiny-chat-container",
17591843
Tag("shiny-chat-messages", *message_tags),
@@ -1764,6 +1848,7 @@ def chat_ui(
17641848
),
17651849
chat_deps(),
17661850
icon_deps,
1851+
shiny_input_dep,
17671852
{
17681853
"style": css(
17691854
width=as_css_unit(width),

0 commit comments

Comments
 (0)