ipyslides 7.0.2__tar.gz → 7.0.4__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {ipyslides-7.0.2 → ipyslides-7.0.4}/PKG-INFO +1 -1
- ipyslides-7.0.4/ipyslides/__version__.py +2 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/base.py +32 -39
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/settings.py +5 -5
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/static/interaction.js +1 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/widgets.py +1 -3
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/core.py +2 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides.egg-info/PKG-INFO +1 -1
- ipyslides-7.0.2/ipyslides/__version__.py +0 -2
- {ipyslides-7.0.2 → ipyslides-7.0.4}/LICENSE +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/README.md +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/__init__.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/__init__.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/_layout.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/_syntax.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/_widgets.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/export_html.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/export_template.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/icons.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/intro.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/navigation.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/notes.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/slide.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/static/interaction.css +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/static/laser.css +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/static/laser.js +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/static/notes.js +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_base/styles.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/_demo.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/dashlab.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/formatters.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/source.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/utils.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/writer.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides/xmd.py +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides.egg-info/SOURCES.txt +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides.egg-info/dependency_links.txt +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides.egg-info/requires.txt +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/ipyslides.egg-info/top_level.txt +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/setup.cfg +0 -0
- {ipyslides-7.0.2 → ipyslides-7.0.4}/setup.py +0 -0
|
@@ -17,6 +17,7 @@ from .slide import SlideGroup, _build_slide
|
|
|
17
17
|
from ..formatters import XTML, htmlize, slidebound
|
|
18
18
|
from ..xmd import error, get_slides_instance, resolve_included_files, _matched_vars, _parse_as_snapshots, _stream_chunks
|
|
19
19
|
from ..utils import _css_docstring
|
|
20
|
+
from ..dashlab import FileWatcher
|
|
20
21
|
|
|
21
22
|
|
|
22
23
|
class BaseSlides:
|
|
@@ -116,6 +117,13 @@ class BaseSlides:
|
|
|
116
117
|
if synced:
|
|
117
118
|
content = self._process_citations(content)
|
|
118
119
|
|
|
120
|
+
# included files should be able to trigger updates even if main file not edited yet, so we track them as assets
|
|
121
|
+
if synced and hasattr(self, '_watcher'):
|
|
122
|
+
self._watcher.assets = re.findall(r'include\`(.*?)\`',content, flags = re.DOTALL)
|
|
123
|
+
|
|
124
|
+
# Now flatten incuded files, after detecting them as assets above
|
|
125
|
+
content = resolve_included_files(content)
|
|
126
|
+
|
|
119
127
|
chunks = list(_stream_chunks(content, '---'))
|
|
120
128
|
handles = self.create(range(start, start + len(chunks))) # create slides faster or return older
|
|
121
129
|
mdvars = [{k:v for k,v in md_kws.items() if k in _matched_vars(chunk)} for chunk in chunks] # vars used in each chunk
|
|
@@ -137,10 +145,11 @@ class BaseSlides:
|
|
|
137
145
|
return SlideGroup(handles)
|
|
138
146
|
|
|
139
147
|
def _process_citations(self, content):
|
|
140
|
-
|
|
141
|
-
if
|
|
142
|
-
raise ValueError(f"Only a single block of citations is parsed, found {len(
|
|
148
|
+
matches = re.findall(r'^```citations.*?^```|^:::\s*citations.*?(?=^:::|\Z|^\S)', content, flags= re.DOTALL | re.MULTILINE)
|
|
149
|
+
if len(matches) > 1:
|
|
150
|
+
raise ValueError(f"Only a single block of citations is parsed, found {len(matches)} blocks\n{matches}")
|
|
143
151
|
|
|
152
|
+
match1 = matches[0] if matches else ''
|
|
144
153
|
content = content.replace(match1, '') # clean up
|
|
145
154
|
if getattr(self,'_bib_md','') != match1:
|
|
146
155
|
self._bib_md = match1 # set for next test
|
|
@@ -181,47 +190,31 @@ class BaseSlides:
|
|
|
181
190
|
raise ValueError("interval should be integer greater than 100 millieconds.")
|
|
182
191
|
|
|
183
192
|
start = self._fix_slide_number(start_slide_number)
|
|
193
|
+
self._watcher = FileWatcher(path, interval=interval)
|
|
184
194
|
|
|
185
|
-
#
|
|
186
|
-
#
|
|
187
|
-
self._from_markdown(start,
|
|
188
|
-
self.widgets._timer.clear() # remove previous updates
|
|
189
|
-
self._mtime = os.stat(path).st_mtime
|
|
190
|
-
included_files = set()
|
|
195
|
+
# First call after watcher set, so it can observe included files immediately,
|
|
196
|
+
# and errors must be caught before going forward
|
|
197
|
+
self._from_markdown(start, path.read_text(encoding="utf-8"), synced=True)
|
|
191
198
|
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
)
|
|
205
|
-
self._from_markdown(start,
|
|
206
|
-
resolve_included_files(content), # add included file text to be detected for changes
|
|
207
|
-
synced=True # only one citation block allowed for consistency
|
|
208
|
-
)
|
|
209
|
-
self.notify('x') # need to remove any notification from previous error
|
|
210
|
-
self._unregister_postrun_cell() # No cells buttons from inside file code run
|
|
211
|
-
except:
|
|
212
|
-
e, text = traceback.format_exc(limit=0).split(':',1) # only get last error for notification
|
|
213
|
-
self.notify(f"{error('SyncError','something went wrong')}<br/>{error(e,text)}",20)
|
|
214
|
-
else:
|
|
215
|
-
self.notify(error("SyncError", f"file {path!r} no longer exists!").value, 20)
|
|
216
|
-
|
|
217
|
-
self.widgets._timer.run(interval, update, loop = True)
|
|
218
|
-
print(f"Syncing content from file {path!r}\nYou can use `Slides.unsync()` to stop syncing.")
|
|
219
|
-
|
|
199
|
+
@self._watcher.on_update
|
|
200
|
+
def update_target_slides(path):
|
|
201
|
+
try:
|
|
202
|
+
self._from_markdown(start, path.read_text(encoding="utf-8"), synced=True)
|
|
203
|
+
self.notify('x') # need to remove any notification from previous error
|
|
204
|
+
self._unregister_postrun_cell() # No cells buttons from inside file code run
|
|
205
|
+
except:
|
|
206
|
+
e, text = traceback.format_exc(limit=0).split(':',1) # only get last error for notification
|
|
207
|
+
self.notify(f"{error('SyncError','something went wrong')}<br/>{error(e,text)}",20)
|
|
208
|
+
|
|
209
|
+
display(self._watcher) # must be displayed to work
|
|
210
|
+
self._unregister_postrun_cell() # avoid unnessary scroll button after postrun cell here
|
|
220
211
|
|
|
221
212
|
def unsync(self):
|
|
222
213
|
"Stop syncing markdown file synced with `Slides.sync_with_file` function."
|
|
223
|
-
if self
|
|
224
|
-
self.
|
|
214
|
+
if getattr(self, '_watcher', None):
|
|
215
|
+
self._watcher.stop() # stop the file watcher
|
|
216
|
+
self._watcher.close() # clear the displayed watcher at frontend
|
|
217
|
+
del self._watcher # remove reference to the watcher
|
|
225
218
|
else:
|
|
226
219
|
print("There was no markdown file linked to sync!")
|
|
227
220
|
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
Author Notes: Classes in this module should only be instantiated in Slides class or it's parent class
|
|
3
3
|
and then provided to other classes via composition, not inheritance.
|
|
4
4
|
"""
|
|
5
|
-
import json
|
|
5
|
+
import json, re
|
|
6
6
|
import traitlets
|
|
7
7
|
from contextlib import suppress
|
|
8
8
|
|
|
@@ -167,11 +167,9 @@ class Footer(ConfigTraits):
|
|
|
167
167
|
style = 'white-space:nowrap;margin-block:0;position:absolute;left:0;bottom:0;width:100%'
|
|
168
168
|
inner = self.text
|
|
169
169
|
if self.section and (running := self._running_section_text(slide)):
|
|
170
|
-
inner += ("
|
|
170
|
+
inner += (" | " if inner else "") + f"<span class='section'>{running}</span>"
|
|
171
171
|
if self.date:
|
|
172
|
-
inner += (
|
|
173
|
-
"<span style='white-space:pre;opacity:0.4;'> \u2502 </span>" if inner else ""
|
|
174
|
-
) + f'{today(fg = "var(--fg2-color)") if self.date == "today" else self.date}'
|
|
172
|
+
inner += (" | " if inner else "") + f'{today(fg = "var(--fg2-color)") if self.date == "today" else self.date}'
|
|
175
173
|
|
|
176
174
|
inner = f'<div class="footer-text"><div>{inner}</div>'
|
|
177
175
|
if self.controls:
|
|
@@ -186,6 +184,8 @@ class Footer(ConfigTraits):
|
|
|
186
184
|
unit = 100/(self.main._slides._lms_idx or 1) # unit progress value per slide
|
|
187
185
|
pbar = f'<div class="sprogress-view" style="width:{pv}%;height:100%;background:var(--accent-color,blue);" data-cw="{pv}" data-uw="{unit}"></div>' # attributes for JS
|
|
188
186
|
inner += f'<div class="slide-progress print-only" style="background:var(--bg2-color,#aaa4);width:100%;height:2px;">{pbar}</div>'
|
|
187
|
+
|
|
188
|
+
inner = re.sub(r'(?<![\`\\])\s*\|\s*', '<span style="white-space:pre;opacity:0.4;"> \u2502 </span>', inner) # replace | with fancy divider before parsing and preserve space around
|
|
189
189
|
return htmlize(f'<div markdown="1" class="slide-footer" style="{style}">{inner}</div>')
|
|
190
190
|
|
|
191
191
|
@fix_sig
|
|
@@ -334,6 +334,7 @@ function printSlides(box, model) {
|
|
|
334
334
|
});
|
|
335
335
|
|
|
336
336
|
box.style.setProperty('--printPadding', `${fpad}px`); // set padding for print mode
|
|
337
|
+
zoom.reset(box); // reset any zoom before print to avoid weird scaling
|
|
337
338
|
|
|
338
339
|
for (let n = 0; n < slides.length; n++) {
|
|
339
340
|
let slide = slides[n];
|
|
@@ -15,7 +15,7 @@ from . import styles
|
|
|
15
15
|
from ._widgets import InteractionWidget, NotesWidget, LaserPointer
|
|
16
16
|
from .intro import get_logo, how_to_print, instructions, key_combs
|
|
17
17
|
from ..utils import html, htmlize
|
|
18
|
-
from ..dashlab import ListWidget,
|
|
18
|
+
from ..dashlab import ListWidget, TabsWidget
|
|
19
19
|
from .. import formatters as fmtrs
|
|
20
20
|
|
|
21
21
|
|
|
@@ -358,7 +358,6 @@ class Widgets:
|
|
|
358
358
|
self.sliders = _Sliders()
|
|
359
359
|
self.checks = _Checks()
|
|
360
360
|
self.htmls = _Htmls()
|
|
361
|
-
self._timer = JupyTimer()
|
|
362
361
|
self.drawer = DrawWidget(self)
|
|
363
362
|
self._ctxmenu= CtxMenu(self, description='Shift + Right Click for Browser Menu')
|
|
364
363
|
self.iw = InteractionWidget(self)
|
|
@@ -384,7 +383,6 @@ class Widgets:
|
|
|
384
383
|
self.htmls.theme,
|
|
385
384
|
self.htmls.usercss,
|
|
386
385
|
self.iw,
|
|
387
|
-
self._timer.widget(minimal=True),
|
|
388
386
|
self.panelbox,
|
|
389
387
|
self.htmls.pointer,
|
|
390
388
|
self.htmls.hilite,
|
|
@@ -973,6 +973,8 @@ class Slides(BaseSlides,metaclass=Singleton):
|
|
|
973
973
|
::: note
|
|
974
974
|
`Slides.PART` is deprecated and kept as an alias for backward compatibility.
|
|
975
975
|
"""
|
|
976
|
+
# DO NOT FALL FOR GLOBAL PAGE STUFF, THAT WOULD BE A NIGHTMARE TO HANDLE
|
|
977
|
+
# AND CANNOT HAVE ITS OWN STATE METADATA, AS WE REMOVED IT EARLIER.
|
|
976
978
|
_type = "PART"
|
|
977
979
|
|
|
978
980
|
def __init__(self, isolate=False):
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|