1+ from __future__ import annotations
2+
3+ from abc import ABC , abstractmethod
4+ from pathlib import Path
5+ from typing import TYPE_CHECKING , Awaitable , Callable , Literal , NoReturn
6+
7+ from .._utils import AsyncCallbacks , CancelCallback , wrap_async
8+ from ..types import MISSING , MISSING_TYPE
9+ from . import _globals as bookmark_globals
10+ from ._globals import BookmarkStore
11+ from ._restore_state import RestoreContextState
12+ from ._save_state import ShinySaveState
13+
114# TODO: bookmark button
215
316# TODO:
4659# * May need to escape (all?) the parameters to avoid collisions with `h=` or `code=`.
4760# Set query string to parent frame / tab
4861
49- from abc import ABC , abstractmethod
50- from pathlib import Path
51- from typing import TYPE_CHECKING , Awaitable , Callable , Literal , NoReturn
52-
53- from .._utils import AsyncCallbacks , CancelCallback , wrap_async
54- from ._restore_state import RestoreContextState
55- from ._save_state import ShinySaveState
5662
5763if TYPE_CHECKING :
5864 from .._namespaces import ResolvedId
7076 ExpressStubSession = Any
7177
7278
73- BookmarkStore = Literal ["url" , "server" , "disable" ]
74-
75-
7679# TODO: future - Local storage Bookmark class!
7780# * Needs a consistent id for storage.
7881# * Needs ways to clean up other storage
@@ -84,7 +87,20 @@ class Bookmark(ABC):
8487 # TODO: Barret - This feels like it needs to be a weakref
8588 _session_root : Session
8689
87- store : BookmarkStore
90+ _store : BookmarkStore | MISSING_TYPE
91+
92+ @property
93+ def store (self ) -> BookmarkStore :
94+ # Should we allow for this?
95+ # Allows a per-session override of the global bookmark store
96+ if isinstance (self ._session_root .bookmark ._store , MISSING_TYPE ):
97+ return bookmark_globals .bookmark_store
98+ return self ._session_root .bookmark ._store
99+
100+ @store .setter
101+ def store (self , value : BookmarkStore ) -> None :
102+ self ._session_root .bookmark ._store = value
103+ self ._store = value
88104
89105 _proxy_exclude_fns : list [Callable [[], list [str ]]]
90106 exclude : list [str ]
@@ -107,8 +123,18 @@ def __init__(self, session_root: Session):
107123 # from ._restore_state import RestoreContext
108124
109125 super ().__init__ ()
126+ # TODO: Barret - Q: Should this be a weakref; Session -> Bookmark -> Session
110127 self ._session_root = session_root
111128 self ._restore_context = None
129+ self ._store = MISSING
130+
131+ self ._proxy_exclude_fns = []
132+ self .exclude = []
133+
134+ self ._on_bookmark_callbacks = AsyncCallbacks ()
135+ self ._on_bookmarked_callbacks = AsyncCallbacks ()
136+ self ._on_restore_callbacks = AsyncCallbacks ()
137+ self ._on_restored_callbacks = AsyncCallbacks ()
112138
113139 # # TODO: Barret - Implement this?!?
114140 # @abstractmethod
@@ -247,25 +273,14 @@ def on_restored(
247273
248274class BookmarkApp (Bookmark ):
249275 def __init__ (self , session_root : Session ):
250-
251276 super ().__init__ (session_root )
252277
253- self .store = "disable"
254- self .store = "url"
255- self .exclude = []
256- self ._proxy_exclude_fns = []
257- self ._on_bookmark_callbacks = AsyncCallbacks ()
258- self ._on_bookmarked_callbacks = AsyncCallbacks ()
259- self ._on_restore_callbacks = AsyncCallbacks ()
260- self ._on_restored_callbacks = AsyncCallbacks ()
261-
262278 def _create_effects (self ) -> None :
263279 # Get bookmarking config
264280 if self .store == "disable" :
265281 return
266282
267283 print ("Creating effects" )
268-
269284 session = self ._session_root
270285
271286 from .. import reactive
@@ -481,17 +496,9 @@ def __init__(self, session_proxy: SessionProxy):
481496 super ().__init__ (session_proxy .root_scope ())
482497
483498 self ._ns = session_proxy .ns
484- # TODO: Barret - This feels like it needs to be a weakref
499+ # TODO: Barret - Q: Should this be a weakref
485500 self ._session_proxy = session_proxy
486501
487- self .exclude = []
488- self ._proxy_exclude_fns = []
489- self ._on_bookmark_callbacks = AsyncCallbacks ()
490- self ._on_bookmarked_callbacks = AsyncCallbacks ()
491- self ._on_restore_callbacks = AsyncCallbacks ()
492- self ._on_restored_callbacks = AsyncCallbacks ()
493-
494- # TODO: Barret - Double check that this works with nested modules!
495502 self ._session_root .bookmark ._proxy_exclude_fns .append (
496503 lambda : [str (self ._ns (name )) for name in self .exclude ]
497504 )
@@ -508,6 +515,14 @@ async def scoped_on_bookmark(root_state: ShinySaveState) -> None:
508515
509516 from ..session import session_context
510517
518+ @self ._root_bookmark .on_bookmarked
519+ async def scoped_on_bookmarked (url : str ) -> None :
520+ if self ._on_bookmarked_callbacks .count () == 0 :
521+ return
522+
523+ with session_context (self ._session_proxy ):
524+ await self ._on_bookmarked_callbacks .invoke (url )
525+
511526 ns_prefix = str (self ._ns + self ._ns ._sep )
512527
513528 @self ._root_bookmark .on_restore
0 commit comments