jekyll-dice-tray 0.5.0 → 0.5.2
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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/assets/jekyll-dice-tray/dice_tray.css +6 -3
- data/assets/jekyll-dice-tray/dice_tray.js +9 -51
- data/lib/jekyll/dice_tray/html_rewriter.rb +26 -2
- data/lib/jekyll/dice_tray/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f94a0efe5f9d8e77660ad59f9a455d7639c5c84f0aba09664f26d707bef1ad5f
|
|
4
|
+
data.tar.gz: ae0e7be86f93d73b93753b7394a38e2a0f45b9f77856803775c16b49048464d8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: f6a7a8507c6a193051373cb66ae7b6f7a71f911e87ac7c01a172c0ba26b62b5eb76793212ca38da475a64ff0bad0572de1518e9f12bb6088aff2f615580e2ed4
|
|
7
|
+
data.tar.gz: 7f3c908b2eee3946f710de9af643e79dd9d001eeb7838654cb818defd6b921f8b33025950a07ad782eb7619af96f471650fb9043c77e115a9b857619acd73179
|
data/README.md
CHANGED
|
@@ -4,7 +4,7 @@ A Jekyll plugin gem that:
|
|
|
4
4
|
|
|
5
5
|
- Adds an overlay dice tray that accepts dice rolling input
|
|
6
6
|
- Recognizes dice expressions in rendered pages like `d4`, `1d6`, `1d20+1` and turns them into clickable links that roll in the tray
|
|
7
|
-
- Clicking a lookup-table die (any `dN`) rolls and shows the matching entry — supports any number of side-by-side key/value column groups, ranges like `3–12`, and tables with or without headers.
|
|
7
|
+
- Clicking a lookup-table die (any `dN`) rolls and shows the matching entry — supports any number of side-by-side key/value column groups, ranges like `3–12`, and tables with or without headers. Header dice always search the whole table (side-by-side column groups included)
|
|
8
8
|
- Persists input history, result history, minimize status
|
|
9
9
|
|
|
10
10
|
https://github.com/user-attachments/assets/6ef8d788-a1ee-49d4-ab26-f63899bb4a10
|
|
@@ -34,13 +34,16 @@
|
|
|
34
34
|
border-radius: 12px;
|
|
35
35
|
box-shadow: 0 18px 48px rgba(0, 0, 0, 0.22);
|
|
36
36
|
overflow: hidden;
|
|
37
|
-
|
|
37
|
+
/* Stay collapsed until data-expanded="true". A default of flex overrides the
|
|
38
|
+
hidden attribute and paints the open tray before hydration. */
|
|
39
|
+
display: none;
|
|
38
40
|
flex-direction: column;
|
|
39
41
|
max-height: 360px;
|
|
40
42
|
}
|
|
41
43
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
+
/* Only the pre-paint script or dice_tray.js sets this; absent means minimized. */
|
|
45
|
+
#jekyll-dice-tray[data-expanded="true"] .jdt-body {
|
|
46
|
+
display: flex;
|
|
44
47
|
}
|
|
45
48
|
|
|
46
49
|
#jekyll-dice-tray .jdt-clue {
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
"use strict";
|
|
3
3
|
|
|
4
4
|
var STORAGE_PREFIX = "jekyll_dice_tray:";
|
|
5
|
+
// Also read before first paint by the inline script in HtmlRewriter.inject_tray.
|
|
5
6
|
var STORAGE_EXPANDED = STORAGE_PREFIX + "expanded";
|
|
6
7
|
var STORAGE_HISTORY = STORAGE_PREFIX + "history_v1";
|
|
7
8
|
var STORAGE_INPUT_HISTORY = STORAGE_PREFIX + "input_history_v1";
|
|
@@ -179,14 +180,6 @@
|
|
|
179
180
|
return Array.prototype.slice.call(row.querySelectorAll("td, th"));
|
|
180
181
|
}
|
|
181
182
|
|
|
182
|
-
function cellColumnIndex(row, cell) {
|
|
183
|
-
var cells = rowCells(row);
|
|
184
|
-
for (var i = 0; i < cells.length; i++) {
|
|
185
|
-
if (cells[i] === cell) return i;
|
|
186
|
-
}
|
|
187
|
-
return -1;
|
|
188
|
-
}
|
|
189
|
-
|
|
190
183
|
function rowLooksLikeHeader(row) {
|
|
191
184
|
if (!row) return false;
|
|
192
185
|
if (row.querySelector("th")) return true;
|
|
@@ -269,13 +262,11 @@
|
|
|
269
262
|
return max;
|
|
270
263
|
}
|
|
271
264
|
|
|
272
|
-
function collectRowEntriesForGroups(row, groups
|
|
265
|
+
function collectRowEntriesForGroups(row, groups) {
|
|
273
266
|
var cells = rowCells(row);
|
|
274
267
|
var entries = [];
|
|
275
|
-
var allowAll = !allowedKeyIndices || !allowedKeyIndices.length;
|
|
276
268
|
for (var g = 0; g < groups.length; g++) {
|
|
277
269
|
var group = groups[g];
|
|
278
|
-
if (!allowAll && allowedKeyIndices.indexOf(group.keyIndex) === -1) continue;
|
|
279
270
|
var keyCell = cells[group.keyIndex];
|
|
280
271
|
if (!keyCell) continue;
|
|
281
272
|
var key = parseKeyEntry(normalizeCellText(keyCell));
|
|
@@ -302,16 +293,17 @@
|
|
|
302
293
|
if (!table || !groups || !groups.length) return false;
|
|
303
294
|
var matches = 0;
|
|
304
295
|
eachDataRow(table, headerRow, function (row) {
|
|
305
|
-
matches += collectRowEntriesForGroups(row, groups
|
|
296
|
+
matches += collectRowEntriesForGroups(row, groups).length;
|
|
306
297
|
});
|
|
307
298
|
return matches >= 2;
|
|
308
299
|
}
|
|
309
300
|
|
|
310
|
-
|
|
301
|
+
// Header dice (one or many side-by-side) always search every key column in the table.
|
|
302
|
+
function findLookupMatch(table, headerRow, groups, rollTotal) {
|
|
311
303
|
var exact = null;
|
|
312
304
|
var range = null;
|
|
313
305
|
eachDataRow(table, headerRow, function (row) {
|
|
314
|
-
var entries = collectRowEntriesForGroups(row, groups
|
|
306
|
+
var entries = collectRowEntriesForGroups(row, groups);
|
|
315
307
|
for (var e = 0; e < entries.length; e++) {
|
|
316
308
|
var entry = entries[e];
|
|
317
309
|
if (entry.key.kind === "exact" && entry.key.value === rollTotal) {
|
|
@@ -329,45 +321,18 @@
|
|
|
329
321
|
return exact || range;
|
|
330
322
|
}
|
|
331
323
|
|
|
332
|
-
function headerDiceCount(headerRow) {
|
|
333
|
-
if (!headerRow) return 0;
|
|
334
|
-
return headerRow.querySelectorAll('a[data-dice]').length;
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
function groupForColumn(groups, columnIndex) {
|
|
338
|
-
for (var g = 0; g < groups.length; g++) {
|
|
339
|
-
var group = groups[g];
|
|
340
|
-
if (columnIndex === group.keyIndex) return group;
|
|
341
|
-
if (group.valueIndices.indexOf(columnIndex) !== -1) return group;
|
|
342
|
-
}
|
|
343
|
-
return null;
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
// One die in the header (e.g. d100 over many pairs) => search every group.
|
|
347
|
-
// Several dice (e.g. d10 | Weather | d10 | Terrain | d6 | Mood) => only the clicked group.
|
|
348
|
-
function allowedKeyIndicesForClick(headerRow, clickCell, groups) {
|
|
349
|
-
if (!headerRow || !clickCell || !groups.length) return null;
|
|
350
|
-
if (headerDiceCount(headerRow) <= 1) return null;
|
|
351
|
-
var col = cellColumnIndex(headerRow, clickCell);
|
|
352
|
-
if (col < 0) return null;
|
|
353
|
-
var group = groupForColumn(groups, col);
|
|
354
|
-
return group ? [group.keyIndex] : null;
|
|
355
|
-
}
|
|
356
|
-
|
|
357
324
|
function getLookupTableContext(anchor, rollTotal) {
|
|
358
325
|
if (!anchor || !anchor.closest || rollTotal == null) return null;
|
|
359
326
|
|
|
360
327
|
var cell = null;
|
|
361
328
|
var table = null;
|
|
362
329
|
var headerRow = null;
|
|
363
|
-
var allowedKeys = null;
|
|
364
330
|
var sourceTable = anchor._jdtSourceTable;
|
|
365
331
|
|
|
366
332
|
if (sourceTable && sourceTable.querySelector) {
|
|
367
333
|
// Re-roll from a previous table result in the tray.
|
|
368
334
|
table = sourceTable;
|
|
369
335
|
headerRow = findTableHeaderRow(table);
|
|
370
|
-
allowedKeys = anchor._jdtAllowedKeyIndices || null;
|
|
371
336
|
} else {
|
|
372
337
|
cell = anchor.closest("td, th");
|
|
373
338
|
if (!cell) return null;
|
|
@@ -384,10 +349,7 @@
|
|
|
384
349
|
var groups = buildColumnGroups(keyColumns, tableColumnCount(table, headerRow));
|
|
385
350
|
if (!isLookupTable(table, headerRow, groups)) return null;
|
|
386
351
|
|
|
387
|
-
|
|
388
|
-
allowedKeys = allowedKeyIndicesForClick(headerRow, cell, groups);
|
|
389
|
-
}
|
|
390
|
-
var matched = findLookupMatch(table, headerRow, groups, rollTotal, allowedKeys);
|
|
352
|
+
var matched = findLookupMatch(table, headerRow, groups, rollTotal);
|
|
391
353
|
if (!matched) return null;
|
|
392
354
|
|
|
393
355
|
var headerCells = headerRow ? rowCells(headerRow) : [];
|
|
@@ -420,9 +382,7 @@
|
|
|
420
382
|
});
|
|
421
383
|
}
|
|
422
384
|
|
|
423
|
-
return columns.length
|
|
424
|
-
? { columns: columns, _sourceTable: table, _allowedKeyIndices: allowedKeys }
|
|
425
|
-
: null;
|
|
385
|
+
return columns.length ? { columns: columns, _sourceTable: table } : null;
|
|
426
386
|
}
|
|
427
387
|
|
|
428
388
|
function serializableTableContext(tableContext) {
|
|
@@ -459,9 +419,6 @@
|
|
|
459
419
|
if (tableContext._sourceTable && tableContext._sourceTable.querySelector) {
|
|
460
420
|
reroll._jdtSourceTable = tableContext._sourceTable;
|
|
461
421
|
}
|
|
462
|
-
if (tableContext._allowedKeyIndices) {
|
|
463
|
-
reroll._jdtAllowedKeyIndices = tableContext._allowedKeyIndices;
|
|
464
|
-
}
|
|
465
422
|
headerSpan.appendChild(reroll);
|
|
466
423
|
} else if (col.header_html) {
|
|
467
424
|
headerSpan.innerHTML = col.header_html;
|
|
@@ -565,6 +522,7 @@
|
|
|
565
522
|
root.setAttribute("data-expanded", expanded ? "true" : "false");
|
|
566
523
|
// Some themes override [hidden], so enforce display too.
|
|
567
524
|
body.hidden = !expanded;
|
|
525
|
+
// Clear the pre-paint inline lock so the expanded stylesheet rule can show the body.
|
|
568
526
|
body.style.display = expanded ? "" : "none";
|
|
569
527
|
saveBool(STORAGE_EXPANDED, expanded);
|
|
570
528
|
if (expanded) {
|
|
@@ -199,18 +199,42 @@ module Jekyll
|
|
|
199
199
|
def self.inject_tray(html, assets_path:)
|
|
200
200
|
return html if html.include?('data-dice-tray-root="true"')
|
|
201
201
|
|
|
202
|
+
# Start collapsed. Inline display:none holds the body shut until the script
|
|
203
|
+
# below runs: the hidden attribute loses to author CSS (including ours), and
|
|
204
|
+
# the deferred dice_tray.js can run after first paint, which flashes the
|
|
205
|
+
# open tray on navigation. This script reads the same localStorage key as
|
|
206
|
+
# STORAGE_EXPANDED in dice_tray.js and applies it before first paint.
|
|
202
207
|
tray = <<~HTML
|
|
203
|
-
<div id="jekyll-dice-tray" data-dice-tray-root="true" data-version="#{VERSION}" aria-live="polite">
|
|
208
|
+
<div id="jekyll-dice-tray" data-dice-tray-root="true" data-version="#{VERSION}" data-expanded="false" aria-live="polite">
|
|
204
209
|
<div class="jdt-header">
|
|
205
210
|
<button type="button" class="jdt-toggle" aria-expanded="false" title="Toggle dice tray">Dice</button>
|
|
206
211
|
</div>
|
|
207
|
-
<div class="jdt-body" hidden>
|
|
212
|
+
<div class="jdt-body" hidden style="display:none">
|
|
208
213
|
<div class="jdt-clue">Type <code>1d20+5</code> or <code>/help</code>, then press Enter.</div>
|
|
209
214
|
<div class="jdt-log" role="log" aria-label="Dice roll log"></div>
|
|
210
215
|
<input class="jdt-input" type="text" inputmode="text" autocomplete="off" spellcheck="false"
|
|
211
216
|
placeholder="Roll: 1d6, d4, 2d8+1, /help" />
|
|
212
217
|
</div>
|
|
213
218
|
</div>
|
|
219
|
+
<script>
|
|
220
|
+
// Synchronous on purpose: must finish before the browser paints the tray.
|
|
221
|
+
(function () {
|
|
222
|
+
try {
|
|
223
|
+
// Keep in sync with STORAGE_EXPANDED in dice_tray.js.
|
|
224
|
+
var expanded = localStorage.getItem("jekyll_dice_tray:expanded") === "true";
|
|
225
|
+
var root = document.getElementById("jekyll-dice-tray");
|
|
226
|
+
if (!root) return;
|
|
227
|
+
root.setAttribute("data-expanded", expanded ? "true" : "false");
|
|
228
|
+
var toggle = root.querySelector(".jdt-toggle");
|
|
229
|
+
if (toggle) toggle.setAttribute("aria-expanded", expanded ? "true" : "false");
|
|
230
|
+
var body = root.querySelector(".jdt-body");
|
|
231
|
+
if (!body) return;
|
|
232
|
+
body.hidden = !expanded;
|
|
233
|
+
// Inline display wins over theme rules that override [hidden].
|
|
234
|
+
body.style.display = expanded ? "flex" : "none";
|
|
235
|
+
} catch (e) {}
|
|
236
|
+
})();
|
|
237
|
+
</script>
|
|
214
238
|
HTML
|
|
215
239
|
|
|
216
240
|
tags = <<~HTML
|