screengraft 0.41.0 → 0.41.1
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.
- package/package.json +1 -1
- package/scripts/ui.py +15 -1
- package/ui/index.html +9 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "screengraft",
|
|
3
|
-
"version": "0.41.
|
|
3
|
+
"version": "0.41.1",
|
|
4
4
|
"description": "Put a UI screenshot or screen recording onto a photographed device screen with the perspective exactly right \u2014 a homography you confirm by hand, not a generative guess.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"mockup",
|
package/scripts/ui.py
CHANGED
|
@@ -702,6 +702,10 @@ def _adopt(role, path):
|
|
|
702
702
|
return {"path": real, "size": [im.shape[1], im.shape[0]], **meta}
|
|
703
703
|
|
|
704
704
|
|
|
705
|
+
class RenderBusy(Exception):
|
|
706
|
+
"""A request that must not run while a render is in flight."""
|
|
707
|
+
|
|
708
|
+
|
|
705
709
|
def _clear(role):
|
|
706
710
|
"""Un-choose a source. The mirror of _adopt(), and the only way to start
|
|
707
711
|
over: picking a different file was the one exit, and a reload restores the
|
|
@@ -719,6 +723,13 @@ def _clear(role):
|
|
|
719
723
|
"""
|
|
720
724
|
if role not in ROLES:
|
|
721
725
|
raise ValueError(f"role must be one of {', '.join(ROLES)}")
|
|
726
|
+
# A render in flight would publish its output and sidecar AFTER this
|
|
727
|
+
# cleared them, from a source that is no longer loaded -- the exact stale
|
|
728
|
+
# artefact this exists to prevent. Refused, the way the render route
|
|
729
|
+
# refuses a second render; the page shows the message.
|
|
730
|
+
with RENDER_LOCK:
|
|
731
|
+
if RENDER["state"] == "running":
|
|
732
|
+
raise RenderBusy("a render is running — wait for it, then remove the source")
|
|
722
733
|
if role == "photo":
|
|
723
734
|
SESSION.update(photo=None, corners=None, output=None)
|
|
724
735
|
else:
|
|
@@ -897,7 +908,10 @@ class Handler(BaseHTTPRequestHandler):
|
|
|
897
908
|
return self._json(_adopt(b["role"], b["path"]))
|
|
898
909
|
|
|
899
910
|
if u.path == "/api/clear":
|
|
900
|
-
|
|
911
|
+
try:
|
|
912
|
+
return self._json(_clear(b.get("role")))
|
|
913
|
+
except RenderBusy as exc:
|
|
914
|
+
return self._json({"error": str(exc)}, 409)
|
|
901
915
|
|
|
902
916
|
if u.path == "/api/figma":
|
|
903
917
|
return self._json(SESSION.enqueue({
|
package/ui/index.html
CHANGED
|
@@ -1490,6 +1490,11 @@ async function clearSource(role){
|
|
|
1490
1490
|
// Nothing to draw on: the canvas goes back to its empty state rather
|
|
1491
1491
|
// than showing the last photograph with no way to act on it.
|
|
1492
1492
|
const c = $('#c'); c.getContext('2d').clearRect(0, 0, c.width, c.height);
|
|
1493
|
+
// ... and the edge view, which would otherwise keep showing a strip of a
|
|
1494
|
+
// photograph that is no longer here.
|
|
1495
|
+
for (const id of ['strip', 'stripF']) {
|
|
1496
|
+
const k = $('#' + id); if (k) k.getContext('2d').clearRect(0, 0, k.width, k.height);
|
|
1497
|
+
}
|
|
1493
1498
|
$('#cvbar').hidden = true;
|
|
1494
1499
|
$('#detSt').className = 'status';
|
|
1495
1500
|
$('#detSt').textContent = 'Photo removed. A fit you saved for it comes back when you pick it again.';
|
|
@@ -1501,6 +1506,10 @@ async function clearSource(role){
|
|
|
1501
1506
|
: 'Screenshot removed.';
|
|
1502
1507
|
}
|
|
1503
1508
|
markStale();
|
|
1509
|
+
// The control that had focus has just hidden itself; without this, focus
|
|
1510
|
+
// drops to <body> and a keyboard user is nowhere. The empty chip is the
|
|
1511
|
+
// natural next action.
|
|
1512
|
+
chip.focus();
|
|
1504
1513
|
}
|
|
1505
1514
|
document.querySelectorAll('.chipclear').forEach(b => { b.onclick = () => clearSource(b.dataset.role); });
|
|
1506
1515
|
|