@fc3/mmcadi 0.1.49 → 0.1.51

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.
Files changed (40) hide show
  1. package/dist/.last-compile-time +1 -1
  2. package/dist/.last-publish-time +1 -1
  3. package/dist/client.js +503 -84
  4. package/dist/src/client/helper/drag.d.ts +29 -0
  5. package/dist/src/client/helper/drag.js +350 -0
  6. package/dist/src/client/helper/drag.js.map +1 -0
  7. package/dist/src/client/helper/interaction.d.ts +30 -0
  8. package/dist/src/client/helper/interaction.js +385 -0
  9. package/dist/src/client/helper/interaction.js.map +1 -0
  10. package/dist/src/client/page/cursor.d.ts +3 -0
  11. package/dist/src/client/page/cursor.js +52 -33
  12. package/dist/src/client/page/cursor.js.map +1 -1
  13. package/dist/src/client/utility/get-index-path-for-element.d.ts +2 -0
  14. package/dist/src/client/utility/get-index-path-for-element.js +12 -0
  15. package/dist/src/client/utility/get-index-path-for-element.js.map +1 -0
  16. package/dist/src/common/utility/role-is-public.d.ts +3 -0
  17. package/dist/src/common/utility/role-is-public.js +13 -0
  18. package/dist/src/common/utility/role-is-public.js.map +1 -0
  19. package/dist/src/enum/action-type.d.ts +1 -0
  20. package/dist/src/enum/action-type.js +1 -0
  21. package/dist/src/enum/action-type.js.map +1 -1
  22. package/dist/src/index.d.ts +1 -0
  23. package/dist/src/index.js +3 -1
  24. package/dist/src/index.js.map +1 -1
  25. package/dist/src/server/endpoint/action/create.d.ts +1 -0
  26. package/dist/src/server/endpoint/action/create.js +20 -1
  27. package/dist/src/server/endpoint/action/create.js.map +1 -1
  28. package/dist/src/server/operation/reposition-block.d.ts +15 -0
  29. package/dist/src/server/operation/reposition-block.js +108 -0
  30. package/dist/src/server/operation/reposition-block.js.map +1 -0
  31. package/dist/src/server/serializer/base.js +23 -13
  32. package/dist/src/server/serializer/base.js.map +1 -1
  33. package/dist/src/server/serializer/block/audio.js +1 -1
  34. package/dist/src/server/serializer/block.js +24 -20
  35. package/dist/src/server/serializer/block.js.map +1 -1
  36. package/dist/src/type/action/reposition-block.d.ts +8 -0
  37. package/dist/src/type/action/reposition-block.js +3 -0
  38. package/dist/src/type/action/reposition-block.js.map +1 -0
  39. package/dist/tsconfig.tsbuildinfo +1 -1
  40. package/package.json +1 -1
package/dist/client.js CHANGED
@@ -259,9 +259,9 @@
259
259
  };
260
260
  Object.defineProperty(exports, "__esModule", { value: true });
261
261
  var generic_1 = __importDefault(require_generic());
262
- var InvariantViolation12 = class extends generic_1.default {
262
+ var InvariantViolation14 = class extends generic_1.default {
263
263
  };
264
- exports.default = InvariantViolation12;
264
+ exports.default = InvariantViolation14;
265
265
  }
266
266
  });
267
267
 
@@ -968,18 +968,18 @@
968
968
  "node_modules/@fc3/time/dist/src/enum/time-interval.js"(exports) {
969
969
  "use strict";
970
970
  Object.defineProperty(exports, "__esModule", { value: true });
971
- var TimeInterval2;
972
- (function(TimeInterval3) {
973
- TimeInterval3[TimeInterval3["ONE_FRAME"] = 16] = "ONE_FRAME";
974
- TimeInterval3[TimeInterval3["ONE_SECOND"] = 1e3] = "ONE_SECOND";
975
- TimeInterval3[TimeInterval3["ONE_MINUTE"] = 6e4] = "ONE_MINUTE";
976
- TimeInterval3[TimeInterval3["ONE_HOUR"] = 36e5] = "ONE_HOUR";
977
- TimeInterval3[TimeInterval3["ONE_DAY"] = 864e5] = "ONE_DAY";
978
- TimeInterval3[TimeInterval3["ONE_WEEK"] = 6048e5] = "ONE_WEEK";
979
- TimeInterval3[TimeInterval3["ONE_MONTH"] = 2592e6] = "ONE_MONTH";
980
- TimeInterval3[TimeInterval3["ONE_YEAR"] = 31536e6] = "ONE_YEAR";
981
- })(TimeInterval2 || (TimeInterval2 = {}));
982
- exports.default = TimeInterval2;
971
+ var TimeInterval3;
972
+ (function(TimeInterval4) {
973
+ TimeInterval4[TimeInterval4["ONE_FRAME"] = 16] = "ONE_FRAME";
974
+ TimeInterval4[TimeInterval4["ONE_SECOND"] = 1e3] = "ONE_SECOND";
975
+ TimeInterval4[TimeInterval4["ONE_MINUTE"] = 6e4] = "ONE_MINUTE";
976
+ TimeInterval4[TimeInterval4["ONE_HOUR"] = 36e5] = "ONE_HOUR";
977
+ TimeInterval4[TimeInterval4["ONE_DAY"] = 864e5] = "ONE_DAY";
978
+ TimeInterval4[TimeInterval4["ONE_WEEK"] = 6048e5] = "ONE_WEEK";
979
+ TimeInterval4[TimeInterval4["ONE_MONTH"] = 2592e6] = "ONE_MONTH";
980
+ TimeInterval4[TimeInterval4["ONE_YEAR"] = 31536e6] = "ONE_YEAR";
981
+ })(TimeInterval3 || (TimeInterval3 = {}));
982
+ exports.default = TimeInterval3;
983
983
  }
984
984
  });
985
985
 
@@ -1725,7 +1725,7 @@
1725
1725
  });
1726
1726
 
1727
1727
  // src/client/client.ts
1728
- var import_errors12 = __toESM(require_src2());
1728
+ var import_errors14 = __toESM(require_src2());
1729
1729
 
1730
1730
  // src/client/enum/page-type.ts
1731
1731
  var PageType = /* @__PURE__ */ ((PageType2) => {
@@ -2178,9 +2178,9 @@
2178
2178
  var select_block_type_default = SelectBlockTypePage;
2179
2179
 
2180
2180
  // src/client/page/cursor.ts
2181
- var import_errors7 = __toESM(require_src2());
2181
+ var import_errors9 = __toESM(require_src2());
2182
2182
  var import_array = __toESM(require_src3());
2183
- var import_time = __toESM(require_src6());
2183
+ var import_time2 = __toESM(require_src6());
2184
2184
 
2185
2185
  // src/client/utility/get-meta-value.ts
2186
2186
  var import_errors5 = __toESM(require_src2());
@@ -2242,30 +2242,429 @@
2242
2242
  })(MediaReadyState || {});
2243
2243
  var media_ready_state_default = MediaReadyState;
2244
2244
 
2245
- // src/client/page/cursor.ts
2246
- function getAttributeForElement(element, attribute) {
2247
- const value = element.getAttribute(attribute);
2245
+ // src/client/helper/interaction.ts
2246
+ var import_time = __toESM(require_src6());
2247
+ var import_errors8 = __toESM(require_src2());
2248
+
2249
+ // src/enum/action-type.ts
2250
+ var ActionType = /* @__PURE__ */ ((ActionType2) => {
2251
+ ActionType2["ADD_BLOCK"] = "add_block";
2252
+ ActionType2["DELETE_BLOCK"] = "delete_block";
2253
+ ActionType2["MOVE_BLOCK"] = "move_block";
2254
+ ActionType2["HIDE_BLOCK"] = "hide_block";
2255
+ ActionType2["PROMOTE_BLOCK"] = "promote_block";
2256
+ ActionType2["DEMOTE_BLOCK"] = "demote_block";
2257
+ ActionType2["REPOSITION_BLOCK"] = "reposition_block";
2258
+ ActionType2["EDIT_BLOCK"] = "edit_block";
2259
+ ActionType2["CREATE_PAGE"] = "create_page";
2260
+ ActionType2["COMPLETE_BLOCK"] = "complete_block";
2261
+ ActionType2["ADD_BLOCK_TO_PLAYLIST"] = "add_to_playlist";
2262
+ return ActionType2;
2263
+ })(ActionType || {});
2264
+ var action_type_default = ActionType;
2265
+
2266
+ // src/client/utility/get-index-path-for-element.ts
2267
+ var import_errors7 = __toESM(require_src2());
2268
+ function getIndexPathForElement(element) {
2269
+ const value = element.getAttribute("data-index-path");
2248
2270
  if (value === null) {
2249
- throw new import_errors7.InvariantViolation(`
2250
- Tried to read ${attribute} for element, but it was not set
2251
- `);
2271
+ throw new import_errors7.InvariantViolation(
2272
+ "Tried to read data-index-path for element, but it was not set"
2273
+ );
2252
2274
  }
2253
2275
  return value;
2254
2276
  }
2255
- function getIndexPathForElement(element) {
2256
- return getAttributeForElement(element, "data-index-path");
2257
- }
2277
+ var get_index_path_for_element_default = getIndexPathForElement;
2278
+
2279
+ // src/client/helper/interaction.ts
2280
+ var InteractionHelper = class {
2281
+ constructor() {
2282
+ this.drag_start_coordinate = null;
2283
+ this.drag_delay_timer = null;
2284
+ }
2285
+ attach() {
2286
+ document.addEventListener("pointerdown", (event) => {
2287
+ this.handlePointerDown(event);
2288
+ }, { capture: true });
2289
+ document.addEventListener("pointermove", (event) => {
2290
+ this.handlePointerMove(event);
2291
+ }, { capture: true, passive: false });
2292
+ document.addEventListener("pointerup", (event) => {
2293
+ this.handlePointerUp(event);
2294
+ }, { capture: true });
2295
+ document.addEventListener("pointercancel", (event) => {
2296
+ this.handlePointerCancel(event);
2297
+ }, { capture: true });
2298
+ document.addEventListener("dragstart", (event) => {
2299
+ this.handleNativeDragStart(event);
2300
+ }, { capture: true });
2301
+ }
2302
+ isDragging() {
2303
+ const elements = Array.from(document.querySelectorAll(".dragging"));
2304
+ return elements.length > 0;
2305
+ }
2306
+ handlePointerDown(event) {
2307
+ const { target } = event;
2308
+ if (target === null) {
2309
+ return;
2310
+ }
2311
+ const target_element = target;
2312
+ let current_element = target_element;
2313
+ while (current_element) {
2314
+ const attribute = current_element.getAttribute("data-role");
2315
+ if (attribute === "block_activation") {
2316
+ break;
2317
+ }
2318
+ if (current_element instanceof HTMLAnchorElement) {
2319
+ return;
2320
+ }
2321
+ current_element = current_element.parentNode;
2322
+ if (!(current_element instanceof HTMLElement)) {
2323
+ break;
2324
+ }
2325
+ }
2326
+ const block = target_element.closest("section.block");
2327
+ if (block === null) {
2328
+ return;
2329
+ }
2330
+ if (target_element.closest("button, input, textarea, select, label, form")) {
2331
+ return;
2332
+ }
2333
+ const coordinate = this.getEventCoordinate(event);
2334
+ if (coordinate === null) {
2335
+ return;
2336
+ }
2337
+ this.drag_start_coordinate = coordinate;
2338
+ block.classList.add("drag-candidate");
2339
+ this.scheduleDelayedDrag();
2340
+ }
2341
+ scheduleDelayedDrag() {
2342
+ this.cancelDelayedDrag();
2343
+ const delay = import_time.TimeInterval.ONE_SECOND;
2344
+ this.drag_delay_timer = setTimeout(this.beginDelayedDrag.bind(this), delay);
2345
+ }
2346
+ cancelDelayedDrag() {
2347
+ if (this.drag_delay_timer !== null) {
2348
+ clearTimeout(this.drag_delay_timer);
2349
+ }
2350
+ }
2351
+ removeClassFromAllElements(class_name) {
2352
+ const raw_elements = document.querySelectorAll(`.${class_name}`);
2353
+ const elements = Array.from(raw_elements);
2354
+ elements.forEach((element) => {
2355
+ element.classList.remove(class_name);
2356
+ });
2357
+ return elements;
2358
+ }
2359
+ beginDelayedDrag() {
2360
+ const raw_candidates = document.querySelectorAll(".drag-candidate");
2361
+ const candidates = Array.from(raw_candidates);
2362
+ candidates.forEach((candidate) => {
2363
+ const ghost = candidate.cloneNode(true);
2364
+ const index_path = get_index_path_for_element_default(candidate);
2365
+ ghost.classList.add("ghost");
2366
+ ghost.setAttribute("data-for", index_path);
2367
+ candidate.classList.remove("drag-candidate");
2368
+ const { parentNode } = candidate;
2369
+ if (parentNode === null) {
2370
+ throw new import_errors8.InvariantViolation(`
2371
+ Expected drag candidate to be located in a parent, but it was null
2372
+ `);
2373
+ }
2374
+ const rect = candidate.getBoundingClientRect();
2375
+ Object.assign(candidate.style, {
2376
+ top: `${rect.top}px`,
2377
+ left: `${rect.left}px`,
2378
+ width: `${rect.width}px`,
2379
+ height: `${rect.height}px`
2380
+ });
2381
+ candidate.setAttribute("data-drag-start-x", rect.left.toString());
2382
+ candidate.setAttribute("data-drag-start-y", rect.top.toString());
2383
+ candidate.classList.add("dragging");
2384
+ parentNode.insertBefore(ghost, candidate);
2385
+ });
2386
+ }
2387
+ handleNativeDragStart(event) {
2388
+ const target = event.target;
2389
+ if (!target) {
2390
+ return;
2391
+ }
2392
+ const closest_block = target.closest("section.block");
2393
+ if (closest_block !== null) {
2394
+ event.preventDefault();
2395
+ }
2396
+ }
2397
+ handlePointerMove(event) {
2398
+ const current_coordinate = this.getEventCoordinate(event);
2399
+ const start_coordinate = this.getDragStartCoordinate();
2400
+ if (start_coordinate === null || current_coordinate === null) {
2401
+ return;
2402
+ }
2403
+ const { target } = event;
2404
+ if (target !== null) {
2405
+ const target_element = target;
2406
+ const block = target_element.closest("section.block");
2407
+ if (block) {
2408
+ if (!block.classList.contains("dragging")) {
2409
+ block.classList.add("drag-candidate");
2410
+ }
2411
+ }
2412
+ }
2413
+ const { x: start_x, y: start_y } = start_coordinate;
2414
+ const { x: current_x, y: current_y } = current_coordinate;
2415
+ const distance = Math.hypot(current_x - start_x, current_y - start_y);
2416
+ if (distance > 25) {
2417
+ this.removeClassFromAllElements("drag-candidate");
2418
+ }
2419
+ this.scheduleDelayedDrag();
2420
+ const raw_targets = document.querySelectorAll(".dragging");
2421
+ const drag_target_blocks = Array.from(raw_targets);
2422
+ drag_target_blocks.forEach((target_block) => {
2423
+ this.translateDragTargetBlock(target_block, current_coordinate);
2424
+ });
2425
+ if (drag_target_blocks.length > 0) {
2426
+ event.preventDefault();
2427
+ }
2428
+ }
2429
+ translateDragTargetBlock(block, current_coordinate) {
2430
+ const x_attribute = block.getAttribute("data-drag-start-x");
2431
+ const y_attribute = block.getAttribute("data-drag-start-y");
2432
+ if (x_attribute === null || y_attribute === null) {
2433
+ throw new import_errors8.InvariantViolation(`
2434
+ Drag coordinate attributes were invalid:
2435
+ x: ${x_attribute}
2436
+ y: ${y_attribute}
2437
+ `);
2438
+ }
2439
+ const parsed_x = parseInt(x_attribute);
2440
+ const parsed_y = parseInt(y_attribute);
2441
+ if (isNaN(parsed_x) || isNaN(parsed_y)) {
2442
+ throw new import_errors8.InvariantViolation(`
2443
+ Drag coordinate attributes were invalid:
2444
+ x: ${x_attribute}
2445
+ y: ${y_attribute}
2446
+ `);
2447
+ }
2448
+ const start_coordinate = this.getDragStartCoordinate();
2449
+ if (start_coordinate === null) {
2450
+ throw new import_errors8.InvariantViolation(`
2451
+ Tried to translate drag target, but drag start coordinate was null
2452
+ `);
2453
+ }
2454
+ const { x: start_x, y: start_y } = start_coordinate;
2455
+ const { x: current_x, y: current_y } = current_coordinate;
2456
+ const x_delta = current_x - start_x;
2457
+ const y_delta = current_y - start_y;
2458
+ const new_x = parsed_x + x_delta;
2459
+ const new_y = parsed_y + y_delta;
2460
+ block.style.left = `${new_x}px`;
2461
+ block.style.top = `${new_y}px`;
2462
+ const block_rect = block.getBoundingClientRect();
2463
+ const previous_block = this.getPreviousBlock(block);
2464
+ const next_block = this.getNextBlock(block);
2465
+ const ghost = this.getGhostForBlock(block);
2466
+ let swapped = false;
2467
+ if (previous_block !== null) {
2468
+ const previous_rect = previous_block.getBoundingClientRect();
2469
+ const previous_block_y_threshold = previous_rect.top + previous_rect.height * 0.4;
2470
+ if (block_rect.top < previous_block_y_threshold) {
2471
+ swapped = true;
2472
+ const next_sibling = ghost.nextElementSibling;
2473
+ previous_block.replaceWith(ghost);
2474
+ if (next_sibling) {
2475
+ next_sibling.before(previous_block);
2476
+ }
2477
+ }
2478
+ }
2479
+ if (next_block !== null && swapped === false) {
2480
+ const next_rect = next_block.getBoundingClientRect();
2481
+ const next_block_y_threshold = next_rect.top + next_rect.height * 0.6;
2482
+ if (block_rect.bottom > next_block_y_threshold) {
2483
+ const next_sibling = ghost.nextElementSibling === next_block ? ghost : ghost.nextElementSibling;
2484
+ next_block.replaceWith(ghost);
2485
+ if (next_sibling) {
2486
+ next_sibling.before(next_block);
2487
+ }
2488
+ }
2489
+ }
2490
+ }
2491
+ getGhostForBlock(block) {
2492
+ const index_path = get_index_path_for_element_default(block);
2493
+ const ghost = document.querySelector(`[data-for="${index_path}"]`);
2494
+ if (ghost === null) {
2495
+ throw new import_errors8.InvariantViolation(`
2496
+ Unable to find ghost for block with index path ${index_path}
2497
+ `);
2498
+ }
2499
+ return ghost;
2500
+ }
2501
+ getPreviousBlock(block) {
2502
+ const parent_node = block.parentNode;
2503
+ const siblings = Array.from(parent_node.children);
2504
+ const ghost = this.getGhostForBlock(block);
2505
+ let index = siblings.indexOf(ghost);
2506
+ if (index === -1) {
2507
+ throw new import_errors8.InvariantViolation("Unable to locate ghost within siblings");
2508
+ }
2509
+ while (index--) {
2510
+ const sibling = siblings[index];
2511
+ if (sibling === block) {
2512
+ continue;
2513
+ }
2514
+ const { classList } = sibling;
2515
+ if (!classList.contains("block")) {
2516
+ continue;
2517
+ }
2518
+ if (classList.contains("ghost")) {
2519
+ continue;
2520
+ }
2521
+ return sibling;
2522
+ }
2523
+ return null;
2524
+ }
2525
+ getNextBlock(block) {
2526
+ const parent_node = block.parentNode;
2527
+ const siblings = Array.from(parent_node.children);
2528
+ const ghost = this.getGhostForBlock(block);
2529
+ let index = siblings.indexOf(ghost);
2530
+ if (index === -1) {
2531
+ throw new import_errors8.InvariantViolation("Unable to locate ghost within siblings");
2532
+ }
2533
+ while (index < siblings.length) {
2534
+ index++;
2535
+ const sibling = siblings[index];
2536
+ if (sibling === block) {
2537
+ continue;
2538
+ }
2539
+ const { classList } = sibling;
2540
+ if (!classList.contains("block")) {
2541
+ continue;
2542
+ }
2543
+ if (classList.contains("ghost")) {
2544
+ continue;
2545
+ }
2546
+ return sibling;
2547
+ }
2548
+ return null;
2549
+ }
2550
+ handlePointerUp(event) {
2551
+ this.stopDragging();
2552
+ }
2553
+ handlePointerCancel(event) {
2554
+ this.stopDragging();
2555
+ }
2556
+ stopDragging() {
2557
+ this.showFullscreenBlockingOverlay();
2558
+ this.stopDraggingAsync().then(() => {
2559
+ this.hideFullscreenBlockingOverlay();
2560
+ });
2561
+ }
2562
+ showFullscreenBlockingOverlay() {
2563
+ }
2564
+ hideFullscreenBlockingOverlay() {
2565
+ }
2566
+ async stopDraggingAsync() {
2567
+ this.cancelDelayedDrag();
2568
+ this.removeClassFromAllElements("drag-candidate");
2569
+ const dragging_elements = this.removeClassFromAllElements("dragging");
2570
+ let index = 0;
2571
+ while (index < dragging_elements.length) {
2572
+ const element = dragging_elements[index++];
2573
+ const ghost = this.getGhostForBlock(element);
2574
+ const source_index_path = get_index_path_for_element_default(element);
2575
+ const target_index_path = this.getIndexPathForGhost(ghost);
2576
+ await this.submitReposition(source_index_path, target_index_path);
2577
+ ghost.replaceWith(element);
2578
+ Object.assign(element.style, {
2579
+ left: "",
2580
+ top: "",
2581
+ right: "",
2582
+ bottom: "",
2583
+ width: "",
2584
+ height: ""
2585
+ });
2586
+ }
2587
+ }
2588
+ getIndexPathSafe(element) {
2589
+ const is_block = element.classList.contains("block");
2590
+ if (!is_block) {
2591
+ return null;
2592
+ }
2593
+ const is_ghost = element.classList.contains("ghost");
2594
+ if (is_ghost) {
2595
+ return null;
2596
+ }
2597
+ return get_index_path_for_element_default(element);
2598
+ }
2599
+ getIndexPathForGhost(ghost) {
2600
+ let current_child = ghost;
2601
+ while (current_child) {
2602
+ const index_path = this.getIndexPathSafe(current_child);
2603
+ if (index_path !== null) {
2604
+ return index_path;
2605
+ }
2606
+ current_child = current_child.nextElementSibling;
2607
+ }
2608
+ current_child = ghost;
2609
+ while (current_child) {
2610
+ const index_path = this.getIndexPathSafe(current_child);
2611
+ if (index_path !== null) {
2612
+ const index_major_version = parseInt(index_path);
2613
+ const next_version = index_major_version + 1;
2614
+ return next_version.toString();
2615
+ }
2616
+ current_child = current_child.previousElementSibling;
2617
+ }
2618
+ return "0";
2619
+ }
2620
+ async submitReposition(source_index_path, target_index_path) {
2621
+ const form = new FormData();
2622
+ form.set("path", window.location.pathname);
2623
+ form.set("action_type", action_type_default.REPOSITION_BLOCK);
2624
+ form.set("source_index_path", source_index_path);
2625
+ form.set("target_index_path", target_index_path);
2626
+ const response = await fetch(`/actions`, {
2627
+ method: "POST",
2628
+ body: form,
2629
+ credentials: "same-origin",
2630
+ redirect: "follow"
2631
+ });
2632
+ try {
2633
+ const url_object = new URL(response.url, window.location.origin);
2634
+ return url_object.searchParams.get("index_path");
2635
+ } catch (_) {
2636
+ return null;
2637
+ }
2638
+ }
2639
+ getEventCoordinate(event) {
2640
+ return {
2641
+ x: event.clientX,
2642
+ y: event.clientY
2643
+ };
2644
+ }
2645
+ getDragStartCoordinate() {
2646
+ return this.drag_start_coordinate;
2647
+ }
2648
+ };
2649
+ var interaction_default = InteractionHelper;
2650
+
2651
+ // src/client/page/cursor.ts
2258
2652
  var CursorPage = class extends page_default {
2259
2653
  constructor() {
2260
2654
  super();
2261
2655
  this.logged_in = false;
2262
2656
  this.queued_media = null;
2263
2657
  this.ready_media = [];
2658
+ this.interaction_helper = new interaction_default();
2264
2659
  }
2265
2660
  initView() {
2266
2661
  this.focusCurrentBlockElement();
2267
2662
  const meta_value = get_meta_value_default("logged_in");
2268
2663
  this.logged_in = meta_value === "true";
2664
+ if (this.isLoggedIn()) {
2665
+ const interaction_helper = this.getInteractionHelper();
2666
+ interaction_helper.attach();
2667
+ }
2269
2668
  }
2270
2669
  initEvents() {
2271
2670
  super.initEvents();
@@ -2283,7 +2682,8 @@
2283
2682
  });
2284
2683
  }
2285
2684
  handleGenericClick(event) {
2286
- if (!this.hasActiveMedia()) {
2685
+ const interaction_helper = this.getInteractionHelper();
2686
+ if (interaction_helper.isDragging()) {
2287
2687
  return;
2288
2688
  }
2289
2689
  if (event.defaultPrevented) {
@@ -2300,17 +2700,31 @@
2300
2700
  return;
2301
2701
  }
2302
2702
  const target = event.target;
2303
- const anchor = target.closest("a[href]");
2304
- if (anchor === null) {
2305
- return;
2703
+ const selector = '[data-role="block_activation"]';
2704
+ const activator = (() => {
2705
+ if (target.matches(selector)) {
2706
+ return target;
2707
+ }
2708
+ return target.querySelector(selector) || target.closest(selector);
2709
+ })();
2710
+ if (activator !== null) {
2711
+ const block = activator.closest("section.block");
2712
+ if (block === null) {
2713
+ throw new import_errors9.InvariantViolation(`
2714
+ Unable to handle activator; no wrapping block was found
2715
+ `);
2716
+ }
2717
+ return this.activateBlock(block);
2306
2718
  }
2307
- const url = new URL(anchor.href, window.location.href);
2308
- if (url.origin !== window.location.origin) {
2309
- return;
2719
+ const anchor = target.closest("a[href]");
2720
+ if (anchor !== null && this.hasActiveMedia()) {
2721
+ const url = new URL(anchor.href, window.location.href);
2722
+ if (url.origin === window.location.origin) {
2723
+ const path = url.pathname + url.search + url.hash;
2724
+ this.navigateToPath(path);
2725
+ event.preventDefault();
2726
+ }
2310
2727
  }
2311
- event.preventDefault();
2312
- const path = url.pathname + url.search + url.hash;
2313
- this.navigateToPath(path);
2314
2728
  }
2315
2729
  navigateToPath(path) {
2316
2730
  if (!this.hasActiveMedia()) {
@@ -2365,7 +2779,7 @@
2365
2779
  switch (key_code) {
2366
2780
  case key_code_default.ENTER:
2367
2781
  case key_code_default.O:
2368
- return this.activateBlock();
2782
+ return this.activateCurrentBlock();
2369
2783
  case key_code_default.G:
2370
2784
  return this.performPageJump();
2371
2785
  case key_code_default.J:
@@ -2396,13 +2810,13 @@
2396
2810
  const link_id = `${block_id}-add-to-playlist`;
2397
2811
  const link_element = document.getElementById(link_id);
2398
2812
  if (link_element === null) {
2399
- throw new import_errors7.InvariantViolation(`
2813
+ throw new import_errors9.InvariantViolation(`
2400
2814
  Unable to find playlist link element for block: ${block_id}
2401
2815
  `);
2402
2816
  }
2403
2817
  const href = link_element.getAttribute("href");
2404
2818
  if (href === null) {
2405
- throw new import_errors7.InvariantViolation(`
2819
+ throw new import_errors9.InvariantViolation(`
2406
2820
  Unable to find playlist link href for block: ${block_id}
2407
2821
  `);
2408
2822
  }
@@ -2430,7 +2844,7 @@
2430
2844
  const form_id = `${block_id}-promote`;
2431
2845
  const form_element = document.getElementById(form_id);
2432
2846
  if (form_element === null) {
2433
- throw new import_errors7.InvariantViolation(`
2847
+ throw new import_errors9.InvariantViolation(`
2434
2848
  Unable to find promotion form element for block: ${block_id}
2435
2849
  `);
2436
2850
  }
@@ -2448,7 +2862,7 @@
2448
2862
  const form_id = `${block_id}-demote`;
2449
2863
  const form_element = document.getElementById(form_id);
2450
2864
  if (form_element === null) {
2451
- throw new import_errors7.InvariantViolation(`
2865
+ throw new import_errors9.InvariantViolation(`
2452
2866
  Unable to find demotion form element for block: ${block_id}
2453
2867
  `);
2454
2868
  }
@@ -2487,7 +2901,7 @@
2487
2901
  const block_elements = this.getBlockElements();
2488
2902
  let found = false;
2489
2903
  block_elements.forEach((block_element) => {
2490
- const sibling_path = getIndexPathForElement(block_element);
2904
+ const sibling_path = get_index_path_for_element_default(block_element);
2491
2905
  const is_match = sibling_path === index_path;
2492
2906
  block_element.classList.toggle("selected", is_match);
2493
2907
  if (is_match) {
@@ -2495,7 +2909,7 @@
2495
2909
  }
2496
2910
  });
2497
2911
  if (!found) {
2498
- throw new import_errors7.InvariantViolation(`
2912
+ throw new import_errors9.InvariantViolation(`
2499
2913
  Tried to navigate to element at index path ${index_path},
2500
2914
  but matching element was not found
2501
2915
  `);
@@ -2535,7 +2949,7 @@
2535
2949
  if (element === null) {
2536
2950
  return "0";
2537
2951
  }
2538
- return getIndexPathForElement(element);
2952
+ return get_index_path_for_element_default(element);
2539
2953
  }
2540
2954
  getCurrentBlockNumericIndex() {
2541
2955
  const index = this.getCurrentBlockIndex();
@@ -2564,7 +2978,7 @@
2564
2978
  return null;
2565
2979
  }
2566
2980
  const element = block_elements.find((element2) => {
2567
- const attribute = getIndexPathForElement(element2);
2981
+ const attribute = get_index_path_for_element_default(element2);
2568
2982
  return attribute === index_path;
2569
2983
  });
2570
2984
  return element || null;
@@ -2575,7 +2989,7 @@
2575
2989
  if (first_block === void 0) {
2576
2990
  return null;
2577
2991
  }
2578
- return getIndexPathForElement(first_block);
2992
+ return get_index_path_for_element_default(first_block);
2579
2993
  }
2580
2994
  getLastBlockIndex() {
2581
2995
  const blocks = this.getBlockElements();
@@ -2583,7 +2997,7 @@
2583
2997
  if (last_block === void 0) {
2584
2998
  return null;
2585
2999
  }
2586
- return getIndexPathForElement(last_block);
3000
+ return get_index_path_for_element_default(last_block);
2587
3001
  }
2588
3002
  getNextBlockIndex() {
2589
3003
  const current_block = this.getCurrentBlockElement();
@@ -2593,7 +3007,7 @@
2593
3007
  if (next_block === void 0) {
2594
3008
  return null;
2595
3009
  }
2596
- return getIndexPathForElement(next_block);
3010
+ return get_index_path_for_element_default(next_block);
2597
3011
  }
2598
3012
  getPreviousBlockIndex() {
2599
3013
  const current_block = this.getCurrentBlockElement();
@@ -2605,21 +3019,23 @@
2605
3019
  }
2606
3020
  return previous_block.getAttribute("data-index-path");
2607
3021
  }
2608
- activateBlock() {
3022
+ activateCurrentBlock() {
2609
3023
  const block_element = this.getCurrentBlockElement();
2610
- if (block_element === null) {
2611
- return;
3024
+ if (block_element !== null) {
3025
+ this.activateBlock(block_element);
2612
3026
  }
3027
+ }
3028
+ activateBlock(block_element) {
2613
3029
  const attribute = block_element.getAttribute("data-block-type");
2614
3030
  if (attribute === null) {
2615
- throw new import_errors7.InvariantViolation(`
3031
+ throw new import_errors9.InvariantViolation(`
2616
3032
  Tried to activate current block, but it did not have a block type
2617
3033
  `);
2618
3034
  }
2619
3035
  const block_type = attribute;
2620
3036
  const block_types = Object.values(block_type_default);
2621
3037
  if (!block_types.includes(block_type)) {
2622
- throw new import_errors7.InvariantViolation(`
3038
+ throw new import_errors9.InvariantViolation(`
2623
3039
  Invalid block type: ${block_type}
2624
3040
  `);
2625
3041
  }
@@ -2640,7 +3056,7 @@
2640
3056
  const forms = block_element.getElementsByTagName("form");
2641
3057
  const form = forms[0];
2642
3058
  if (form === void 0) {
2643
- throw new import_errors7.InvariantViolation(`
3059
+ throw new import_errors9.InvariantViolation(`
2644
3060
  Tried to activate form for todo block, but it was not set
2645
3061
  `);
2646
3062
  }
@@ -2657,7 +3073,7 @@
2657
3073
  activateAudioBlock(block_element) {
2658
3074
  const audio_element = block_element.querySelectorAll("audio")[0];
2659
3075
  if (audio_element === void 0) {
2660
- throw new import_errors7.InvariantViolation(`
3076
+ throw new import_errors9.InvariantViolation(`
2661
3077
  Tried to read audio element for block, but it was not present
2662
3078
  `);
2663
3079
  }
@@ -2678,11 +3094,11 @@
2678
3094
  this.pauseActiveMedia();
2679
3095
  const media_block = element.closest("section.block");
2680
3096
  if (media_block === null) {
2681
- throw new import_errors7.InvariantViolation(`
3097
+ throw new import_errors9.InvariantViolation(`
2682
3098
  Tried to access closest block wrapper for media, but it was not found
2683
3099
  `);
2684
3100
  }
2685
- const index_path = getIndexPathForElement(media_block);
3101
+ const index_path = get_index_path_for_element_default(media_block);
2686
3102
  this.navigateToIndex(index_path);
2687
3103
  this.focusCurrentBlockElement();
2688
3104
  const persistent_element = document.getElementById("persistent-audio");
@@ -2692,27 +3108,27 @@
2692
3108
  const track_source = media_block.querySelector('[data-role="track_name"]');
2693
3109
  const artist_source = media_block.querySelector('[data-role="artist_name"]');
2694
3110
  if (persistent_audio === null) {
2695
- throw new import_errors7.InvariantViolation(`
3111
+ throw new import_errors9.InvariantViolation(`
2696
3112
  Tried to access persistent audio element, but it was not found
2697
3113
  `);
2698
3114
  }
2699
3115
  if (track_target === null) {
2700
- throw new import_errors7.InvariantViolation(`
3116
+ throw new import_errors9.InvariantViolation(`
2701
3117
  Tried to access persistent track name element, but it was not found
2702
3118
  `);
2703
3119
  }
2704
3120
  if (artist_target === null) {
2705
- throw new import_errors7.InvariantViolation(`
3121
+ throw new import_errors9.InvariantViolation(`
2706
3122
  Tried to access persistent artist name element, but it was not found
2707
3123
  `);
2708
3124
  }
2709
3125
  if (track_source === null) {
2710
- throw new import_errors7.InvariantViolation(`
3126
+ throw new import_errors9.InvariantViolation(`
2711
3127
  Tried to read track name source, but it was not found
2712
3128
  `);
2713
3129
  }
2714
3130
  if (artist_source === null) {
2715
- throw new import_errors7.InvariantViolation(`
3131
+ throw new import_errors9.InvariantViolation(`
2716
3132
  Tried to read artist name source, but it was not found
2717
3133
  `);
2718
3134
  }
@@ -2731,13 +3147,13 @@
2731
3147
  return;
2732
3148
  }
2733
3149
  const media_target = target;
2734
- const duration_ms = media_target.duration * import_time.TimeInterval.ONE_SECOND;
2735
- const timecode = (0, import_time.formatTimecode)(duration_ms);
3150
+ const duration_ms = media_target.duration * import_time2.TimeInterval.ONE_SECOND;
3151
+ const timecode = (0, import_time2.formatTimecode)(duration_ms);
2736
3152
  const block = media_target.closest("section.block");
2737
3153
  if (block !== null) {
2738
3154
  const duration_label = block.querySelector('[data-role="duration"]');
2739
3155
  if (duration_label === null) {
2740
- throw new import_errors7.InvariantViolation(`
3156
+ throw new import_errors9.InvariantViolation(`
2741
3157
  Tried to read duration label for media block, but it was not found
2742
3158
  `);
2743
3159
  }
@@ -2803,6 +3219,9 @@
2803
3219
  media_element.pause();
2804
3220
  });
2805
3221
  }
3222
+ getInteractionHelper() {
3223
+ return this.interaction_helper;
3224
+ }
2806
3225
  isLoggedIn() {
2807
3226
  return this.logged_in;
2808
3227
  }
@@ -2840,7 +3259,7 @@
2840
3259
  var create_block_default = CreateBlockPage;
2841
3260
 
2842
3261
  // src/client/page/edit-block.ts
2843
- var import_errors8 = __toESM(require_src2());
3262
+ var import_errors10 = __toESM(require_src2());
2844
3263
  var EditBlockPage = class extends page_default {
2845
3264
  initEvents() {
2846
3265
  super.initEvents();
@@ -2857,7 +3276,7 @@
2857
3276
  }
2858
3277
  }
2859
3278
  if (form === void 0) {
2860
- throw new import_errors8.InvariantViolation(`
3279
+ throw new import_errors10.InvariantViolation(`
2861
3280
  Tried to read form for textarea, but it was not set
2862
3281
  `);
2863
3282
  }
@@ -2873,7 +3292,7 @@
2873
3292
  var edit_block_default = EditBlockPage;
2874
3293
 
2875
3294
  // src/client/page/view-custom.ts
2876
- var import_errors9 = __toESM(require_src2());
3295
+ var import_errors11 = __toESM(require_src2());
2877
3296
  var ViewCustomPage = class extends cursor_default {
2878
3297
  handleKey(key_code) {
2879
3298
  switch (key_code) {
@@ -2903,13 +3322,13 @@
2903
3322
  const link_id = `${block_id}-edit`;
2904
3323
  const link_element = document.getElementById(link_id);
2905
3324
  if (link_element === null) {
2906
- throw new import_errors9.InvariantViolation(`
3325
+ throw new import_errors11.InvariantViolation(`
2907
3326
  Unable to find edit link element for block: ${block_id}
2908
3327
  `);
2909
3328
  }
2910
3329
  const href = link_element.getAttribute("href");
2911
3330
  if (href === null) {
2912
- throw new import_errors9.InvariantViolation(`
3331
+ throw new import_errors11.InvariantViolation(`
2913
3332
  Unable to find edit link href for block: ${block_id}
2914
3333
  `);
2915
3334
  }
@@ -2922,7 +3341,7 @@
2922
3341
  const current_path = this.getCurrentBlockIndex();
2923
3342
  const top_level_index = parseInt(current_path, 10);
2924
3343
  if (isNaN(top_level_index)) {
2925
- throw new import_errors9.InvariantViolation(`Invalid index path: ${current_path}`);
3344
+ throw new import_errors11.InvariantViolation(`Invalid index path: ${current_path}`);
2926
3345
  }
2927
3346
  const add_block_links = document.querySelectorAll('[data-role="add_block_link"]');
2928
3347
  const link_index = (() => {
@@ -2934,14 +3353,14 @@
2934
3353
  })();
2935
3354
  const link = add_block_links[link_index];
2936
3355
  if (link === void 0) {
2937
- throw new import_errors9.InvariantViolation(`
3356
+ throw new import_errors11.InvariantViolation(`
2938
3357
  Tried to read link at index ${link_index},
2939
3358
  but it was not found
2940
3359
  `);
2941
3360
  }
2942
3361
  const href = link.getAttribute("href");
2943
3362
  if (href === null) {
2944
- throw new import_errors9.InvariantViolation(`
3363
+ throw new import_errors11.InvariantViolation(`
2945
3364
  Tried to read href for link at index ${link_index},
2946
3365
  but it was not set
2947
3366
  `);
@@ -2960,13 +3379,13 @@
2960
3379
  const link_id = `${block_id}-move`;
2961
3380
  const link_element = document.getElementById(link_id);
2962
3381
  if (link_element === null) {
2963
- throw new import_errors9.InvariantViolation(`
3382
+ throw new import_errors11.InvariantViolation(`
2964
3383
  Unable to find move link element for block: ${block_id}
2965
3384
  `);
2966
3385
  }
2967
3386
  const href = link_element.getAttribute("href");
2968
3387
  if (href === null) {
2969
- throw new import_errors9.InvariantViolation(`
3388
+ throw new import_errors11.InvariantViolation(`
2970
3389
  Unable to find move link href for block: ${block_id}
2971
3390
  `);
2972
3391
  }
@@ -2987,13 +3406,13 @@
2987
3406
  const link_id = `${block_id}-hide`;
2988
3407
  const link_element = document.getElementById(link_id);
2989
3408
  if (link_element === null) {
2990
- throw new import_errors9.InvariantViolation(`
3409
+ throw new import_errors11.InvariantViolation(`
2991
3410
  Unable to find hide link element for block: ${block_id}
2992
3411
  `);
2993
3412
  }
2994
3413
  const href = link_element.getAttribute("href");
2995
3414
  if (href === null) {
2996
- throw new import_errors9.InvariantViolation(`
3415
+ throw new import_errors11.InvariantViolation(`
2997
3416
  Unable to find hide link href for block: ${block_id}
2998
3417
  `);
2999
3418
  }
@@ -3004,13 +3423,13 @@
3004
3423
  const link_id = `${block_id}-delete`;
3005
3424
  const link_element = document.getElementById(link_id);
3006
3425
  if (link_element === null) {
3007
- throw new import_errors9.InvariantViolation(`
3426
+ throw new import_errors11.InvariantViolation(`
3008
3427
  Unable to find deletion link element for block: ${block_id}
3009
3428
  `);
3010
3429
  }
3011
3430
  const href = link_element.getAttribute("href");
3012
3431
  if (href === null) {
3013
- throw new import_errors9.InvariantViolation(`
3432
+ throw new import_errors11.InvariantViolation(`
3014
3433
  Unable to find deletion link href for block: ${block_id}
3015
3434
  `);
3016
3435
  }
@@ -3039,7 +3458,7 @@
3039
3458
  var edit_custom_default = EditCustomPage;
3040
3459
 
3041
3460
  // src/client/page/confirm-delete-block.ts
3042
- var import_errors10 = __toESM(require_src2());
3461
+ var import_errors12 = __toESM(require_src2());
3043
3462
  var ConfirmDeleteBlockPage = class extends page_default {
3044
3463
  handleKey(key_code) {
3045
3464
  switch (key_code) {
@@ -3052,7 +3471,7 @@
3052
3471
  submitDeletionForm() {
3053
3472
  const element = document.getElementById("deletion-form");
3054
3473
  if (element === null) {
3055
- throw new import_errors10.InvariantViolation("Could not find deletion form element");
3474
+ throw new import_errors12.InvariantViolation("Could not find deletion form element");
3056
3475
  }
3057
3476
  const form = element;
3058
3477
  form.submit();
@@ -3061,7 +3480,7 @@
3061
3480
  var confirm_delete_block_default = ConfirmDeleteBlockPage;
3062
3481
 
3063
3482
  // src/client/page/confirm-hide-block.ts
3064
- var import_errors11 = __toESM(require_src2());
3483
+ var import_errors13 = __toESM(require_src2());
3065
3484
  var ConfirmHideBlockPage = class extends page_default {
3066
3485
  handleKey(key_code) {
3067
3486
  switch (key_code) {
@@ -3074,7 +3493,7 @@
3074
3493
  submitHideForm() {
3075
3494
  const element = document.getElementById("hide-form");
3076
3495
  if (element === null) {
3077
- throw new import_errors11.InvariantViolation("Could not find hide form element");
3496
+ throw new import_errors13.InvariantViolation("Could not find hide form element");
3078
3497
  }
3079
3498
  const form = element;
3080
3499
  form.submit();
@@ -3167,7 +3586,7 @@
3167
3586
  const page_type = meta_value;
3168
3587
  const page_types = Object.values(page_type_default);
3169
3588
  if (!page_types.includes(page_type)) {
3170
- throw new import_errors12.InvariantViolation(`
3589
+ throw new import_errors14.InvariantViolation(`
3171
3590
  Invalid page type: ${page_type}
3172
3591
  `);
3173
3592
  }