dtree-explorer 1.0.0__tar.gz → 1.0.2__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.
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/PKG-INFO +5 -5
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/README.md +3 -3
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer/__init__.py +1 -1
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer/explorer.html +46 -35
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/PKG-INFO +5 -5
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/pyproject.toml +1 -1
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/tests/test_explorer.py +4 -3
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/LICENSE.md +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer/__main__.py +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer/bridge.py +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/SOURCES.txt +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/dependency_links.txt +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/entry_points.txt +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/requires.txt +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/dtree_explorer.egg-info/top_level.txt +0 -0
- {dtree_explorer-1.0.0 → dtree_explorer-1.0.2}/setup.cfg +0 -0
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dtree-explorer
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: DTree Explorer: encode a directed tree with DTree's two projections (Q1, Q2) and watch it step by step, in the browser
|
|
5
5
|
Author-email: Enis Olgac <enis@digraphs.info>
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/EnisOlgac/DTree-Explorer
|
|
8
8
|
Project-URL: Library, https://github.com/EnisOlgac/DTree
|
|
9
|
-
Project-URL: Online, https://digraphs.
|
|
9
|
+
Project-URL: Online, https://dtree.digraphs.net/
|
|
10
10
|
Project-URL: Paper, https://doi.org/10.5772/intechopen.1013408
|
|
11
11
|
Keywords: directed tree,tree topology,reachability,visualization,incremental encoding,teaching
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -32,7 +32,7 @@ Every tree is computed by the published library, [dtree-encoding](https://pypi.o
|
|
|
32
32
|
|
|
33
33
|
## Three ways to use it
|
|
34
34
|
|
|
35
|
-
**Online:** [digraphs.
|
|
35
|
+
**Online:** [dtree.digraphs.net](https://dtree.digraphs.net/), nothing to install.
|
|
36
36
|
|
|
37
37
|
**As a Python program**, offline, with the library installed on your machine:
|
|
38
38
|
|
|
@@ -59,11 +59,11 @@ The examples include the trees of the paper: the introductory example, Figure 1,
|
|
|
59
59
|
|
|
60
60
|
## Privacy
|
|
61
61
|
|
|
62
|
-
Your tree stays on your computer.
|
|
62
|
+
Your tree stays on your computer. Only the online copy at dtree.digraphs.net counts visits, with [GoatCounter](https://www.goatcounter.com/): no cookies, no personal data. The package and the release file count nothing.
|
|
63
63
|
|
|
64
64
|
## Building
|
|
65
65
|
|
|
66
|
-
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (digraphs.
|
|
66
|
+
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (dtree.digraphs.net) with the installed dtree-encoding. Tests: `python -m unittest discover -s tests`.
|
|
67
67
|
|
|
68
68
|
## Background
|
|
69
69
|
|
|
@@ -6,7 +6,7 @@ Every tree is computed by the published library, [dtree-encoding](https://pypi.o
|
|
|
6
6
|
|
|
7
7
|
## Three ways to use it
|
|
8
8
|
|
|
9
|
-
**Online:** [digraphs.
|
|
9
|
+
**Online:** [dtree.digraphs.net](https://dtree.digraphs.net/), nothing to install.
|
|
10
10
|
|
|
11
11
|
**As a Python program**, offline, with the library installed on your machine:
|
|
12
12
|
|
|
@@ -33,11 +33,11 @@ The examples include the trees of the paper: the introductory example, Figure 1,
|
|
|
33
33
|
|
|
34
34
|
## Privacy
|
|
35
35
|
|
|
36
|
-
Your tree stays on your computer.
|
|
36
|
+
Your tree stays on your computer. Only the online copy at dtree.digraphs.net counts visits, with [GoatCounter](https://www.goatcounter.com/): no cookies, no personal data. The package and the release file count nothing.
|
|
37
37
|
|
|
38
38
|
## Building
|
|
39
39
|
|
|
40
|
-
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (digraphs.
|
|
40
|
+
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (dtree.digraphs.net) with the installed dtree-encoding. Tests: `python -m unittest discover -s tests`.
|
|
41
41
|
|
|
42
42
|
## Background
|
|
43
43
|
|
|
@@ -64,6 +64,11 @@ button:focus-visible, select:focus-visible, textarea:focus-visible, input:focus-
|
|
|
64
64
|
.toolbar { display: flex; flex-wrap: wrap; gap: 10px 18px; align-items: center; }
|
|
65
65
|
.stepper { display: flex; align-items: center; gap: 8px; flex: 1 1 320px; min-width: 0; }
|
|
66
66
|
.stepper input[type="range"] { flex: 1; min-width: 80px; accent-color: var(--accent); }
|
|
67
|
+
.stepper button { white-space: nowrap; }
|
|
68
|
+
@media (max-width: 560px) {
|
|
69
|
+
.stepper { flex-wrap: wrap; }
|
|
70
|
+
.stepper input[type="range"] { order: -1; flex-basis: 100%; } /* slider on its own row above the buttons */
|
|
71
|
+
}
|
|
67
72
|
.steplabel { font-size: 14px; min-height: 1.5em; }
|
|
68
73
|
.steplabel b { font-family: var(--mono); }
|
|
69
74
|
.chips { display: flex; flex-wrap: wrap; gap: 6px; }
|
|
@@ -100,9 +105,6 @@ footer.band { background: var(--peach); margin-top: 8px; }
|
|
|
100
105
|
footer.band .wrap { padding-block: 16px 22px; font-size: 13px; display: flex; flex-wrap: wrap; justify-content: space-between; gap: 8px 24px; }
|
|
101
106
|
footer.band p { margin: 2px 0; }
|
|
102
107
|
footer.band a { color: var(--ink); }
|
|
103
|
-
#consent { position: fixed; left: 0; right: 0; bottom: 0; z-index: 20; background: var(--paper); border-top: 2px solid var(--peach-deep); box-shadow: 0 -4px 14px rgba(0, 0, 0, 0.08); padding-bottom: env(safe-area-inset-bottom, 0px); }
|
|
104
|
-
#consent .wrap { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 10px 18px; padding-block: 12px; font-size: 14px; }
|
|
105
|
-
#consent .row button.agree { background: #2e9b4f; border-color: #2e9b4f; color: #fff; font-weight: 600; }
|
|
106
108
|
.sr { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); }
|
|
107
109
|
@media (prefers-reduced-motion: reduce) { * { transition: none !important; } }
|
|
108
110
|
</style>
|
|
@@ -151,9 +153,9 @@ footer.band a { color: var(--ink); }
|
|
|
151
153
|
<div class="card">
|
|
152
154
|
<div class="toolbar">
|
|
153
155
|
<div class="stepper">
|
|
154
|
-
<button id="prev" type="button"
|
|
156
|
+
<button id="prev" type="button" title="Previous edge (left arrow key)">◀ Previous edge</button>
|
|
155
157
|
<input id="step" type="range" min="0" max="0" value="0" aria-label="Step">
|
|
156
|
-
<button id="next" type="button"
|
|
158
|
+
<button id="next" type="button" title="Next edge (right arrow key)">Next edge ▶</button>
|
|
157
159
|
<button id="play" type="button">Play</button>
|
|
158
160
|
</div>
|
|
159
161
|
<div class="chips" role="group" aria-label="Views">
|
|
@@ -207,19 +209,13 @@ footer.band a { color: var(--ink); }
|
|
|
207
209
|
<footer class="band">
|
|
208
210
|
<div class="wrap">
|
|
209
211
|
<div>
|
|
210
|
-
<p><b>DTree Explorer 1.0.
|
|
212
|
+
<p><b>DTree Explorer 1.0.2</b> · computed by <a href="https://pypi.org/project/dtree-encoding/">dtree-encoding</a> (MIT) · <a href="https://github.com/EnisOlgac/DTree-Explorer">source on GitHub</a> · <a href="https://doi.org/10.5772/intechopen.1013408">the paper</a></p>
|
|
211
213
|
<p>Your tree never leaves your computer. Opened from a file or a website, the page loads the Python runtime from cdn.jsdelivr.net and the package from pypi.org; started with <code>dtree-explorer</code>, it uses the library installed on your machine.</p>
|
|
212
214
|
</div>
|
|
213
|
-
<div><p>Contact: Enis Olgac, enis@digraphs.info</p><p>Copyright © 2026 by Ihsan Enis Olgac, Böblingen</p></div>
|
|
215
|
+
<div><p>Contact: Enis Olgac, enis@digraphs.info</p><p>Copyright © 2026 by Ihsan Enis Olgac, Böblingen</p><p id="legal" hidden><a href="imprint.html">Imprint</a> · <a id="privacy-link" href="#">Privacy</a></p></div>
|
|
214
216
|
</div>
|
|
215
217
|
</footer>
|
|
216
218
|
|
|
217
|
-
<div id="consent" hidden>
|
|
218
|
-
<div class="wrap">
|
|
219
|
-
<span>This page counts visits with Google Analytics, using cookies, if you agree. Please read the statement on <a id="privacy-link" href="https://digraphs.blog/">data protection and privacy</a>.</span>
|
|
220
|
-
<span class="row"><button type="button" id="c-no">No thanks</button><button type="button" class="agree" id="c-yes">I agree</button></span>
|
|
221
|
-
</div>
|
|
222
|
-
</div>
|
|
223
219
|
|
|
224
220
|
<script type="text/plain" id="src-init">"""DTree: directed tree library with dual projections Q1 and Q2."""
|
|
225
221
|
|
|
@@ -1472,9 +1468,9 @@ def encode(text, limit=LIMIT):
|
|
|
1472
1468
|
const CONFIG = {
|
|
1473
1469
|
dtreeVersion: "1.8.0",
|
|
1474
1470
|
pyodideURL: "https://cdn.jsdelivr.net/pyodide/v0.26.4/full/",
|
|
1475
|
-
explorerVersion: "1.0.
|
|
1476
|
-
|
|
1477
|
-
privacyURL: "", //
|
|
1471
|
+
explorerVersion: "1.0.2",
|
|
1472
|
+
counter: "", // GoatCounter endpoint, only in the online copy (dtree.digraphs.net); empty elsewhere
|
|
1473
|
+
privacyURL: "", // privacy notice of the online copy; empty elsewhere
|
|
1478
1474
|
};
|
|
1479
1475
|
const EXAMPLES = {
|
|
1480
1476
|
"Quick start": "A: B; D\nB: C\n",
|
|
@@ -1707,7 +1703,7 @@ function render() {
|
|
|
1707
1703
|
}
|
|
1708
1704
|
const si = C.stepInfo;
|
|
1709
1705
|
$("#steplabel").innerHTML = d.stepwise
|
|
1710
|
-
? `
|
|
1706
|
+
? `Edge ${state.step + 1} of ${total}: <b>${edgeText(si.op)}</b> <span style="color:var(--muted)">(line ${si.line})</span> · ${C.s.q1.length} nodes`
|
|
1711
1707
|
: `Final tree: ${C.s.q1.length} nodes. Step by step is available up to ${d.limit} insertions.`;
|
|
1712
1708
|
$("#stats").textContent = `${d.final.q1.length} nodes · renumberings Q1 / Q2: ${d.renumber[0]} / ${d.renumber[1]}`;
|
|
1713
1709
|
if ($("#v-tree").checked) $("#tree").innerHTML = treeSVG(C);
|
|
@@ -1720,6 +1716,14 @@ function render() {
|
|
|
1720
1716
|
$("#query").innerHTML = queryHTML(C);
|
|
1721
1717
|
}
|
|
1722
1718
|
|
|
1719
|
+
// "p:c" -> "p → c", "s>c" -> "c after s", "s<c" -> "c before s"
|
|
1720
|
+
function edgeText(op) {
|
|
1721
|
+
const at = op.search(/[:<>]/);
|
|
1722
|
+
const a = esc(op.slice(0, at)), b = esc(op.slice(at + 1)), k = op[at];
|
|
1723
|
+
if (k === ":") return `${a} → ${b}`;
|
|
1724
|
+
return `${b} ${k === ">" ? "after" : "before"} ${a}`;
|
|
1725
|
+
}
|
|
1726
|
+
|
|
1723
1727
|
function setData(data) {
|
|
1724
1728
|
stopPlay();
|
|
1725
1729
|
state.data = data;
|
|
@@ -1790,6 +1794,15 @@ function wire() {
|
|
|
1790
1794
|
});
|
|
1791
1795
|
$("#text").addEventListener("keydown", (ev) => { if ((ev.ctrlKey || ev.metaKey) && ev.key === "Enter") runEncode(); });
|
|
1792
1796
|
$("#step").addEventListener("input", (ev) => { stopPlay(); goStep(+ev.target.value); });
|
|
1797
|
+
document.addEventListener("keydown", (ev) => { // arrow keys step edge by edge, except while typing
|
|
1798
|
+
if (ev.altKey || ev.ctrlKey || ev.metaKey || ev.target.closest("textarea, input:not([type=range]), select")) return;
|
|
1799
|
+
if (ev.key === "ArrowRight" || ev.key === "ArrowLeft") {
|
|
1800
|
+
if (ev.target.id === "step") return; // the slider handles its own arrow keys
|
|
1801
|
+
ev.preventDefault();
|
|
1802
|
+
stopPlay();
|
|
1803
|
+
goStep(state.step + (ev.key === "ArrowRight" ? 1 : -1));
|
|
1804
|
+
}
|
|
1805
|
+
});
|
|
1793
1806
|
$("#prev").addEventListener("click", () => { stopPlay(); goStep(state.step - 1); });
|
|
1794
1807
|
$("#next").addEventListener("click", () => { stopPlay(); goStep(state.step + 1); });
|
|
1795
1808
|
$("#play").addEventListener("click", () => {
|
|
@@ -1933,30 +1946,28 @@ async function boot() {
|
|
|
1933
1946
|
}
|
|
1934
1947
|
}
|
|
1935
1948
|
|
|
1936
|
-
// ---- visit counting
|
|
1937
|
-
function track(name, params) {
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
window.
|
|
1941
|
-
|
|
1942
|
-
|
|
1943
|
-
|
|
1949
|
+
// ---- visit counting (online copy only): GoatCounter, no cookies, no personal data --------
|
|
1950
|
+
function track(name, params) {
|
|
1951
|
+
if (!window.goatcounter || typeof window.goatcounter.count !== "function") return;
|
|
1952
|
+
const extra = params ? " " + Object.values(params).join(" ") : "";
|
|
1953
|
+
window.goatcounter.count({ path: name + extra, title: name, event: true });
|
|
1954
|
+
}
|
|
1955
|
+
function startCounter() {
|
|
1956
|
+
if (!CONFIG.counter || location.protocol === "file:" || ["127.0.0.1", "localhost"].includes(location.hostname)) return;
|
|
1944
1957
|
const s = document.createElement("script");
|
|
1945
|
-
s.async = true;
|
|
1958
|
+
s.async = true;
|
|
1959
|
+
s.dataset.goatcounter = CONFIG.counter;
|
|
1960
|
+
s.src = "https://gc.zgo.at/count.js";
|
|
1946
1961
|
document.head.appendChild(s);
|
|
1947
1962
|
}
|
|
1948
|
-
function
|
|
1949
|
-
if (!CONFIG.
|
|
1963
|
+
function privacyLink() {
|
|
1964
|
+
if (!CONFIG.privacyURL) return; // the imprint lies next to the privacy notice
|
|
1950
1965
|
$("#privacy-link").href = CONFIG.privacyURL;
|
|
1951
|
-
|
|
1952
|
-
if (c === "yes") { startAnalytics(); return; }
|
|
1953
|
-
if (c === "no") return;
|
|
1954
|
-
$("#consent").hidden = false;
|
|
1955
|
-
$("#c-yes").addEventListener("click", () => { store.set("dtree-explorer-consent", "yes"); $("#consent").hidden = true; startAnalytics(); });
|
|
1956
|
-
$("#c-no").addEventListener("click", () => { store.set("dtree-explorer-consent", "no"); $("#consent").hidden = true; });
|
|
1966
|
+
$("#legal").hidden = false;
|
|
1957
1967
|
}
|
|
1958
1968
|
|
|
1959
|
-
|
|
1969
|
+
startCounter();
|
|
1970
|
+
privacyLink();
|
|
1960
1971
|
boot();
|
|
1961
1972
|
</script>
|
|
1962
1973
|
</body>
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: dtree-explorer
|
|
3
|
-
Version: 1.0.
|
|
3
|
+
Version: 1.0.2
|
|
4
4
|
Summary: DTree Explorer: encode a directed tree with DTree's two projections (Q1, Q2) and watch it step by step, in the browser
|
|
5
5
|
Author-email: Enis Olgac <enis@digraphs.info>
|
|
6
6
|
License: MIT
|
|
7
7
|
Project-URL: Homepage, https://github.com/EnisOlgac/DTree-Explorer
|
|
8
8
|
Project-URL: Library, https://github.com/EnisOlgac/DTree
|
|
9
|
-
Project-URL: Online, https://digraphs.
|
|
9
|
+
Project-URL: Online, https://dtree.digraphs.net/
|
|
10
10
|
Project-URL: Paper, https://doi.org/10.5772/intechopen.1013408
|
|
11
11
|
Keywords: directed tree,tree topology,reachability,visualization,incremental encoding,teaching
|
|
12
12
|
Classifier: Development Status :: 4 - Beta
|
|
@@ -32,7 +32,7 @@ Every tree is computed by the published library, [dtree-encoding](https://pypi.o
|
|
|
32
32
|
|
|
33
33
|
## Three ways to use it
|
|
34
34
|
|
|
35
|
-
**Online:** [digraphs.
|
|
35
|
+
**Online:** [dtree.digraphs.net](https://dtree.digraphs.net/), nothing to install.
|
|
36
36
|
|
|
37
37
|
**As a Python program**, offline, with the library installed on your machine:
|
|
38
38
|
|
|
@@ -59,11 +59,11 @@ The examples include the trees of the paper: the introductory example, Figure 1,
|
|
|
59
59
|
|
|
60
60
|
## Privacy
|
|
61
61
|
|
|
62
|
-
Your tree stays on your computer.
|
|
62
|
+
Your tree stays on your computer. Only the online copy at dtree.digraphs.net counts visits, with [GoatCounter](https://www.goatcounter.com/): no cookies, no personal data. The package and the release file count nothing.
|
|
63
63
|
|
|
64
64
|
## Building
|
|
65
65
|
|
|
66
|
-
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (digraphs.
|
|
66
|
+
Working in this repository needs the library installed: `pip install dtree-encoding`. `src/template.html` is the page, `dtree_explorer/bridge.py` the Python part it runs, `src/build.py` assembles `dtree_explorer/explorer.html` (package and release) and `site/index.html` (dtree.digraphs.net) with the installed dtree-encoding. Tests: `python -m unittest discover -s tests`.
|
|
67
67
|
|
|
68
68
|
## Background
|
|
69
69
|
|
|
@@ -30,7 +30,7 @@ dtree-explorer = "dtree_explorer.__main__:main"
|
|
|
30
30
|
[project.urls]
|
|
31
31
|
Homepage = "https://github.com/EnisOlgac/DTree-Explorer"
|
|
32
32
|
Library = "https://github.com/EnisOlgac/DTree"
|
|
33
|
-
Online = "https://digraphs.
|
|
33
|
+
Online = "https://dtree.digraphs.net/"
|
|
34
34
|
Paper = "https://doi.org/10.5772/intechopen.1013408"
|
|
35
35
|
|
|
36
36
|
[tool.setuptools]
|
|
@@ -89,11 +89,12 @@ class TestServer(unittest.TestCase):
|
|
|
89
89
|
|
|
90
90
|
class TestPages(unittest.TestCase):
|
|
91
91
|
def test_variants(self):
|
|
92
|
-
plain, site = build.page(), build.page(build.SITE["
|
|
92
|
+
plain, site = build.page(), build.page(build.SITE["counter"], build.SITE["privacy"])
|
|
93
93
|
for html in (plain, site):
|
|
94
94
|
self.assertNotRegex(html, r"__[A-Z_]+__")
|
|
95
|
-
|
|
96
|
-
self.
|
|
95
|
+
self.assertNotIn("googletagmanager", html) # no Google Analytics anywhere
|
|
96
|
+
self.assertNotIn(build.SITE["counter"], plain) # package copy: no visit counting
|
|
97
|
+
self.assertIn(build.SITE["counter"], site)
|
|
97
98
|
|
|
98
99
|
def test_save(self):
|
|
99
100
|
with tempfile.TemporaryDirectory() as d:
|
|
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
|