@fc3/mmcadi 0.1.48 → 0.1.50

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 (52) hide show
  1. package/dist/.last-compile-time +1 -1
  2. package/dist/.last-publish-time +1 -1
  3. package/dist/client.js +1925 -172
  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 +47 -0
  8. package/dist/src/client/helper/interaction.js +739 -0
  9. package/dist/src/client/helper/interaction.js.map +1 -0
  10. package/dist/src/client/page/cursor.d.ts +9 -1
  11. package/dist/src/client/page/cursor.js +206 -47
  12. package/dist/src/client/page/cursor.js.map +1 -1
  13. package/dist/src/client/page/history.js.map +1 -1
  14. package/dist/src/client/page/view-custom.js +3 -0
  15. package/dist/src/client/page/view-custom.js.map +1 -1
  16. package/dist/src/client/page.d.ts +1 -1
  17. package/dist/src/client/page.js +24 -13
  18. package/dist/src/client/page.js.map +1 -1
  19. package/dist/src/client/utility/get-index-path-for-element.d.ts +2 -0
  20. package/dist/src/client/utility/get-index-path-for-element.js +12 -0
  21. package/dist/src/client/utility/get-index-path-for-element.js.map +1 -0
  22. package/dist/src/common/utility/role-is-public.d.ts +3 -0
  23. package/dist/src/common/utility/role-is-public.js +13 -0
  24. package/dist/src/common/utility/role-is-public.js.map +1 -0
  25. package/dist/src/enum/action-type.d.ts +1 -0
  26. package/dist/src/enum/action-type.js +1 -0
  27. package/dist/src/enum/action-type.js.map +1 -1
  28. package/dist/src/enum/emoji.d.ts +3 -1
  29. package/dist/src/enum/emoji.js +2 -0
  30. package/dist/src/enum/emoji.js.map +1 -1
  31. package/dist/src/index.d.ts +1 -0
  32. package/dist/src/index.js +3 -1
  33. package/dist/src/index.js.map +1 -1
  34. package/dist/src/server/endpoint/action/create.d.ts +1 -0
  35. package/dist/src/server/endpoint/action/create.js +20 -1
  36. package/dist/src/server/endpoint/action/create.js.map +1 -1
  37. package/dist/src/server/operation/reposition-block.d.ts +15 -0
  38. package/dist/src/server/operation/reposition-block.js +108 -0
  39. package/dist/src/server/operation/reposition-block.js.map +1 -0
  40. package/dist/src/server/serializer/base.d.ts +1 -0
  41. package/dist/src/server/serializer/base.js +46 -2
  42. package/dist/src/server/serializer/base.js.map +1 -1
  43. package/dist/src/server/serializer/block/audio.js +31 -5
  44. package/dist/src/server/serializer/block/audio.js.map +1 -1
  45. package/dist/src/server/serializer/block/video.js +1 -1
  46. package/dist/src/server/serializer/page.js +5 -3
  47. package/dist/src/server/serializer/page.js.map +1 -1
  48. package/dist/src/type/action/reposition-block.d.ts +8 -0
  49. package/dist/src/type/action/reposition-block.js +3 -0
  50. package/dist/src/type/action/reposition-block.js.map +1 -0
  51. package/dist/tsconfig.tsbuildinfo +1 -1
  52. package/package.json +2 -2
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
 
@@ -888,10 +888,10 @@
888
888
  "node_modules/@fc3/array/dist/src/get-first-value.js"(exports) {
889
889
  "use strict";
890
890
  Object.defineProperty(exports, "__esModule", { value: true });
891
- function getFirstValue3(array) {
891
+ function getFirstValue2(array) {
892
892
  return array[0];
893
893
  }
894
- exports.default = getFirstValue3;
894
+ exports.default = getFirstValue2;
895
895
  }
896
896
  });
897
897
 
@@ -963,8 +963,769 @@
963
963
  }
964
964
  });
965
965
 
966
+ // node_modules/@fc3/time/dist/src/enum/time-interval.js
967
+ var require_time_interval = __commonJS({
968
+ "node_modules/@fc3/time/dist/src/enum/time-interval.js"(exports) {
969
+ "use strict";
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;
983
+ }
984
+ });
985
+
986
+ // node_modules/@fc3/time/dist/src/utility/sleep.js
987
+ var require_sleep = __commonJS({
988
+ "node_modules/@fc3/time/dist/src/utility/sleep.js"(exports) {
989
+ "use strict";
990
+ Object.defineProperty(exports, "__esModule", { value: true });
991
+ function sleep(duration) {
992
+ return new Promise((resolve) => {
993
+ setTimeout(() => {
994
+ resolve();
995
+ }, duration);
996
+ });
997
+ }
998
+ exports.default = sleep;
999
+ }
1000
+ });
1001
+
1002
+ // node_modules/@fc3/grammar/dist/src/noun-inflector.js
1003
+ var require_noun_inflector = __commonJS({
1004
+ "node_modules/@fc3/grammar/dist/src/noun-inflector.js"(exports) {
1005
+ "use strict";
1006
+ Object.defineProperty(exports, "__esModule", { value: true });
1007
+ var SINGULAR_TO_PLURAL_MAP = {
1008
+ loot: "loot"
1009
+ };
1010
+ var NounInflector = class {
1011
+ singularize(plural_form) {
1012
+ for (const singular_key in SINGULAR_TO_PLURAL_MAP) {
1013
+ if (SINGULAR_TO_PLURAL_MAP[singular_key] === plural_form) {
1014
+ return singular_key;
1015
+ }
1016
+ }
1017
+ if (plural_form.slice(-3) === "ies") {
1018
+ return plural_form.slice(0, -3) + "y";
1019
+ }
1020
+ if (plural_form.slice(-1) === "i") {
1021
+ return plural_form.slice(0, -1) + "us";
1022
+ }
1023
+ if (plural_form.slice(-1) === "s") {
1024
+ return plural_form.slice(0, -1);
1025
+ }
1026
+ return plural_form;
1027
+ }
1028
+ pluralize(singular_form) {
1029
+ if (SINGULAR_TO_PLURAL_MAP[singular_form] !== void 0) {
1030
+ return SINGULAR_TO_PLURAL_MAP[singular_form];
1031
+ }
1032
+ if (singular_form.slice(-1) === "y") {
1033
+ if (!this.isVowel(singular_form.slice(-2, -1))) {
1034
+ return singular_form.slice(0, -1) + "ies";
1035
+ }
1036
+ }
1037
+ if (singular_form.slice(-2) === "ch") {
1038
+ return singular_form + "es";
1039
+ }
1040
+ if (singular_form.slice(-2) === "us") {
1041
+ return singular_form.slice(0, -2) + "i";
1042
+ }
1043
+ if (singular_form.slice(-2) === "ss") {
1044
+ return singular_form + "es";
1045
+ }
1046
+ if (singular_form === "life") {
1047
+ return "lives";
1048
+ }
1049
+ return singular_form + "s";
1050
+ }
1051
+ /**
1052
+ * Takes a number, and a singular suffix noun, and returns the correctly
1053
+ * formatted result for the given number.
1054
+ *
1055
+ * Example:
1056
+ *
1057
+ * singularizeOrPluralize(1, 'account') => '1 account'
1058
+ * singularizeOrPluralize(6, 'account') => '6 accounts'
1059
+ */
1060
+ singularizeOrPluralize(amount, suffix) {
1061
+ if (typeof amount === "string") {
1062
+ amount = parseFloat(amount);
1063
+ }
1064
+ if (amount === 1) {
1065
+ return `${amount} ${suffix}`;
1066
+ }
1067
+ const plural_suffix = this.pluralize(suffix);
1068
+ return `${amount} ${plural_suffix}`;
1069
+ }
1070
+ prependArticle(suffix) {
1071
+ const first_letter = suffix[0];
1072
+ const is_vowel = this.isVowel(first_letter);
1073
+ let article;
1074
+ if (is_vowel) {
1075
+ article = "an";
1076
+ } else {
1077
+ article = "a";
1078
+ }
1079
+ return `${article} ${suffix}`;
1080
+ }
1081
+ isVowel(letter) {
1082
+ return /[aeiou]/.test(letter.toLowerCase());
1083
+ }
1084
+ };
1085
+ exports.default = NounInflector;
1086
+ }
1087
+ });
1088
+
1089
+ // node_modules/@fc3/string/dist/src/create-slug.js
1090
+ var require_create_slug = __commonJS({
1091
+ "node_modules/@fc3/string/dist/src/create-slug.js"(exports) {
1092
+ "use strict";
1093
+ Object.defineProperty(exports, "__esModule", { value: true });
1094
+ function createSlug(message) {
1095
+ if (message === "") {
1096
+ throw new Error("Tried to create slug, but message was empty");
1097
+ }
1098
+ return message.replace(/[^A-Za-z0-9-\s_]/g, "").trim().replace(/[\s_]/g, "-").toLowerCase();
1099
+ }
1100
+ exports.default = createSlug;
1101
+ }
1102
+ });
1103
+
1104
+ // node_modules/@fc3/string/dist/src/capitalize.js
1105
+ var require_capitalize = __commonJS({
1106
+ "node_modules/@fc3/string/dist/src/capitalize.js"(exports) {
1107
+ "use strict";
1108
+ Object.defineProperty(exports, "__esModule", { value: true });
1109
+ function capitalize(str) {
1110
+ const first_character = str[0];
1111
+ const remaining_characters = str.slice(1);
1112
+ return first_character.toUpperCase() + remaining_characters;
1113
+ }
1114
+ exports.default = capitalize;
1115
+ }
1116
+ });
1117
+
1118
+ // node_modules/@fc3/string/dist/src/enum/string-encoding.js
1119
+ var require_string_encoding = __commonJS({
1120
+ "node_modules/@fc3/string/dist/src/enum/string-encoding.js"(exports) {
1121
+ "use strict";
1122
+ Object.defineProperty(exports, "__esModule", { value: true });
1123
+ var StringEncoding;
1124
+ (function(StringEncoding2) {
1125
+ StringEncoding2["ASCII"] = "ascii";
1126
+ StringEncoding2["BASE64"] = "base64";
1127
+ StringEncoding2["BINARY"] = "binary";
1128
+ StringEncoding2["HEX"] = "hex";
1129
+ StringEncoding2["UTF8"] = "utf8";
1130
+ })(StringEncoding || (StringEncoding = {}));
1131
+ exports.default = StringEncoding;
1132
+ }
1133
+ });
1134
+
1135
+ // node_modules/@fc3/string/dist/src/index.js
1136
+ var require_src4 = __commonJS({
1137
+ "node_modules/@fc3/string/dist/src/index.js"(exports) {
1138
+ "use strict";
1139
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1140
+ return mod && mod.__esModule ? mod : { "default": mod };
1141
+ };
1142
+ Object.defineProperty(exports, "__esModule", { value: true });
1143
+ exports.StringEncoding = exports.capitalize = exports.createSlug = void 0;
1144
+ var create_slug_1 = require_create_slug();
1145
+ Object.defineProperty(exports, "createSlug", { enumerable: true, get: function() {
1146
+ return __importDefault(create_slug_1).default;
1147
+ } });
1148
+ var capitalize_1 = require_capitalize();
1149
+ Object.defineProperty(exports, "capitalize", { enumerable: true, get: function() {
1150
+ return __importDefault(capitalize_1).default;
1151
+ } });
1152
+ var string_encoding_1 = require_string_encoding();
1153
+ Object.defineProperty(exports, "StringEncoding", { enumerable: true, get: function() {
1154
+ return __importDefault(string_encoding_1).default;
1155
+ } });
1156
+ }
1157
+ });
1158
+
1159
+ // node_modules/@fc3/grammar/dist/src/verb-inflector.js
1160
+ var require_verb_inflector = __commonJS({
1161
+ "node_modules/@fc3/grammar/dist/src/verb-inflector.js"(exports) {
1162
+ "use strict";
1163
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1164
+ return mod && mod.__esModule ? mod : { "default": mod };
1165
+ };
1166
+ Object.defineProperty(exports, "__esModule", { value: true });
1167
+ var string_1 = require_src4();
1168
+ var noun_inflector_1 = __importDefault(require_noun_inflector());
1169
+ var VerbInflector = class {
1170
+ constructor(value) {
1171
+ this.value = value;
1172
+ const index = value.indexOf(" ");
1173
+ if (index !== -1) {
1174
+ this.suffix = value.slice(index);
1175
+ value = value.slice(0, index);
1176
+ } else {
1177
+ this.suffix = "";
1178
+ }
1179
+ this.uppercase = value !== value.toLowerCase();
1180
+ this.verb = value.toLowerCase();
1181
+ }
1182
+ toPresentParticiple() {
1183
+ if (this.verb === "group") {
1184
+ return this.finalize("grouping");
1185
+ }
1186
+ if (this.verb === "be") {
1187
+ return this.finalize("being");
1188
+ }
1189
+ if (/[aeiou]p$/.test(this.verb)) {
1190
+ return this.finalize(this.verb + "ping");
1191
+ }
1192
+ if (/[aeiou]g$/.test(this.verb)) {
1193
+ return this.finalize(this.verb + "ging");
1194
+ }
1195
+ if (/ee$/.test(this.verb)) {
1196
+ return this.finalize(this.verb + "ing");
1197
+ }
1198
+ if (/e$/.test(this.verb)) {
1199
+ return this.finalize(this.verb.slice(0, -1) + "ing");
1200
+ }
1201
+ if (/[aeiou]n$/.test(this.verb)) {
1202
+ return this.finalize(this.verb + "ning");
1203
+ }
1204
+ if (/[aeiou]t$/.test(this.verb)) {
1205
+ return this.finalize(this.verb + "ting");
1206
+ }
1207
+ return this.finalize(this.verb + "ing");
1208
+ }
1209
+ toPastParticiple() {
1210
+ switch (this.verb) {
1211
+ case "choose":
1212
+ return this.finalize("chosen");
1213
+ default:
1214
+ return this.toPastTense();
1215
+ }
1216
+ }
1217
+ toInfinitive() {
1218
+ return this.finalize(`to ${this.verb}`);
1219
+ }
1220
+ toAdjective() {
1221
+ if (this.value.startsWith("be ")) {
1222
+ return this.value.slice(3);
1223
+ } else {
1224
+ return this.finalize(this.verb + "y");
1225
+ }
1226
+ }
1227
+ toPresentTense() {
1228
+ switch (this.verb) {
1229
+ case "be":
1230
+ return this.finalize("is");
1231
+ default:
1232
+ return this.finalize(this.verb);
1233
+ }
1234
+ }
1235
+ toImperfectTense() {
1236
+ const participle = this.toPresentParticiple();
1237
+ return this.finalize(`was ${participle}`);
1238
+ }
1239
+ toPastTense() {
1240
+ switch (this.verb) {
1241
+ case "find":
1242
+ return this.finalize("found");
1243
+ case "get":
1244
+ return this.finalize("got");
1245
+ case "run":
1246
+ return this.finalize("ran");
1247
+ case "read":
1248
+ return this.finalize("read");
1249
+ case "write":
1250
+ return this.finalize("wrote");
1251
+ case "choose":
1252
+ return this.finalize("chose");
1253
+ case "build":
1254
+ return this.finalize("built");
1255
+ }
1256
+ if (/[aeiou]p$/.test(this.verb)) {
1257
+ return this.finalize(this.verb + "ped");
1258
+ }
1259
+ if (/[aeiou]g$/.test(this.verb)) {
1260
+ return this.finalize(this.verb + "ged");
1261
+ }
1262
+ if (this.verb === "be") {
1263
+ return this.finalize("was");
1264
+ }
1265
+ if (this.verb === "draw") {
1266
+ return this.finalize("drew");
1267
+ }
1268
+ if (/e$/.test(this.verb)) {
1269
+ return this.finalize(this.verb + "d");
1270
+ }
1271
+ if (/[aeiou]y$/.test(this.verb)) {
1272
+ return this.finalize(this.verb + "ed");
1273
+ }
1274
+ if (/y$/.test(this.verb)) {
1275
+ return this.finalize(this.verb.slice(0, -1) + "ied");
1276
+ }
1277
+ return this.finalize(this.verb + "ed");
1278
+ }
1279
+ toFutureTense() {
1280
+ return this.finalize(`will ${this.verb}`);
1281
+ }
1282
+ toSingularNoun() {
1283
+ switch (this.verb) {
1284
+ case "cut":
1285
+ return this.finalize("cut");
1286
+ case "die":
1287
+ return this.finalize("death");
1288
+ case "live":
1289
+ return this.finalize("life");
1290
+ case "change":
1291
+ return this.finalize("change");
1292
+ case "make water":
1293
+ return this.finalize("water");
1294
+ case "do":
1295
+ return this.finalize("action");
1296
+ case "protect":
1297
+ return this.finalize("protection");
1298
+ case "affirm":
1299
+ return this.finalize("affirmation");
1300
+ case "choose":
1301
+ return this.finalize("choice");
1302
+ case "collide":
1303
+ return this.finalize("collision");
1304
+ case "encase":
1305
+ return this.finalize("casing");
1306
+ case "darken":
1307
+ return this.finalize("shadow");
1308
+ case "damage":
1309
+ return this.finalize("damage");
1310
+ case "define":
1311
+ return this.finalize("definition");
1312
+ case "describe":
1313
+ return this.finalize("description");
1314
+ case "hear":
1315
+ return this.finalize("sound");
1316
+ case "measure":
1317
+ return this.finalize("measurement");
1318
+ case "rate":
1319
+ return this.finalize("rating");
1320
+ case "move":
1321
+ return this.finalize("movement");
1322
+ case "regard":
1323
+ return this.finalize("regard");
1324
+ case "survey":
1325
+ return this.finalize("area");
1326
+ case "interact":
1327
+ return this.finalize("interaction");
1328
+ case "name":
1329
+ return this.finalize("name");
1330
+ case "speak":
1331
+ return this.finalize("speech");
1332
+ case "count":
1333
+ return this.finalize("number");
1334
+ case "reside":
1335
+ return this.finalize("residence");
1336
+ case "know":
1337
+ return this.finalize("knowledge");
1338
+ case "divide":
1339
+ return this.finalize("division");
1340
+ case "void":
1341
+ return this.finalize("void");
1342
+ case "make":
1343
+ switch (this.value) {
1344
+ case "make music":
1345
+ return "music";
1346
+ case "make noise":
1347
+ return "noise";
1348
+ default:
1349
+ return this.suffix.slice(1);
1350
+ }
1351
+ case "breathe":
1352
+ return this.finalize("breath");
1353
+ case "have":
1354
+ return this.finalize("belonging");
1355
+ case "bear":
1356
+ if (this.suffix === " fruit") {
1357
+ return "fruit";
1358
+ }
1359
+ case "dream":
1360
+ return "dream";
1361
+ case "test":
1362
+ return "test";
1363
+ case "prepare":
1364
+ return "preparation";
1365
+ case "ascend":
1366
+ return "ascension";
1367
+ case "sleep":
1368
+ return "sleep";
1369
+ default:
1370
+ if (this.verb.slice(-2) === "te") {
1371
+ return this.finalize(this.verb.slice(0, -2) + "tion");
1372
+ }
1373
+ return this.finalize(this.toPresentParticiple());
1374
+ }
1375
+ }
1376
+ toPluralNoun() {
1377
+ const inflector = new noun_inflector_1.default();
1378
+ const singular = this.toSingularNoun();
1379
+ return this.finalize(inflector.pluralize(singular));
1380
+ }
1381
+ toSingularActor() {
1382
+ switch (this.verb) {
1383
+ case "be":
1384
+ return this.finalize("being");
1385
+ }
1386
+ if (this.verb.endsWith("ate")) {
1387
+ return this.finalize(`${this.verb.slice(0, -1)}or`);
1388
+ }
1389
+ if (this.verb.endsWith("e")) {
1390
+ return this.finalize(`${this.verb}r`);
1391
+ }
1392
+ if (this.verb.endsWith("ct")) {
1393
+ return this.finalize(`${this.verb}or`);
1394
+ }
1395
+ return this.finalize(`${this.verb}er`);
1396
+ }
1397
+ toPluralActor() {
1398
+ const singular_actor = this.toSingularActor();
1399
+ const inflector = new noun_inflector_1.default();
1400
+ return this.finalize(inflector.pluralize(singular_actor));
1401
+ }
1402
+ finalize(value) {
1403
+ value += this.suffix;
1404
+ if (this.uppercase) {
1405
+ return (0, string_1.capitalize)(value);
1406
+ } else {
1407
+ return value.toLowerCase();
1408
+ }
1409
+ }
1410
+ };
1411
+ exports.default = VerbInflector;
1412
+ }
1413
+ });
1414
+
1415
+ // node_modules/@fc3/grammar/dist/src/utility/get-words-from-identifier.js
1416
+ var require_get_words_from_identifier = __commonJS({
1417
+ "node_modules/@fc3/grammar/dist/src/utility/get-words-from-identifier.js"(exports) {
1418
+ "use strict";
1419
+ Object.defineProperty(exports, "__esModule", { value: true });
1420
+ function getWordsFromIdentifier(identifier) {
1421
+ const delimited_identifier = identifier.replace(/[a-z][A-Z]/g, (match) => {
1422
+ return match[0] + "_" + match[1];
1423
+ });
1424
+ return delimited_identifier.split("_");
1425
+ }
1426
+ exports.default = getWordsFromIdentifier;
1427
+ }
1428
+ });
1429
+
1430
+ // node_modules/@fc3/grammar/dist/src/utility/singularize.js
1431
+ var require_singularize = __commonJS({
1432
+ "node_modules/@fc3/grammar/dist/src/utility/singularize.js"(exports) {
1433
+ "use strict";
1434
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1435
+ return mod && mod.__esModule ? mod : { "default": mod };
1436
+ };
1437
+ Object.defineProperty(exports, "__esModule", { value: true });
1438
+ var noun_inflector_1 = __importDefault(require_noun_inflector());
1439
+ function singularize(word) {
1440
+ const inflector = new noun_inflector_1.default();
1441
+ return inflector.singularize(word);
1442
+ }
1443
+ exports.default = singularize;
1444
+ }
1445
+ });
1446
+
1447
+ // node_modules/@fc3/grammar/dist/src/utility/pluralize.js
1448
+ var require_pluralize = __commonJS({
1449
+ "node_modules/@fc3/grammar/dist/src/utility/pluralize.js"(exports) {
1450
+ "use strict";
1451
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1452
+ return mod && mod.__esModule ? mod : { "default": mod };
1453
+ };
1454
+ Object.defineProperty(exports, "__esModule", { value: true });
1455
+ var noun_inflector_1 = __importDefault(require_noun_inflector());
1456
+ function pluralize(word) {
1457
+ const inflector = new noun_inflector_1.default();
1458
+ return inflector.pluralize(word);
1459
+ }
1460
+ exports.default = pluralize;
1461
+ }
1462
+ });
1463
+
1464
+ // node_modules/@fc3/grammar/dist/src/utility/singularize-or-pluralize.js
1465
+ var require_singularize_or_pluralize = __commonJS({
1466
+ "node_modules/@fc3/grammar/dist/src/utility/singularize-or-pluralize.js"(exports) {
1467
+ "use strict";
1468
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1469
+ return mod && mod.__esModule ? mod : { "default": mod };
1470
+ };
1471
+ Object.defineProperty(exports, "__esModule", { value: true });
1472
+ var noun_inflector_1 = __importDefault(require_noun_inflector());
1473
+ function singularizeOrPluralize(count, word) {
1474
+ const inflector = new noun_inflector_1.default();
1475
+ return inflector.singularizeOrPluralize(count, word);
1476
+ }
1477
+ exports.default = singularizeOrPluralize;
1478
+ }
1479
+ });
1480
+
1481
+ // node_modules/@fc3/grammar/dist/src/index.js
1482
+ var require_src5 = __commonJS({
1483
+ "node_modules/@fc3/grammar/dist/src/index.js"(exports) {
1484
+ "use strict";
1485
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1486
+ return mod && mod.__esModule ? mod : { "default": mod };
1487
+ };
1488
+ Object.defineProperty(exports, "__esModule", { value: true });
1489
+ exports.singularizeOrPluralize = exports.pluralize = exports.singularize = exports.getWordsFromIdentifier = exports.VerbInflector = exports.NounInflector = void 0;
1490
+ var noun_inflector_1 = require_noun_inflector();
1491
+ Object.defineProperty(exports, "NounInflector", { enumerable: true, get: function() {
1492
+ return __importDefault(noun_inflector_1).default;
1493
+ } });
1494
+ var verb_inflector_1 = require_verb_inflector();
1495
+ Object.defineProperty(exports, "VerbInflector", { enumerable: true, get: function() {
1496
+ return __importDefault(verb_inflector_1).default;
1497
+ } });
1498
+ var get_words_from_identifier_1 = require_get_words_from_identifier();
1499
+ Object.defineProperty(exports, "getWordsFromIdentifier", { enumerable: true, get: function() {
1500
+ return __importDefault(get_words_from_identifier_1).default;
1501
+ } });
1502
+ var singularize_1 = require_singularize();
1503
+ Object.defineProperty(exports, "singularize", { enumerable: true, get: function() {
1504
+ return __importDefault(singularize_1).default;
1505
+ } });
1506
+ var pluralize_1 = require_pluralize();
1507
+ Object.defineProperty(exports, "pluralize", { enumerable: true, get: function() {
1508
+ return __importDefault(pluralize_1).default;
1509
+ } });
1510
+ var singularize_or_pluralize_1 = require_singularize_or_pluralize();
1511
+ Object.defineProperty(exports, "singularizeOrPluralize", { enumerable: true, get: function() {
1512
+ return __importDefault(singularize_or_pluralize_1).default;
1513
+ } });
1514
+ }
1515
+ });
1516
+
1517
+ // node_modules/@fc3/time/dist/src/utility/format-duration.js
1518
+ var require_format_duration = __commonJS({
1519
+ "node_modules/@fc3/time/dist/src/utility/format-duration.js"(exports) {
1520
+ "use strict";
1521
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1522
+ return mod && mod.__esModule ? mod : { "default": mod };
1523
+ };
1524
+ Object.defineProperty(exports, "__esModule", { value: true });
1525
+ var grammar_1 = require_src5();
1526
+ var time_interval_1 = __importDefault(require_time_interval());
1527
+ function formatMilliseconds(ms, shorthand = false) {
1528
+ if (shorthand) {
1529
+ return `${ms}ms`;
1530
+ }
1531
+ const inflector = new grammar_1.NounInflector();
1532
+ return inflector.singularizeOrPluralize(ms, "millisecond");
1533
+ }
1534
+ function formatSeconds(ms, shorthand = false) {
1535
+ const seconds = Math.floor(ms / time_interval_1.default.ONE_SECOND);
1536
+ if (shorthand) {
1537
+ return `${seconds}s`;
1538
+ }
1539
+ const inflector = new grammar_1.NounInflector();
1540
+ return inflector.singularizeOrPluralize(seconds, "second");
1541
+ }
1542
+ function formatMinutes(ms, shorthand = false) {
1543
+ const minutes = Math.floor(ms / time_interval_1.default.ONE_MINUTE);
1544
+ if (shorthand) {
1545
+ return `${minutes}m`;
1546
+ }
1547
+ const inflector = new grammar_1.NounInflector();
1548
+ return inflector.singularizeOrPluralize(minutes, "minute");
1549
+ }
1550
+ function formatHours(ms, shorthand = false) {
1551
+ const hours = Math.floor(ms / time_interval_1.default.ONE_HOUR);
1552
+ if (shorthand) {
1553
+ return `${hours}h`;
1554
+ }
1555
+ const inflector = new grammar_1.NounInflector();
1556
+ return inflector.singularizeOrPluralize(hours, "hour");
1557
+ }
1558
+ function formatDays(ms, shorthand = false) {
1559
+ const days = Math.floor(ms / time_interval_1.default.ONE_DAY);
1560
+ if (shorthand) {
1561
+ return `${days}d`;
1562
+ }
1563
+ const inflector = new grammar_1.NounInflector();
1564
+ return inflector.singularizeOrPluralize(days, "day");
1565
+ }
1566
+ function formatWeeks(ms, shorthand = false) {
1567
+ const weeks = Math.floor(ms / time_interval_1.default.ONE_WEEK);
1568
+ if (shorthand) {
1569
+ return `${weeks}w`;
1570
+ }
1571
+ const inflector = new grammar_1.NounInflector();
1572
+ return inflector.singularizeOrPluralize(weeks, "week");
1573
+ }
1574
+ function formatMonths(ms, shorthand = false) {
1575
+ const months = Math.floor(ms / time_interval_1.default.ONE_MONTH);
1576
+ if (shorthand) {
1577
+ return `${months}mo`;
1578
+ }
1579
+ const inflector = new grammar_1.NounInflector();
1580
+ return inflector.singularizeOrPluralize(months, "month");
1581
+ }
1582
+ function formatYears(ms, shorthand = false) {
1583
+ let years = ms / time_interval_1.default.ONE_YEAR;
1584
+ const years_rounded = Math.round(years);
1585
+ if (Math.abs(years - years_rounded) < 1 / 24) {
1586
+ years = years_rounded;
1587
+ } else {
1588
+ years = parseFloat(years.toFixed(1));
1589
+ }
1590
+ if (shorthand) {
1591
+ return `${years}y`;
1592
+ }
1593
+ const inflector = new grammar_1.NounInflector();
1594
+ return inflector.singularizeOrPluralize(years, "year");
1595
+ }
1596
+ function formatDuration(ms, shorthand = false) {
1597
+ if (ms < time_interval_1.default.ONE_SECOND) {
1598
+ return formatMilliseconds(ms, shorthand);
1599
+ }
1600
+ if (ms < time_interval_1.default.ONE_MINUTE) {
1601
+ return formatSeconds(ms, shorthand);
1602
+ }
1603
+ if (ms < time_interval_1.default.ONE_HOUR) {
1604
+ return formatMinutes(ms, shorthand);
1605
+ }
1606
+ if (ms < time_interval_1.default.ONE_DAY) {
1607
+ return formatHours(ms, shorthand);
1608
+ }
1609
+ if (ms < time_interval_1.default.ONE_WEEK) {
1610
+ return formatDays(ms, shorthand);
1611
+ }
1612
+ if (ms < time_interval_1.default.ONE_MONTH) {
1613
+ return formatWeeks(ms, shorthand);
1614
+ }
1615
+ if (ms < time_interval_1.default.ONE_YEAR) {
1616
+ return formatMonths(ms, shorthand);
1617
+ }
1618
+ return formatYears(ms, shorthand);
1619
+ }
1620
+ exports.default = formatDuration;
1621
+ }
1622
+ });
1623
+
1624
+ // node_modules/@fc3/time/dist/src/utility/format-relative-duration.js
1625
+ var require_format_relative_duration = __commonJS({
1626
+ "node_modules/@fc3/time/dist/src/utility/format-relative-duration.js"(exports) {
1627
+ "use strict";
1628
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1629
+ return mod && mod.__esModule ? mod : { "default": mod };
1630
+ };
1631
+ Object.defineProperty(exports, "__esModule", { value: true });
1632
+ var format_duration_1 = __importDefault(require_format_duration());
1633
+ function formatRelativeDuration(date, shorthand = false) {
1634
+ let ms;
1635
+ if (date instanceof Date) {
1636
+ ms = date.getTime();
1637
+ } else if (typeof date === "string") {
1638
+ ms = new Date(date).getTime();
1639
+ } else {
1640
+ ms = date;
1641
+ }
1642
+ const elapsed_time = Date.now() - ms;
1643
+ return (0, format_duration_1.default)(elapsed_time, shorthand);
1644
+ }
1645
+ exports.default = formatRelativeDuration;
1646
+ }
1647
+ });
1648
+
1649
+ // node_modules/@fc3/time/dist/src/utility/format-relative-date.js
1650
+ var require_format_relative_date = __commonJS({
1651
+ "node_modules/@fc3/time/dist/src/utility/format-relative-date.js"(exports) {
1652
+ "use strict";
1653
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1654
+ return mod && mod.__esModule ? mod : { "default": mod };
1655
+ };
1656
+ Object.defineProperty(exports, "__esModule", { value: true });
1657
+ var format_relative_duration_1 = __importDefault(require_format_relative_duration());
1658
+ function formatRelativeDate(ms) {
1659
+ return (0, format_relative_duration_1.default)(ms) + " ago";
1660
+ }
1661
+ exports.default = formatRelativeDate;
1662
+ }
1663
+ });
1664
+
1665
+ // node_modules/@fc3/time/dist/src/utility/format-timecode.js
1666
+ var require_format_timecode = __commonJS({
1667
+ "node_modules/@fc3/time/dist/src/utility/format-timecode.js"(exports) {
1668
+ "use strict";
1669
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1670
+ return mod && mod.__esModule ? mod : { "default": mod };
1671
+ };
1672
+ Object.defineProperty(exports, "__esModule", { value: true });
1673
+ var time_interval_1 = __importDefault(require_time_interval());
1674
+ function formatTimecode2(ms) {
1675
+ const hours = Math.floor(ms / time_interval_1.default.ONE_HOUR);
1676
+ const leftover_hours = ms % time_interval_1.default.ONE_HOUR;
1677
+ const minutes = Math.floor(leftover_hours / time_interval_1.default.ONE_MINUTE);
1678
+ const leftover_minutes = ms % time_interval_1.default.ONE_MINUTE;
1679
+ const seconds = Math.floor(leftover_minutes / time_interval_1.default.ONE_SECOND);
1680
+ const padded_seconds = seconds.toString().padStart(2, "0");
1681
+ if (hours > 0) {
1682
+ const padded_minutes = minutes.toString().padStart(2, "0");
1683
+ return `${hours}:${padded_minutes}:${padded_seconds}`;
1684
+ }
1685
+ return `${minutes}:${padded_seconds}`;
1686
+ }
1687
+ exports.default = formatTimecode2;
1688
+ }
1689
+ });
1690
+
1691
+ // node_modules/@fc3/time/dist/src/index.js
1692
+ var require_src6 = __commonJS({
1693
+ "node_modules/@fc3/time/dist/src/index.js"(exports) {
1694
+ "use strict";
1695
+ var __importDefault = exports && exports.__importDefault || function(mod) {
1696
+ return mod && mod.__esModule ? mod : { "default": mod };
1697
+ };
1698
+ Object.defineProperty(exports, "__esModule", { value: true });
1699
+ exports.formatTimecode = exports.formatDuration = exports.formatRelativeDate = exports.formatRelativeDuration = exports.sleep = exports.TimeInterval = void 0;
1700
+ var time_interval_1 = require_time_interval();
1701
+ Object.defineProperty(exports, "TimeInterval", { enumerable: true, get: function() {
1702
+ return __importDefault(time_interval_1).default;
1703
+ } });
1704
+ var sleep_1 = require_sleep();
1705
+ Object.defineProperty(exports, "sleep", { enumerable: true, get: function() {
1706
+ return __importDefault(sleep_1).default;
1707
+ } });
1708
+ var format_relative_duration_1 = require_format_relative_duration();
1709
+ Object.defineProperty(exports, "formatRelativeDuration", { enumerable: true, get: function() {
1710
+ return __importDefault(format_relative_duration_1).default;
1711
+ } });
1712
+ var format_relative_date_1 = require_format_relative_date();
1713
+ Object.defineProperty(exports, "formatRelativeDate", { enumerable: true, get: function() {
1714
+ return __importDefault(format_relative_date_1).default;
1715
+ } });
1716
+ var format_duration_1 = require_format_duration();
1717
+ Object.defineProperty(exports, "formatDuration", { enumerable: true, get: function() {
1718
+ return __importDefault(format_duration_1).default;
1719
+ } });
1720
+ var format_timecode_1 = require_format_timecode();
1721
+ Object.defineProperty(exports, "formatTimecode", { enumerable: true, get: function() {
1722
+ return __importDefault(format_timecode_1).default;
1723
+ } });
1724
+ }
1725
+ });
1726
+
966
1727
  // src/client/client.ts
967
- var import_errors12 = __toESM(require_src2());
1728
+ var import_errors14 = __toESM(require_src2());
968
1729
 
969
1730
  // src/client/enum/page-type.ts
970
1731
  var PageType = /* @__PURE__ */ ((PageType2) => {
@@ -993,9 +1754,6 @@
993
1754
  })(PageType || {});
994
1755
  var page_type_default = PageType;
995
1756
 
996
- // src/client/page.ts
997
- var import_array = __toESM(require_src3());
998
-
999
1757
  // src/client/enum/key-code.ts
1000
1758
  var KeyCode = /* @__PURE__ */ ((KeyCode2) => {
1001
1759
  KeyCode2[KeyCode2["ENTER"] = 13] = "ENTER";
@@ -1071,20 +1829,33 @@
1071
1829
  return this.shift_pressed;
1072
1830
  }
1073
1831
  focusElement(element) {
1074
- const rectangle = element.getBoundingClientRect();
1075
- const headers = Array.from(document.getElementsByTagName("header"));
1076
- const header = (0, import_array.getFirstValue)(headers);
1077
- const header_offset = header === void 0 ? 0 : header.clientHeight;
1078
- if (rectangle.top < header_offset) {
1079
- if (header_offset === 0) {
1080
- window.scrollBy(0, rectangle.top);
1832
+ let current_top = 0;
1833
+ let current_element = element;
1834
+ while (current_element) {
1835
+ current_top += current_element.offsetTop;
1836
+ current_element = current_element.offsetParent;
1837
+ }
1838
+ const current_bottom = current_top + element.offsetHeight;
1839
+ const [target_top, viewport_min] = (() => {
1840
+ const header = document.querySelector("header");
1841
+ if (header === null) {
1842
+ return [
1843
+ current_top,
1844
+ window.scrollY
1845
+ ];
1081
1846
  } else {
1082
- window.scrollBy(0, -1 * (header_offset - rectangle.top));
1083
- }
1084
- } else if (rectangle.bottom > window.innerHeight) {
1085
- if (rectangle.height < window.innerHeight) {
1086
- window.scrollBy(0, rectangle.bottom - window.innerHeight);
1847
+ return [
1848
+ current_top - header.offsetHeight,
1849
+ window.scrollY + header.offsetHeight
1850
+ ];
1087
1851
  }
1852
+ })();
1853
+ const viewport_max = window.scrollY + window.innerHeight;
1854
+ if (current_top < viewport_min) {
1855
+ window.scrollTo(0, target_top);
1856
+ }
1857
+ if (current_bottom > viewport_max) {
1858
+ window.scrollTo(0, current_bottom - window.innerHeight);
1088
1859
  }
1089
1860
  }
1090
1861
  getNumericQueryParameter(key, fallback) {
@@ -1385,115 +2156,937 @@
1385
2156
  return super.handleKey(key_code);
1386
2157
  }
1387
2158
  }
1388
- createBlockOfType(block_type) {
1389
- const id = `add-block-${block_type}`;
1390
- const element = document.getElementById(id);
1391
- if (element === null) {
1392
- throw new import_errors4.InvariantViolation(`
1393
- Tried to create block of type ${block_type},
1394
- but the creation link was not found
1395
- `);
2159
+ createBlockOfType(block_type) {
2160
+ const id = `add-block-${block_type}`;
2161
+ const element = document.getElementById(id);
2162
+ if (element === null) {
2163
+ throw new import_errors4.InvariantViolation(`
2164
+ Tried to create block of type ${block_type},
2165
+ but the creation link was not found
2166
+ `);
2167
+ }
2168
+ const href = element.getAttribute("href");
2169
+ if (href === null) {
2170
+ throw new import_errors4.InvariantViolation(`
2171
+ Tried to create block of type ${block_type},
2172
+ but the creation href was not present on the link element
2173
+ `);
2174
+ }
2175
+ window.location.href = href;
2176
+ }
2177
+ };
2178
+ var select_block_type_default = SelectBlockTypePage;
2179
+
2180
+ // src/client/page/cursor.ts
2181
+ var import_errors9 = __toESM(require_src2());
2182
+ var import_array = __toESM(require_src3());
2183
+ var import_time = __toESM(require_src6());
2184
+
2185
+ // src/client/utility/get-meta-value.ts
2186
+ var import_errors5 = __toESM(require_src2());
2187
+ function getMetaValue(name) {
2188
+ const element = document.querySelector(`meta[name="${name}"]`);
2189
+ if (element === null) {
2190
+ throw new import_errors5.InvariantViolation(`
2191
+ Tried to read ${name} meta tag, but it was not set
2192
+ `);
2193
+ }
2194
+ if (!(element instanceof HTMLMetaElement)) {
2195
+ throw new import_errors5.InvariantViolation(`
2196
+ Got wrong element for ${name} meta tag: ${element.tagName}
2197
+ `);
2198
+ }
2199
+ const meta_tag = element;
2200
+ return meta_tag.content;
2201
+ }
2202
+ var get_meta_value_default = getMetaValue;
2203
+
2204
+ // src/server/utility/validate-path.ts
2205
+ var import_errors6 = __toESM(require_src2());
2206
+ function validatePath(path) {
2207
+ if (!path.startsWith("/")) {
2208
+ throw new import_errors6.InvalidError(`Invalid path: ${path}`);
2209
+ }
2210
+ }
2211
+ var validate_path_default = validatePath;
2212
+
2213
+ // src/common/utility/get-parent-path.ts
2214
+ function getParentPath(source_path) {
2215
+ validate_path_default(source_path);
2216
+ const query_index = source_path.indexOf("?");
2217
+ if (query_index !== -1) {
2218
+ source_path = source_path.slice(0, query_index);
2219
+ }
2220
+ if (source_path.endsWith("/")) {
2221
+ source_path = source_path.slice(0, -1);
2222
+ }
2223
+ const parts = source_path.split("/").filter((part) => {
2224
+ return part !== "";
2225
+ });
2226
+ parts.pop();
2227
+ if (parts.length === 0) {
2228
+ return "/";
2229
+ }
2230
+ return "/" + parts.join("/");
2231
+ }
2232
+ var get_parent_path_default = getParentPath;
2233
+
2234
+ // src/client/enum/media-ready-state.ts
2235
+ var MediaReadyState = /* @__PURE__ */ ((MediaReadyState2) => {
2236
+ MediaReadyState2[MediaReadyState2["HAVE_NOTHING"] = 0] = "HAVE_NOTHING";
2237
+ MediaReadyState2[MediaReadyState2["HAVE_METADATA"] = 1] = "HAVE_METADATA";
2238
+ MediaReadyState2[MediaReadyState2["HAVE_CURRENT_DATA"] = 2] = "HAVE_CURRENT_DATA";
2239
+ MediaReadyState2[MediaReadyState2["HAVE_FUTURE_DATA"] = 3] = "HAVE_FUTURE_DATA";
2240
+ MediaReadyState2[MediaReadyState2["HAVE_ENOUGH_DATA"] = 4] = "HAVE_ENOUGH_DATA";
2241
+ return MediaReadyState2;
2242
+ })(MediaReadyState || {});
2243
+ var media_ready_state_default = MediaReadyState;
2244
+
2245
+ // src/client/helper/interaction.ts
2246
+ var import_errors8 = __toESM(require_src2());
2247
+
2248
+ // src/enum/action-type.ts
2249
+ var ActionType = /* @__PURE__ */ ((ActionType2) => {
2250
+ ActionType2["ADD_BLOCK"] = "add_block";
2251
+ ActionType2["DELETE_BLOCK"] = "delete_block";
2252
+ ActionType2["MOVE_BLOCK"] = "move_block";
2253
+ ActionType2["HIDE_BLOCK"] = "hide_block";
2254
+ ActionType2["PROMOTE_BLOCK"] = "promote_block";
2255
+ ActionType2["DEMOTE_BLOCK"] = "demote_block";
2256
+ ActionType2["REPOSITION_BLOCK"] = "reposition_block";
2257
+ ActionType2["EDIT_BLOCK"] = "edit_block";
2258
+ ActionType2["CREATE_PAGE"] = "create_page";
2259
+ ActionType2["COMPLETE_BLOCK"] = "complete_block";
2260
+ ActionType2["ADD_BLOCK_TO_PLAYLIST"] = "add_to_playlist";
2261
+ return ActionType2;
2262
+ })(ActionType || {});
2263
+ var action_type_default = ActionType;
2264
+
2265
+ // src/enum/emoji.ts
2266
+ var Emoji = /* @__PURE__ */ ((Emoji2) => {
2267
+ Emoji2["USER_PORTRAIT"] = "\u{1F464}";
2268
+ Emoji2["WARNING_SIGN"] = "\u26A0\uFE0F";
2269
+ Emoji2["BAR_CHART"] = "\u{1F4CA}";
2270
+ Emoji2["FOLDER"] = "\u{1F5C2}\uFE0F";
2271
+ Emoji2["FILE"] = "\u{1F4C4}";
2272
+ Emoji2["HOUSE"] = "\u{1F3E0}";
2273
+ Emoji2["NONE"] = "\u{1F6AB}";
2274
+ Emoji2["WHITE_SQUARE"] = "\u2B1C";
2275
+ Emoji2["GRID_GLOBE"] = "\u{1F310}";
2276
+ Emoji2["SATELLITE_DISH"] = "\u{1F4E1}";
2277
+ Emoji2["COMPLETED_CHECKMARK"] = "\u2705";
2278
+ Emoji2["RED_X"] = "\u274C";
2279
+ Emoji2["CLOCK"] = "\u{1F552}";
2280
+ Emoji2["SUNSHINE"] = "\u{1F506}";
2281
+ Emoji2["ALARM_CLOCK"] = "\u23F0";
2282
+ Emoji2["MAGNIFYING_GLASS"] = "\u{1F50E}";
2283
+ Emoji2["MAGIC_WAND"] = "\u{1FA84}";
2284
+ Emoji2["CALENDAR"] = "\u{1F4C5}";
2285
+ Emoji2["LOCKED"] = "\u{1F512}";
2286
+ Emoji2["UNLOCKED"] = "\u{1F513}";
2287
+ Emoji2["NORTHWEST_ARROW"] = "\u2196\uFE0F";
2288
+ Emoji2["RIGHT_ARROW"] = "\u27A1\uFE0F";
2289
+ Emoji2["LEFT_ARROW"] = "\u2B05\uFE0F";
2290
+ Emoji2["UP_ARROW"] = "\u2B06\uFE0F";
2291
+ Emoji2["UP_DOWN_ARROW"] = "\u2195\uFE0F";
2292
+ Emoji2["LEFT_ARROW_UNICODE"] = "\u25C4";
2293
+ Emoji2["UP_ARROW_UNICODE"] = "\u25B2";
2294
+ Emoji2["RIGHT_ARROW_UNICODE"] = "\u25BA";
2295
+ Emoji2["DOWN_ARROW_UNICODE"] = "\u25BC";
2296
+ Emoji2["BRICK"] = "\u{1F9F1}";
2297
+ Emoji2["RULER"] = "\u{1F4D0}";
2298
+ Emoji2["SWORD"] = "\u{1F5E1}\uFE0F";
2299
+ Emoji2["PEACE_SIGN"] = "\u270C\uFE0F";
2300
+ Emoji2["SIGN"] = "\u{1FAA7}";
2301
+ Emoji2["CONSTRUCTION"] = "\u{1F3D7}\uFE0F";
2302
+ Emoji2["CAMERA"] = "\u{1F4F7}";
2303
+ Emoji2["MOVIE_CAMERA"] = "\u{1F3A5}";
2304
+ Emoji2["PAINTING"] = "\u{1F5BC}\uFE0F";
2305
+ Emoji2["PALETTE"] = "\u{1F3A8}";
2306
+ Emoji2["MICROPHONE"] = "\u{1F399}\uFE0F";
2307
+ Emoji2["NOTEPAD"] = "\u{1F4DD}";
2308
+ Emoji2["GEAR"] = "\u2699\uFE0F";
2309
+ Emoji2["REPEAT"] = "\u{1F501}";
2310
+ Emoji2["SNOWMAN"] = "\u2603\uFE0F";
2311
+ Emoji2["SNOWFLAKE"] = "\u2744\uFE0F";
2312
+ Emoji2["SNOW_CLOUD"] = "\u{1F328}\uFE0F";
2313
+ Emoji2["SCARF"] = "\u{1F9E3}";
2314
+ Emoji2["GLOVES"] = "\u{1F9E4}";
2315
+ Emoji2["CANDLE"] = "\u{1F56F}\uFE0F";
2316
+ Emoji2["CHRISTMAS_TREE"] = "\u{1F384}";
2317
+ Emoji2["SOCKS"] = "\u{1F9E6}";
2318
+ Emoji2["COLD_FACE"] = "\u{1F976}";
2319
+ Emoji2["EYE"] = "\u{1F441}\uFE0F";
2320
+ Emoji2["CHAINS"] = "\u26D3\uFE0F";
2321
+ Emoji2["SPEAKER"] = "\u{1F50A}";
2322
+ Emoji2["COMPACT_DISK"] = "\u{1F4BF}";
2323
+ Emoji2["SEEDLING"] = "\u{1F331}";
2324
+ Emoji2["TULIP"] = "\u{1F337}";
2325
+ Emoji2["BEE"] = "\u{1F41D}";
2326
+ Emoji2["HATCHING_CHICK"] = "\u{1F423}";
2327
+ Emoji2["NEST_WITH_EGGS"] = "\u{1FABA}";
2328
+ Emoji2["BLOSSOM"] = "\u{1F33C}";
2329
+ Emoji2["UMBRELLA"] = "\u2614";
2330
+ Emoji2["RAINBOW"] = "\u{1F308}";
2331
+ Emoji2["PICNIC_BASKET"] = "\u{1F9FA}";
2332
+ Emoji2["SUN_WITH_FACE"] = "\u{1F31E}";
2333
+ Emoji2["BEACH_UMBRELLA"] = "\u{1F3D6}\uFE0F";
2334
+ Emoji2["WATERMELON"] = "\u{1F349}";
2335
+ Emoji2["SUNGLASSES"] = "\u{1F576}\uFE0F";
2336
+ Emoji2["ICE_CREAM"] = "\u{1F366}";
2337
+ Emoji2["SUNFLOWER"] = "\u{1F33B}";
2338
+ Emoji2["CAMPING"] = "\u{1F3D5}\uFE0F";
2339
+ Emoji2["JUICE_BOX"] = "\u{1F9C3}";
2340
+ Emoji2["PARASOL"] = "\u26F1\uFE0F";
2341
+ Emoji2["MAPLE_LEAF"] = "\u{1F341}";
2342
+ Emoji2["FALLEN_LEAF"] = "\u{1F342}";
2343
+ Emoji2["TURKEY"] = "\u{1F983}";
2344
+ Emoji2["JACK_O_LANTERN"] = "\u{1F383}";
2345
+ Emoji2["PIE"] = "\u{1F967}";
2346
+ Emoji2["LOG"] = "\u{1FAB5}";
2347
+ Emoji2["SPIDER_WEB"] = "\u{1F578}\uFE0F";
2348
+ Emoji2["BACKPACK"] = "\u{1F392}";
2349
+ Emoji2["CHESTNUT"] = "\u{1F330}";
2350
+ Emoji2["PLACARD"] = "\u{1FAA7}";
2351
+ Emoji2["RECEIPT"] = "\u{1F9FE}";
2352
+ Emoji2["DOCUMENT"] = "\u{1F4C4}";
2353
+ Emoji2["SPARKLES"] = "\u2728";
2354
+ Emoji2["BOOKS"] = "\u{1F4DA}";
2355
+ Emoji2["SHOPPING_BAGS"] = "\u{1F6CD}\uFE0F";
2356
+ Emoji2["LINK"] = "\u{1F517}";
2357
+ Emoji2["GREEN_ASTERISK"] = "\u2733\uFE0F";
2358
+ Emoji2["RADIO_BUTTON"] = "\u{1F518}";
2359
+ Emoji2["WINDOW"] = "\u{1FA9F}";
2360
+ Emoji2["MUSIC_NOTES"] = "\u{1F3B6}";
2361
+ Emoji2["INVISIBLE_FACE"] = "\u{1FAE5}";
2362
+ Emoji2["PLUS_SIGN"] = "\u2795";
2363
+ Emoji2["JOKER"] = "\u{1F0CF}";
2364
+ Emoji2["PLAY"] = "\u25B6\uFE0F";
2365
+ Emoji2["PAUSE"] = "\u23F8\uFE0F";
2366
+ return Emoji2;
2367
+ })(Emoji || {});
2368
+ var emoji_default = Emoji;
2369
+
2370
+ // src/client/utility/get-index-path-for-element.ts
2371
+ var import_errors7 = __toESM(require_src2());
2372
+ function getIndexPathForElement(element) {
2373
+ const value = element.getAttribute("data-index-path");
2374
+ if (value === null) {
2375
+ throw new import_errors7.InvariantViolation(
2376
+ "Tried to read data-index-path for element, but it was not set"
2377
+ );
2378
+ }
2379
+ return value;
2380
+ }
2381
+ var get_index_path_for_element_default = getIndexPathForElement;
2382
+
2383
+ // src/client/helper/interaction.ts
2384
+ var InteractionHelper = class {
2385
+ constructor() {
2386
+ this.drag_active = false;
2387
+ this.drag_origin_block = null;
2388
+ this.drag_placeholder = null;
2389
+ this.drag_ghost = null;
2390
+ this.drag_start_y = null;
2391
+ this.drag_pointer_offset_y = null;
2392
+ this.drag_press_timer = null;
2393
+ this.swipe_active = false;
2394
+ this.swipe_block = null;
2395
+ this.swipe_start_x = null;
2396
+ this.swipe_start_y = null;
2397
+ this.swipe_content = null;
2398
+ this.swipe_menu_width = 0;
2399
+ this.open_swipe_block = null;
2400
+ this.open_swipe_content = null;
2401
+ }
2402
+ attach() {
2403
+ document.addEventListener("mousedown", (event) => {
2404
+ this.onPressStart(event);
2405
+ }, true);
2406
+ document.addEventListener("touchstart", (event) => {
2407
+ this.onPressStart(event);
2408
+ }, { capture: true, passive: false });
2409
+ document.addEventListener("mousemove", (event) => {
2410
+ this.onPointerMove(event);
2411
+ }, true);
2412
+ document.addEventListener("touchmove", (event) => {
2413
+ this.onPointerMove(event);
2414
+ }, { capture: true, passive: false });
2415
+ document.addEventListener("mouseup", (event) => {
2416
+ this.onPressEnd(event);
2417
+ }, true);
2418
+ document.addEventListener("touchend", (event) => {
2419
+ this.onPressEnd(event);
2420
+ }, true);
2421
+ document.addEventListener("touchstart", (event) => {
2422
+ this.onGlobalTouchStart(event);
2423
+ }, { capture: true, passive: true });
2424
+ document.addEventListener("dragstart", (event) => {
2425
+ this.onNativeDragStart(event);
2426
+ }, true);
2427
+ }
2428
+ isDragging() {
2429
+ return this.drag_active;
2430
+ }
2431
+ getBlockElements() {
2432
+ const elements = document.querySelectorAll("section.block");
2433
+ return Array.from(elements);
2434
+ }
2435
+ getSiblingBlocks(container, exclude) {
2436
+ const children = Array.from(container.children);
2437
+ return children.filter((element) => {
2438
+ if (element === exclude) {
2439
+ return false;
2440
+ }
2441
+ return element.classList.contains("block");
2442
+ });
2443
+ }
2444
+ onPressStart(event) {
2445
+ const target = event.target;
2446
+ if (target === null) {
2447
+ return;
2448
+ }
2449
+ if (target.closest("button, input, textarea, select, label, form")) {
2450
+ return;
2451
+ }
2452
+ const block = target.closest("section.block");
2453
+ if (block === null) {
2454
+ return;
2455
+ }
2456
+ if (event instanceof MouseEvent) {
2457
+ const anchor = target.closest("a[href]");
2458
+ if (anchor) {
2459
+ event.preventDefault();
2460
+ }
2461
+ }
2462
+ const touch_event = event;
2463
+ const is_touch = touch_event.type === "touchstart";
2464
+ const point = this.getEventPoint(event);
2465
+ if (point === null) {
2466
+ return;
2467
+ }
2468
+ this.drag_origin_block = block;
2469
+ this.drag_start_y = point.clientY;
2470
+ if (is_touch) {
2471
+ this.swipe_block = block;
2472
+ this.swipe_start_x = point.clientX;
2473
+ this.swipe_start_y = point.clientY;
2474
+ }
2475
+ const threshold_ms = is_touch ? 350 : 200;
2476
+ this.clearPressTimer();
2477
+ this.drag_press_timer = window.setTimeout(() => {
2478
+ this.beginDrag(point.clientY);
2479
+ }, threshold_ms);
2480
+ }
2481
+ onNativeDragStart(event) {
2482
+ const target = event.target;
2483
+ if (!target) {
2484
+ return;
2485
+ }
2486
+ if (target.closest("section.block")) {
2487
+ event.preventDefault();
2488
+ }
2489
+ }
2490
+ onPointerMove(event) {
2491
+ const point = this.getEventPoint(event);
2492
+ if (point === null) {
2493
+ return;
2494
+ }
2495
+ const touch_event = event;
2496
+ const { touches } = touch_event;
2497
+ const is_touch = touches !== void 0;
2498
+ if (is_touch && this.swipe_block) {
2499
+ if (this.swipe_start_x === null || this.swipe_start_y === null) {
2500
+ throw new import_errors8.InvariantViolation("Swipe start coordinates were not initialized");
2501
+ }
2502
+ const start_x = this.swipe_start_x;
2503
+ const start_y = this.swipe_start_y;
2504
+ const delta_x = point.clientX - start_x;
2505
+ const delta_y = point.clientY - start_y;
2506
+ if (!this.swipe_active) {
2507
+ const abs_x = Math.abs(delta_x);
2508
+ const abs_y = Math.abs(delta_y);
2509
+ if (abs_x > 12 && abs_x > abs_y) {
2510
+ this.clearPressTimer();
2511
+ this.closeOpenSwipeMenu(this.swipe_block);
2512
+ this.swipe_active = true;
2513
+ this.beginSwipe(this.swipe_block);
2514
+ }
2515
+ }
2516
+ if (this.swipe_active) {
2517
+ event.preventDefault();
2518
+ const content_element = this.swipe_content;
2519
+ const menu_width = this.swipe_menu_width;
2520
+ const translate_x = Math.max(-menu_width, Math.min(0, delta_x));
2521
+ content_element.style.transition = "";
2522
+ content_element.style.transform = `translateX(${translate_x}px)`;
2523
+ return;
2524
+ }
2525
+ }
2526
+ if (!this.drag_active && this.drag_origin_block && this.drag_start_y !== null) {
2527
+ const delta_y = Math.abs(point.clientY - this.drag_start_y);
2528
+ if (delta_y > 8 && this.drag_press_timer !== null) {
2529
+ this.beginDrag(point.clientY);
2530
+ }
2531
+ }
2532
+ if (!this.drag_active) {
2533
+ return;
2534
+ }
2535
+ event.preventDefault();
2536
+ const origin = this.drag_origin_block;
2537
+ let container = null;
2538
+ if (this.drag_placeholder !== null) {
2539
+ container = this.drag_placeholder.parentElement;
2540
+ }
2541
+ if (container === null && origin !== null) {
2542
+ container = origin.parentElement;
2543
+ }
2544
+ if (container === null) {
2545
+ return;
2546
+ }
2547
+ const blocks_before = this.getSiblingBlocks(container, origin);
2548
+ const preceding_rects = /* @__PURE__ */ new Map();
2549
+ blocks_before.forEach((element) => {
2550
+ const rect = element.getBoundingClientRect();
2551
+ preceding_rects.set(element, rect);
2552
+ });
2553
+ this.updatePlaceholderPosition(point.clientY);
2554
+ if (this.drag_ghost && this.drag_pointer_offset_y !== null) {
2555
+ const top_position = point.clientY - this.drag_pointer_offset_y;
2556
+ this.drag_ghost.style.top = `${top_position}px`;
2557
+ }
2558
+ const blocks_after = this.getSiblingBlocks(container, origin);
2559
+ this.animateWithFlip(preceding_rects, blocks_after);
2560
+ }
2561
+ onPressEnd(event) {
2562
+ this.clearPressTimer();
2563
+ if (this.swipe_active) {
2564
+ const content = this.swipe_content;
2565
+ const style = window.getComputedStyle(content);
2566
+ let current_x = 0;
2567
+ try {
2568
+ const css_matrix = new WebKitCSSMatrix(style.transform);
2569
+ current_x = css_matrix.m41;
2570
+ } catch {
2571
+ const translate_match = style.transform.match(/translateX\(([-0-9.]+)px\)/);
2572
+ if (translate_match) {
2573
+ current_x = parseFloat(translate_match[1]);
2574
+ }
2575
+ }
2576
+ const width = this.swipe_menu_width;
2577
+ const open = Math.abs(current_x) > width / 2;
2578
+ content.style.transition = "transform 150ms ease";
2579
+ content.style.transform = open ? `translateX(${-width}px)` : "translateX(0)";
2580
+ if (!open) {
2581
+ this.teardownSwipe();
2582
+ }
2583
+ if (open) {
2584
+ this.open_swipe_block = this.swipe_block;
2585
+ this.open_swipe_content = content;
2586
+ }
2587
+ this.swipe_active = false;
2588
+ return;
2589
+ }
2590
+ if (!this.drag_active) {
2591
+ this.resetDragState();
2592
+ return;
2593
+ }
2594
+ event.preventDefault();
2595
+ const origin = this.drag_origin_block;
2596
+ const placeholder = this.drag_placeholder;
2597
+ const source_index_path = get_index_path_for_element_default(origin);
2598
+ const target_index_path = this.computeTargetIndexPath(placeholder);
2599
+ this.cleanupDragElements();
2600
+ if (target_index_path === null || target_index_path === source_index_path) {
2601
+ this.resetDragState();
2602
+ return;
2603
+ }
2604
+ const editing = new URL(window.location.href).searchParams.get("editing") === "true";
2605
+ this.postReposition(source_index_path, target_index_path, editing).then((new_index_path) => {
2606
+ if (new_index_path) {
2607
+ const url = new URL(window.location.href);
2608
+ url.searchParams.set("index_path", new_index_path);
2609
+ history.replaceState({}, "", url.toString());
2610
+ }
2611
+ const blocks = this.getBlockElements();
2612
+ blocks.forEach((element) => {
2613
+ element.classList.remove("selected");
2614
+ });
2615
+ origin.classList.add("selected");
2616
+ this.updateTopLevelIndexPaths();
2617
+ }).finally(() => {
2618
+ this.resetDragState();
2619
+ });
2620
+ }
2621
+ beginSwipe(block) {
2622
+ const result = this.ensureSwipeUI(block);
2623
+ const target = result.target;
2624
+ const menu = result.menu;
2625
+ const menu_width = result.menu_width;
2626
+ this.swipe_content = target;
2627
+ this.swipe_menu_width = menu_width;
2628
+ if (menu) {
2629
+ menu.style.display = "flex";
2630
+ menu.style.opacity = "1";
2631
+ }
2632
+ }
2633
+ closeOpenSwipeMenu(except) {
2634
+ if (!this.open_swipe_content) {
2635
+ return;
2636
+ }
2637
+ if (except && this.open_swipe_block === except) {
2638
+ return;
2639
+ }
2640
+ const content = this.open_swipe_content;
2641
+ content.style.transition = "transform 150ms ease";
2642
+ content.style.transform = "translateX(0)";
2643
+ const clear_callback = () => {
2644
+ content.removeEventListener("transitionend", clear_callback);
2645
+ if (this.open_swipe_block) {
2646
+ const menu_element = this.getSwipeMenuFor(this.open_swipe_block);
2647
+ if (menu_element && menu_element.parentElement) {
2648
+ menu_element.parentElement.removeChild(menu_element);
2649
+ }
2650
+ }
2651
+ this.open_swipe_block = null;
2652
+ this.open_swipe_content = null;
2653
+ };
2654
+ content.addEventListener("transitionend", clear_callback);
2655
+ }
2656
+ teardownSwipe() {
2657
+ if (!this.swipe_block || !this.swipe_content) {
2658
+ this.resetSwipeState();
2659
+ return;
2660
+ }
2661
+ this.swipe_content.style.transition = "";
2662
+ this.swipe_content.style.transform = "translateX(0)";
2663
+ const menu = this.getSwipeMenuFor(this.swipe_block);
2664
+ if (menu && menu.parentElement) {
2665
+ menu.parentElement.removeChild(menu);
2666
+ }
2667
+ this.resetSwipeState();
2668
+ }
2669
+ onGlobalTouchStart(event) {
2670
+ if (!this.open_swipe_block || !this.open_swipe_content) {
2671
+ return;
2672
+ }
2673
+ const target = event.target;
2674
+ if (!target) {
2675
+ return;
2676
+ }
2677
+ const menu = this.getSwipeMenuFor(this.open_swipe_block);
2678
+ const closest_block = target.closest("section.block");
2679
+ const swipe_actions = target.closest(".swipe-actions");
2680
+ if (closest_block === this.open_swipe_block || swipe_actions === menu) {
2681
+ return;
2682
+ }
2683
+ this.closeOpenSwipeMenu();
2684
+ }
2685
+ getSwipeMenuFor(block) {
2686
+ const wrapper = block.closest("main .section-wrapper");
2687
+ if (!wrapper || !block.id) {
2688
+ return null;
2689
+ }
2690
+ return wrapper.querySelector(`.swipe-actions[data-for="${block.id}"]`);
2691
+ }
2692
+ resetSwipeState() {
2693
+ this.swipe_block = null;
2694
+ this.swipe_start_x = null;
2695
+ this.swipe_start_y = null;
2696
+ this.swipe_content = null;
2697
+ this.swipe_menu_width = 0;
2698
+ }
2699
+ ensureSwipeUI(block) {
2700
+ const target = block;
2701
+ target.style.willChange = "transform";
2702
+ target.style.transform = "translateX(0)";
2703
+ target.style.transition = "";
2704
+ target.style.position = target.style.position || "relative";
2705
+ target.style.zIndex = "1";
2706
+ const wrapper = block.closest("main .section-wrapper");
2707
+ let menu = null;
2708
+ if (wrapper) {
2709
+ if (getComputedStyle(wrapper).position === "static") {
2710
+ wrapper.style.position = "relative";
2711
+ }
2712
+ let existing = wrapper.querySelector(`.swipe-actions[data-for="${block.id}"]`);
2713
+ if (!existing) {
2714
+ existing = document.createElement("div");
2715
+ existing.className = "swipe-actions";
2716
+ existing.setAttribute("data-for", block.id);
2717
+ existing.style.position = "absolute";
2718
+ existing.style.right = "0";
2719
+ existing.style.display = "none";
2720
+ existing.style.opacity = "0";
2721
+ existing.style.gap = "8px";
2722
+ existing.style.alignItems = "stretch";
2723
+ existing.style.padding = "0 8px";
2724
+ existing.style.background = "transparent";
2725
+ existing.style.zIndex = "0";
2726
+ const edit_button = document.createElement("button");
2727
+ const delete_button = document.createElement("button");
2728
+ const add_button = document.createElement("button");
2729
+ edit_button.textContent = emoji_default.GEAR;
2730
+ edit_button.setAttribute("aria-label", "Edit");
2731
+ edit_button.style.background = "#f0ad4e";
2732
+ edit_button.style.color = "#000";
2733
+ edit_button.style.border = "none";
2734
+ edit_button.style.padding = "0";
2735
+ edit_button.style.fontSize = "20px";
2736
+ edit_button.style.width = "48px";
2737
+ edit_button.style.minWidth = "48px";
2738
+ edit_button.style.display = "flex";
2739
+ edit_button.style.alignItems = "center";
2740
+ edit_button.style.justifyContent = "center";
2741
+ edit_button.style.cursor = "pointer";
2742
+ delete_button.textContent = emoji_default.RED_X;
2743
+ delete_button.setAttribute("aria-label", "Delete");
2744
+ delete_button.style.background = "#e74c3c";
2745
+ delete_button.style.color = "#fff";
2746
+ delete_button.style.border = "none";
2747
+ delete_button.style.padding = "0";
2748
+ delete_button.style.fontSize = "20px";
2749
+ delete_button.style.width = "48px";
2750
+ delete_button.style.minWidth = "48px";
2751
+ delete_button.style.display = "flex";
2752
+ delete_button.style.alignItems = "center";
2753
+ delete_button.style.justifyContent = "center";
2754
+ delete_button.style.cursor = "pointer";
2755
+ add_button.textContent = emoji_default.PLUS_SIGN;
2756
+ add_button.setAttribute("aria-label", "Add After");
2757
+ add_button.style.background = "#27ae60";
2758
+ add_button.style.color = "#fff";
2759
+ add_button.style.border = "none";
2760
+ add_button.style.padding = "0";
2761
+ add_button.style.fontSize = "20px";
2762
+ add_button.style.width = "48px";
2763
+ add_button.style.minWidth = "48px";
2764
+ add_button.style.display = "flex";
2765
+ add_button.style.alignItems = "center";
2766
+ add_button.style.justifyContent = "center";
2767
+ add_button.style.cursor = "pointer";
2768
+ existing.appendChild(edit_button);
2769
+ existing.appendChild(delete_button);
2770
+ existing.appendChild(add_button);
2771
+ wrapper.appendChild(existing);
2772
+ const edit_handler = (event) => {
2773
+ event.preventDefault();
2774
+ event.stopPropagation();
2775
+ this.navigateToBlockLink(block, "edit");
2776
+ };
2777
+ const delete_handler = (event) => {
2778
+ event.preventDefault();
2779
+ event.stopPropagation();
2780
+ this.navigateToBlockLink(block, "delete");
2781
+ };
2782
+ const add_handler = (event) => {
2783
+ event.preventDefault();
2784
+ event.stopPropagation();
2785
+ this.navigateToAddAfter(block);
2786
+ };
2787
+ existing.addEventListener("touchstart", (event) => {
2788
+ event.stopPropagation();
2789
+ });
2790
+ existing.addEventListener("mousedown", (event) => {
2791
+ event.stopPropagation();
2792
+ });
2793
+ edit_button.addEventListener("click", edit_handler);
2794
+ edit_button.addEventListener("touchend", edit_handler);
2795
+ delete_button.addEventListener("click", delete_handler);
2796
+ delete_button.addEventListener("touchend", delete_handler);
2797
+ add_button.addEventListener("click", add_handler);
2798
+ add_button.addEventListener("touchend", add_handler);
2799
+ }
2800
+ menu = existing;
2801
+ const top = block.offsetTop;
2802
+ const height = block.offsetHeight;
2803
+ menu.style.top = `${top}px`;
2804
+ menu.style.height = `${height}px`;
2805
+ }
2806
+ let menu_width = 160;
2807
+ if (menu) {
2808
+ const prevDisplay = menu.style.display;
2809
+ const prevOpacity = menu.style.opacity;
2810
+ menu.style.display = "flex";
2811
+ menu.style.opacity = "0";
2812
+ menu_width = menu.offsetWidth || 160;
2813
+ menu.style.display = prevDisplay;
2814
+ menu.style.opacity = prevOpacity;
2815
+ }
2816
+ this.enforceTimeVisibility(block);
2817
+ return {
2818
+ target,
2819
+ menu,
2820
+ menu_width
2821
+ };
2822
+ }
2823
+ navigateToAddAfter(block) {
2824
+ const current = get_index_path_for_element_default(block);
2825
+ const parts = current.split(".").map((part) => {
2826
+ return parseInt(part, 10);
2827
+ });
2828
+ const has_invalid_number = parts.some((value) => {
2829
+ return isNaN(value);
2830
+ });
2831
+ if (parts.length === 0 || has_invalid_number) {
2832
+ throw new import_errors8.InvariantViolation("Invalid index_path for Add After");
2833
+ }
2834
+ const last = parts.pop();
2835
+ if (last === void 0) {
2836
+ throw new import_errors8.InvariantViolation("Unable to compute next index for Add After");
2837
+ }
2838
+ parts.push(last + 1);
2839
+ const index_path = parts.join(".");
2840
+ const url = new URL(window.location.href);
2841
+ const editing = url.searchParams.get("editing") === "true";
2842
+ const path = window.location.pathname;
2843
+ const actionUrl = new URL("/actions", window.location.origin);
2844
+ actionUrl.searchParams.set("path", path);
2845
+ actionUrl.searchParams.set("editing", String(editing));
2846
+ actionUrl.searchParams.set("action_type", "add_block");
2847
+ actionUrl.searchParams.set("index_path", index_path);
2848
+ window.location.href = actionUrl.toString();
2849
+ }
2850
+ enforceTimeVisibility(block) {
2851
+ const shows_time = block.classList.contains("with-time");
2852
+ const time_element = block.querySelector(":scope time");
2853
+ if (!time_element) {
2854
+ return;
2855
+ }
2856
+ if (!shows_time) {
2857
+ time_element.style.display = "none";
2858
+ } else {
2859
+ time_element.style.display = "";
2860
+ }
2861
+ }
2862
+ navigateToBlockLink(block, type) {
2863
+ const block_id = block.id;
2864
+ const link_id = `${block_id}-${type}`;
2865
+ const link_element = document.getElementById(link_id);
2866
+ if (!link_element) {
2867
+ return;
1396
2868
  }
1397
- const href = element.getAttribute("href");
1398
- if (href === null) {
1399
- throw new import_errors4.InvariantViolation(`
1400
- Tried to create block of type ${block_type},
1401
- but the creation href was not present on the link element
1402
- `);
2869
+ const href = link_element.getAttribute("href");
2870
+ if (href) {
2871
+ window.location.href = href;
1403
2872
  }
1404
- window.location.href = href;
1405
2873
  }
1406
- };
1407
- var select_block_type_default = SelectBlockTypePage;
1408
-
1409
- // src/client/page/cursor.ts
1410
- var import_errors7 = __toESM(require_src2());
1411
- var import_array2 = __toESM(require_src3());
1412
-
1413
- // src/client/utility/get-meta-value.ts
1414
- var import_errors5 = __toESM(require_src2());
1415
- function getMetaValue(name) {
1416
- const element = document.querySelector(`meta[name="${name}"]`);
1417
- if (element === null) {
1418
- throw new import_errors5.InvariantViolation(`
1419
- Tried to read ${name} meta tag, but it was not set
1420
- `);
2874
+ beginDrag(current_y) {
2875
+ if (this.drag_active) {
2876
+ return;
2877
+ }
2878
+ const block = this.drag_origin_block;
2879
+ if (!block) {
2880
+ return;
2881
+ }
2882
+ this.drag_active = true;
2883
+ document.body.style.userSelect = "none";
2884
+ document.body.style.cursor = "grabbing";
2885
+ const rect = block.getBoundingClientRect();
2886
+ const ghost = block.cloneNode(true);
2887
+ ghost.style.position = "fixed";
2888
+ ghost.style.top = `${rect.top}px`;
2889
+ ghost.style.left = `${rect.left}px`;
2890
+ ghost.style.width = `${rect.width}px`;
2891
+ ghost.style.pointerEvents = "none";
2892
+ ghost.style.opacity = "0.9";
2893
+ ghost.style.boxShadow = "0 8px 16px rgba(0,0,0,0.2)";
2894
+ ghost.style.zIndex = "9999";
2895
+ document.body.appendChild(ghost);
2896
+ this.drag_ghost = ghost;
2897
+ this.drag_pointer_offset_y = current_y - rect.top;
2898
+ const placeholder = document.createElement("div");
2899
+ placeholder.style.height = `${rect.height}px`;
2900
+ placeholder.style.margin = getComputedStyle(block).margin;
2901
+ placeholder.style.border = "2px dashed #888";
2902
+ placeholder.style.borderRadius = "4px";
2903
+ placeholder.style.boxSizing = "border-box";
2904
+ if (block.parentElement !== null) {
2905
+ block.parentElement.insertBefore(placeholder, block);
2906
+ }
2907
+ this.drag_placeholder = placeholder;
2908
+ block.style.display = "none";
2909
+ this.updatePlaceholderPosition(current_y);
2910
+ }
2911
+ updatePlaceholderPosition(cursor_y) {
2912
+ const placeholder = this.drag_placeholder;
2913
+ const origin = this.drag_origin_block;
2914
+ if (!placeholder || !origin) {
2915
+ return;
2916
+ }
2917
+ const container = placeholder.parentElement;
2918
+ const blocks = this.getSiblingBlocks(container, origin);
2919
+ let inserted = false;
2920
+ for (let i = 0; i < blocks.length; i++) {
2921
+ const element = blocks[i];
2922
+ const rect = element.getBoundingClientRect();
2923
+ const midpoint = rect.top + rect.height / 2;
2924
+ if (cursor_y < midpoint) {
2925
+ const parent = element.parentElement;
2926
+ if (parent) {
2927
+ parent.insertBefore(placeholder, element);
2928
+ }
2929
+ inserted = true;
2930
+ break;
2931
+ }
2932
+ }
2933
+ if (!inserted) {
2934
+ const last_element = blocks[blocks.length - 1];
2935
+ if (last_element) {
2936
+ const parent = last_element.parentElement;
2937
+ if (parent) {
2938
+ parent.appendChild(placeholder);
2939
+ }
2940
+ }
2941
+ }
1421
2942
  }
1422
- if (!(element instanceof HTMLMetaElement)) {
1423
- throw new import_errors5.InvariantViolation(`
1424
- Got wrong element for ${name} meta tag: ${element.tagName}
1425
- `);
2943
+ animateWithFlip(preceding_rects, blocks_after) {
2944
+ blocks_after.forEach((element) => {
2945
+ const first = preceding_rects.get(element);
2946
+ if (!first) {
2947
+ return;
2948
+ }
2949
+ const last_rect = element.getBoundingClientRect();
2950
+ const delta_y = first.top - last_rect.top;
2951
+ if (delta_y === 0) {
2952
+ return;
2953
+ }
2954
+ element.style.transition = "";
2955
+ element.style.transform = `translateY(${delta_y}px)`;
2956
+ void element.getBoundingClientRect();
2957
+ element.style.transition = "transform 120ms ease";
2958
+ element.style.transform = "translateY(0)";
2959
+ const cleanup = () => {
2960
+ element.style.transition = "";
2961
+ element.style.transform = "";
2962
+ element.removeEventListener("transitionend", cleanup);
2963
+ };
2964
+ element.addEventListener("transitionend", cleanup);
2965
+ });
1426
2966
  }
1427
- const meta_tag = element;
1428
- return meta_tag.content;
1429
- }
1430
- var get_meta_value_default = getMetaValue;
1431
-
1432
- // src/server/utility/validate-path.ts
1433
- var import_errors6 = __toESM(require_src2());
1434
- function validatePath(path) {
1435
- if (!path.startsWith("/")) {
1436
- throw new import_errors6.InvalidError(`Invalid path: ${path}`);
2967
+ async postReposition(source_index_path, target_index_path, editing) {
2968
+ const form = new FormData();
2969
+ form.set("path", window.location.pathname);
2970
+ form.set("action_type", action_type_default.REPOSITION_BLOCK);
2971
+ form.set("source_index_path", source_index_path);
2972
+ form.set("target_index_path", target_index_path);
2973
+ const response = await fetch(`/actions?editing=${editing}`, {
2974
+ method: "POST",
2975
+ body: form,
2976
+ credentials: "same-origin",
2977
+ redirect: "follow"
2978
+ });
2979
+ try {
2980
+ const url_object = new URL(response.url, window.location.origin);
2981
+ return url_object.searchParams.get("index_path");
2982
+ } catch (_) {
2983
+ return null;
2984
+ }
1437
2985
  }
1438
- }
1439
- var validate_path_default = validatePath;
1440
-
1441
- // src/common/utility/get-parent-path.ts
1442
- function getParentPath(source_path) {
1443
- validate_path_default(source_path);
1444
- const query_index = source_path.indexOf("?");
1445
- if (query_index !== -1) {
1446
- source_path = source_path.slice(0, query_index);
2986
+ computeTargetIndexPath(placeholder) {
2987
+ if (!placeholder) {
2988
+ return null;
2989
+ }
2990
+ const parent = placeholder.parentElement;
2991
+ if (!parent) {
2992
+ return null;
2993
+ }
2994
+ let index = 0;
2995
+ const children_elements = Array.from(parent.children);
2996
+ for (let i = 0; i < children_elements.length; i++) {
2997
+ const child_element = children_elements[i];
2998
+ if (child_element === placeholder) {
2999
+ break;
3000
+ }
3001
+ if (child_element.classList.contains("block")) {
3002
+ index += 1;
3003
+ }
3004
+ }
3005
+ return index.toString();
1447
3006
  }
1448
- if (source_path.endsWith("/")) {
1449
- source_path = source_path.slice(0, -1);
3007
+ updateTopLevelIndexPaths() {
3008
+ const wrapper = document.querySelector("main .section-wrapper");
3009
+ let blocks;
3010
+ if (wrapper) {
3011
+ const node_list = wrapper.querySelectorAll(":scope > section.block");
3012
+ blocks = Array.from(node_list);
3013
+ } else {
3014
+ const node_list = document.querySelectorAll("main > section.block");
3015
+ blocks = Array.from(node_list);
3016
+ }
3017
+ for (let i = 0; i < blocks.length; i++) {
3018
+ blocks[i].setAttribute("data-index-path", i.toString());
3019
+ }
1450
3020
  }
1451
- const parts = source_path.split("/").filter((part) => {
1452
- return part !== "";
1453
- });
1454
- parts.pop();
1455
- if (parts.length === 0) {
1456
- return "/";
3021
+ cleanupDragElements() {
3022
+ if (this.drag_ghost && this.drag_ghost.parentElement) {
3023
+ this.drag_ghost.parentElement.removeChild(this.drag_ghost);
3024
+ }
3025
+ if (this.drag_placeholder && this.drag_placeholder.parentElement) {
3026
+ if (this.drag_origin_block) {
3027
+ this.drag_placeholder.parentElement.insertBefore(this.drag_origin_block, this.drag_placeholder);
3028
+ }
3029
+ this.drag_placeholder.parentElement.removeChild(this.drag_placeholder);
3030
+ }
3031
+ if (this.drag_origin_block) {
3032
+ this.drag_origin_block.style.display = "";
3033
+ }
3034
+ this.drag_ghost = null;
3035
+ this.drag_placeholder = null;
3036
+ document.body.style.userSelect = "";
3037
+ document.body.style.cursor = "";
3038
+ }
3039
+ resetDragState() {
3040
+ this.cleanupDragElements();
3041
+ this.drag_active = false;
3042
+ this.drag_origin_block = null;
3043
+ this.drag_start_y = null;
3044
+ this.drag_pointer_offset_y = null;
3045
+ }
3046
+ clearPressTimer() {
3047
+ if (this.drag_press_timer !== null) {
3048
+ window.clearTimeout(this.drag_press_timer);
3049
+ this.drag_press_timer = null;
3050
+ }
3051
+ }
3052
+ getEventPoint(event) {
3053
+ const touch_event = event;
3054
+ const has_touches = touch_event.touches !== void 0;
3055
+ if (has_touches) {
3056
+ const primary_touch = touch_event.touches[0] || touch_event.changedTouches[0];
3057
+ if (!primary_touch) {
3058
+ return null;
3059
+ }
3060
+ return {
3061
+ clientX: primary_touch.clientX,
3062
+ clientY: primary_touch.clientY
3063
+ };
3064
+ }
3065
+ const mouse_event = event;
3066
+ return {
3067
+ clientX: mouse_event.clientX,
3068
+ clientY: mouse_event.clientY
3069
+ };
1457
3070
  }
1458
- return "/" + parts.join("/");
1459
- }
1460
- var get_parent_path_default = getParentPath;
1461
-
1462
- // src/client/enum/media-ready-state.ts
1463
- var MediaReadyState = /* @__PURE__ */ ((MediaReadyState2) => {
1464
- MediaReadyState2[MediaReadyState2["HAVE_NOTHING"] = 0] = "HAVE_NOTHING";
1465
- MediaReadyState2[MediaReadyState2["HAVE_METADATA"] = 1] = "HAVE_METADATA";
1466
- MediaReadyState2[MediaReadyState2["HAVE_CURRENT_DATA"] = 2] = "HAVE_CURRENT_DATA";
1467
- MediaReadyState2[MediaReadyState2["HAVE_FUTURE_DATA"] = 3] = "HAVE_FUTURE_DATA";
1468
- MediaReadyState2[MediaReadyState2["HAVE_ENOUGH_DATA"] = 4] = "HAVE_ENOUGH_DATA";
1469
- return MediaReadyState2;
1470
- })(MediaReadyState || {});
1471
- var media_ready_state_default = MediaReadyState;
3071
+ };
3072
+ var interaction_default = InteractionHelper;
1472
3073
 
1473
3074
  // src/client/page/cursor.ts
1474
- function getAttributeForElement(element, attribute) {
1475
- const value = element.getAttribute(attribute);
1476
- if (value === null) {
1477
- throw new import_errors7.InvariantViolation(`
1478
- Tried to read ${attribute} for element, but it was not set
1479
- `);
1480
- }
1481
- return value;
1482
- }
1483
- function getIndexPathForElement(element) {
1484
- return getAttributeForElement(element, "data-index-path");
1485
- }
1486
3075
  var CursorPage = class extends page_default {
1487
3076
  constructor() {
1488
3077
  super();
1489
3078
  this.logged_in = false;
1490
3079
  this.queued_media = null;
1491
3080
  this.ready_media = [];
3081
+ this.drag_helper = new interaction_default();
1492
3082
  }
1493
3083
  initView() {
1494
3084
  this.focusCurrentBlockElement();
1495
3085
  const meta_value = get_meta_value_default("logged_in");
1496
3086
  this.logged_in = meta_value === "true";
3087
+ if (this.isLoggedIn()) {
3088
+ this.drag_helper.attach();
3089
+ }
1497
3090
  }
1498
3091
  initEvents() {
1499
3092
  super.initEvents();
@@ -1503,13 +3096,94 @@
1503
3096
  document.addEventListener("ended", (event) => {
1504
3097
  this.handleMediaPlaybackEnded(event);
1505
3098
  }, true);
3099
+ document.addEventListener("click", (event) => {
3100
+ this.handleGenericClick(event);
3101
+ }, true);
3102
+ window.addEventListener("popstate", (event) => {
3103
+ this.handlePopstate(event);
3104
+ });
3105
+ }
3106
+ handleGenericClick(event) {
3107
+ if (this.drag_helper.isDragging()) {
3108
+ return;
3109
+ }
3110
+ if (!this.hasActiveMedia()) {
3111
+ return;
3112
+ }
3113
+ if (event.defaultPrevented) {
3114
+ return;
3115
+ }
3116
+ const mouse_event = event;
3117
+ if (mouse_event.button !== 0) {
3118
+ return;
3119
+ }
3120
+ if (mouse_event.metaKey || mouse_event.ctrlKey || mouse_event.shiftKey || mouse_event.altKey) {
3121
+ return;
3122
+ }
3123
+ if (event.target === null) {
3124
+ return;
3125
+ }
3126
+ const target = event.target;
3127
+ const anchor = target.closest("a[href]");
3128
+ if (anchor === null) {
3129
+ return;
3130
+ }
3131
+ const url = new URL(anchor.href, window.location.href);
3132
+ if (url.origin !== window.location.origin) {
3133
+ return;
3134
+ }
3135
+ event.preventDefault();
3136
+ const path = url.pathname + url.search + url.hash;
3137
+ this.navigateToPath(path);
3138
+ }
3139
+ navigateToPath(path) {
3140
+ if (!this.hasActiveMedia()) {
3141
+ window.location.href = path;
3142
+ return;
3143
+ }
3144
+ history.pushState({ path }, "", path);
3145
+ this.fetchAndDisplay(path);
3146
+ }
3147
+ async fetchAndDisplay(path) {
3148
+ const response = await fetch(path, {
3149
+ headers: {
3150
+ "Accept": "text/html"
3151
+ }
3152
+ });
3153
+ if (!response.ok) {
3154
+ window.location.href = path;
3155
+ return;
3156
+ }
3157
+ const html = await response.text();
3158
+ const parser = new DOMParser();
3159
+ const updated_document = parser.parseFromString(html, "text/html");
3160
+ const tags = ["header", "main", "footer"];
3161
+ let index = 0;
3162
+ while (index < tags.length) {
3163
+ const tag = tags[index++];
3164
+ const old_element = document.querySelector(tag);
3165
+ const new_element = updated_document.querySelector(tag);
3166
+ if (old_element === null && new_element === null) {
3167
+ continue;
3168
+ }
3169
+ if (old_element === null || new_element === null) {
3170
+ window.location.href = path;
3171
+ return;
3172
+ }
3173
+ old_element.replaceWith(new_element);
3174
+ }
3175
+ }
3176
+ handlePopstate(event) {
3177
+ const { pathname, search, hash } = window.location;
3178
+ const path = pathname + search + hash;
3179
+ this.fetchAndDisplay(path);
1506
3180
  }
1507
3181
  focusCurrentBlockElement() {
1508
- const element = this.getCurrentBlockElement();
1509
- if (element === null) {
3182
+ const current_block = this.getCurrentBlockElement();
3183
+ if (current_block === null) {
1510
3184
  return;
1511
3185
  }
1512
- this.focusElement(element);
3186
+ this.focusElement(current_block);
1513
3187
  }
1514
3188
  handleKey(key_code) {
1515
3189
  switch (key_code) {
@@ -1546,13 +3220,13 @@
1546
3220
  const link_id = `${block_id}-add-to-playlist`;
1547
3221
  const link_element = document.getElementById(link_id);
1548
3222
  if (link_element === null) {
1549
- throw new import_errors7.InvariantViolation(`
3223
+ throw new import_errors9.InvariantViolation(`
1550
3224
  Unable to find playlist link element for block: ${block_id}
1551
3225
  `);
1552
3226
  }
1553
3227
  const href = link_element.getAttribute("href");
1554
3228
  if (href === null) {
1555
- throw new import_errors7.InvariantViolation(`
3229
+ throw new import_errors9.InvariantViolation(`
1556
3230
  Unable to find playlist link href for block: ${block_id}
1557
3231
  `);
1558
3232
  }
@@ -1580,7 +3254,7 @@
1580
3254
  const form_id = `${block_id}-promote`;
1581
3255
  const form_element = document.getElementById(form_id);
1582
3256
  if (form_element === null) {
1583
- throw new import_errors7.InvariantViolation(`
3257
+ throw new import_errors9.InvariantViolation(`
1584
3258
  Unable to find promotion form element for block: ${block_id}
1585
3259
  `);
1586
3260
  }
@@ -1598,7 +3272,7 @@
1598
3272
  const form_id = `${block_id}-demote`;
1599
3273
  const form_element = document.getElementById(form_id);
1600
3274
  if (form_element === null) {
1601
- throw new import_errors7.InvariantViolation(`
3275
+ throw new import_errors9.InvariantViolation(`
1602
3276
  Unable to find demotion form element for block: ${block_id}
1603
3277
  `);
1604
3278
  }
@@ -1617,15 +3291,15 @@
1617
3291
  }
1618
3292
  jumpToPageTop() {
1619
3293
  this.navigateToIndex(this.getFirstBlockIndex());
1620
- this.focusCurrentBlockElement();
3294
+ window.scrollTo(0, 0);
1621
3295
  }
1622
3296
  jumpToPageBottom() {
1623
3297
  this.navigateToIndex(this.getLastBlockIndex());
1624
- this.focusCurrentBlockElement();
3298
+ window.scrollTo(0, document.documentElement.scrollHeight);
1625
3299
  }
1626
3300
  navigateToParentPage() {
1627
3301
  const parent_path = get_parent_path_default(window.location.pathname);
1628
- window.location.href = parent_path;
3302
+ this.navigateToPath(parent_path);
1629
3303
  }
1630
3304
  navigateToHistory() {
1631
3305
  window.location.href = "/history";
@@ -1637,7 +3311,7 @@
1637
3311
  const block_elements = this.getBlockElements();
1638
3312
  let found = false;
1639
3313
  block_elements.forEach((block_element) => {
1640
- const sibling_path = getIndexPathForElement(block_element);
3314
+ const sibling_path = get_index_path_for_element_default(block_element);
1641
3315
  const is_match = sibling_path === index_path;
1642
3316
  block_element.classList.toggle("selected", is_match);
1643
3317
  if (is_match) {
@@ -1645,7 +3319,7 @@
1645
3319
  }
1646
3320
  });
1647
3321
  if (!found) {
1648
- throw new import_errors7.InvariantViolation(`
3322
+ throw new import_errors9.InvariantViolation(`
1649
3323
  Tried to navigate to element at index path ${index_path},
1650
3324
  but matching element was not found
1651
3325
  `);
@@ -1658,16 +3332,26 @@
1658
3332
  if (this.shiftIsPressed()) {
1659
3333
  this.promoteCurrentBlock();
1660
3334
  } else {
1661
- this.navigateToIndex(this.getPreviousBlockIndex());
1662
- this.focusCurrentBlockElement();
3335
+ const index = this.getPreviousBlockIndex();
3336
+ if (index === null) {
3337
+ window.scrollTo(0, 0);
3338
+ } else {
3339
+ this.navigateToIndex(index);
3340
+ this.focusCurrentBlockElement();
3341
+ }
1663
3342
  }
1664
3343
  }
1665
3344
  selectNextBlock() {
1666
3345
  if (this.shiftIsPressed()) {
1667
3346
  this.demoteCurrentBlock();
1668
3347
  } else {
1669
- this.navigateToIndex(this.getNextBlockIndex());
1670
- this.focusCurrentBlockElement();
3348
+ const index = this.getNextBlockIndex();
3349
+ if (index === null) {
3350
+ window.scrollTo(0, document.documentElement.scrollHeight);
3351
+ } else {
3352
+ this.navigateToIndex(index);
3353
+ this.focusCurrentBlockElement();
3354
+ }
1671
3355
  }
1672
3356
  }
1673
3357
  getCurrentBlockIndex() {
@@ -1675,7 +3359,7 @@
1675
3359
  if (element === null) {
1676
3360
  return "0";
1677
3361
  }
1678
- return getIndexPathForElement(element);
3362
+ return get_index_path_for_element_default(element);
1679
3363
  }
1680
3364
  getCurrentBlockNumericIndex() {
1681
3365
  const index = this.getCurrentBlockIndex();
@@ -1704,26 +3388,26 @@
1704
3388
  return null;
1705
3389
  }
1706
3390
  const element = block_elements.find((element2) => {
1707
- const attribute = getIndexPathForElement(element2);
3391
+ const attribute = get_index_path_for_element_default(element2);
1708
3392
  return attribute === index_path;
1709
3393
  });
1710
3394
  return element || null;
1711
3395
  }
1712
3396
  getFirstBlockIndex() {
1713
3397
  const blocks = this.getBlockElements();
1714
- const first_block = (0, import_array2.getFirstValue)(blocks);
3398
+ const first_block = (0, import_array.getFirstValue)(blocks);
1715
3399
  if (first_block === void 0) {
1716
3400
  return null;
1717
3401
  }
1718
- return getIndexPathForElement(first_block);
3402
+ return get_index_path_for_element_default(first_block);
1719
3403
  }
1720
3404
  getLastBlockIndex() {
1721
3405
  const blocks = this.getBlockElements();
1722
- const last_block = (0, import_array2.getLastValue)(blocks);
3406
+ const last_block = (0, import_array.getLastValue)(blocks);
1723
3407
  if (last_block === void 0) {
1724
3408
  return null;
1725
3409
  }
1726
- return getIndexPathForElement(last_block);
3410
+ return get_index_path_for_element_default(last_block);
1727
3411
  }
1728
3412
  getNextBlockIndex() {
1729
3413
  const current_block = this.getCurrentBlockElement();
@@ -1733,7 +3417,7 @@
1733
3417
  if (next_block === void 0) {
1734
3418
  return null;
1735
3419
  }
1736
- return getIndexPathForElement(next_block);
3420
+ return get_index_path_for_element_default(next_block);
1737
3421
  }
1738
3422
  getPreviousBlockIndex() {
1739
3423
  const current_block = this.getCurrentBlockElement();
@@ -1752,14 +3436,14 @@
1752
3436
  }
1753
3437
  const attribute = block_element.getAttribute("data-block-type");
1754
3438
  if (attribute === null) {
1755
- throw new import_errors7.InvariantViolation(`
3439
+ throw new import_errors9.InvariantViolation(`
1756
3440
  Tried to activate current block, but it did not have a block type
1757
3441
  `);
1758
3442
  }
1759
3443
  const block_type = attribute;
1760
3444
  const block_types = Object.values(block_type_default);
1761
3445
  if (!block_types.includes(block_type)) {
1762
- throw new import_errors7.InvariantViolation(`
3446
+ throw new import_errors9.InvariantViolation(`
1763
3447
  Invalid block type: ${block_type}
1764
3448
  `);
1765
3449
  }
@@ -1780,7 +3464,7 @@
1780
3464
  const forms = block_element.getElementsByTagName("form");
1781
3465
  const form = forms[0];
1782
3466
  if (form === void 0) {
1783
- throw new import_errors7.InvariantViolation(`
3467
+ throw new import_errors9.InvariantViolation(`
1784
3468
  Tried to activate form for todo block, but it was not set
1785
3469
  `);
1786
3470
  }
@@ -1788,7 +3472,7 @@
1788
3472
  }
1789
3473
  activateFolderBlock(block_element) {
1790
3474
  const href = get_block_activation_href_default(block_element);
1791
- window.location.href = href;
3475
+ this.navigateToPath(href);
1792
3476
  }
1793
3477
  activateImageBlock(block_element) {
1794
3478
  const href = get_block_activation_href_default(block_element);
@@ -1797,7 +3481,7 @@
1797
3481
  activateAudioBlock(block_element) {
1798
3482
  const audio_element = block_element.querySelectorAll("audio")[0];
1799
3483
  if (audio_element === void 0) {
1800
- throw new import_errors7.InvariantViolation(`
3484
+ throw new import_errors9.InvariantViolation(`
1801
3485
  Tried to read audio element for block, but it was not present
1802
3486
  `);
1803
3487
  }
@@ -1812,16 +3496,57 @@
1812
3496
  if (element === null) {
1813
3497
  return;
1814
3498
  }
3499
+ this.playElement(element);
3500
+ }
3501
+ playElement(element) {
3502
+ this.pauseActiveMedia();
1815
3503
  const media_block = element.closest("section.block");
1816
- if (media_block !== null) {
1817
- const index_path = getIndexPathForElement(media_block);
1818
- this.navigateToIndex(index_path);
1819
- this.focusCurrentBlockElement();
3504
+ if (media_block === null) {
3505
+ throw new import_errors9.InvariantViolation(`
3506
+ Tried to access closest block wrapper for media, but it was not found
3507
+ `);
3508
+ }
3509
+ const index_path = get_index_path_for_element_default(media_block);
3510
+ this.navigateToIndex(index_path);
3511
+ this.focusCurrentBlockElement();
3512
+ const persistent_element = document.getElementById("persistent-audio");
3513
+ const persistent_audio = persistent_element;
3514
+ const track_target = document.getElementById("persistent-track-name");
3515
+ const artist_target = document.getElementById("persistent-artist-name");
3516
+ const track_source = media_block.querySelector('[data-role="track_name"]');
3517
+ const artist_source = media_block.querySelector('[data-role="artist_name"]');
3518
+ if (persistent_audio === null) {
3519
+ throw new import_errors9.InvariantViolation(`
3520
+ Tried to access persistent audio element, but it was not found
3521
+ `);
3522
+ }
3523
+ if (track_target === null) {
3524
+ throw new import_errors9.InvariantViolation(`
3525
+ Tried to access persistent track name element, but it was not found
3526
+ `);
3527
+ }
3528
+ if (artist_target === null) {
3529
+ throw new import_errors9.InvariantViolation(`
3530
+ Tried to access persistent artist name element, but it was not found
3531
+ `);
1820
3532
  }
3533
+ if (track_source === null) {
3534
+ throw new import_errors9.InvariantViolation(`
3535
+ Tried to read track name source, but it was not found
3536
+ `);
3537
+ }
3538
+ if (artist_source === null) {
3539
+ throw new import_errors9.InvariantViolation(`
3540
+ Tried to read artist name source, but it was not found
3541
+ `);
3542
+ }
3543
+ persistent_audio.src = element.src;
3544
+ track_target.innerHTML = track_source.innerHTML;
3545
+ artist_target.innerHTML = artist_source.innerHTML;
3546
+ document.body.classList.add("media-visible");
1821
3547
  if (element.readyState >= media_ready_state_default.HAVE_CURRENT_DATA) {
1822
- element.currentTime = 0;
1823
- element.play();
1824
- return;
3548
+ persistent_audio.currentTime = 0;
3549
+ persistent_audio.play();
1825
3550
  }
1826
3551
  }
1827
3552
  handleMediaCanPlay(event) {
@@ -1830,6 +3555,18 @@
1830
3555
  return;
1831
3556
  }
1832
3557
  const media_target = target;
3558
+ const duration_ms = media_target.duration * import_time.TimeInterval.ONE_SECOND;
3559
+ const timecode = (0, import_time.formatTimecode)(duration_ms);
3560
+ const block = media_target.closest("section.block");
3561
+ if (block !== null) {
3562
+ const duration_label = block.querySelector('[data-role="duration"]');
3563
+ if (duration_label === null) {
3564
+ throw new import_errors9.InvariantViolation(`
3565
+ Tried to read duration label for media block, but it was not found
3566
+ `);
3567
+ }
3568
+ duration_label.innerHTML = timecode;
3569
+ }
1833
3570
  if (this.queued_media !== media_target) {
1834
3571
  return;
1835
3572
  }
@@ -1837,8 +3574,7 @@
1837
3574
  return;
1838
3575
  }
1839
3576
  this.ready_media.push(media_target);
1840
- media_target.currentTime = 0;
1841
- media_target.play();
3577
+ this.playElement(media_target);
1842
3578
  }
1843
3579
  handleMediaPlaybackEnded(event) {
1844
3580
  const target = event.target;
@@ -1846,16 +3582,20 @@
1846
3582
  return;
1847
3583
  }
1848
3584
  const media_target = target;
1849
- if (this.queued_media !== null && this.queued_media !== media_target) {
1850
- return;
3585
+ const queued_media = this.queued_media;
3586
+ if (queued_media !== null) {
3587
+ if (queued_media.src !== media_target.src) {
3588
+ return;
3589
+ }
1851
3590
  }
1852
3591
  this.setQueuedMedia(null);
1853
3592
  media_target.currentTime = 0;
1854
- const media_elements = document.querySelectorAll("audio,video");
3593
+ const elements = document.querySelectorAll("audio,video");
3594
+ const media_elements = Array.from(elements);
1855
3595
  let index = 0;
1856
3596
  while (index < media_elements.length) {
1857
3597
  const element = media_elements[index++];
1858
- if (element === media_target) {
3598
+ if (element.src === media_target.src) {
1859
3599
  const next_element = media_elements[index];
1860
3600
  if (next_element) {
1861
3601
  return this.setQueuedMedia(next_element);
@@ -1863,17 +3603,27 @@
1863
3603
  }
1864
3604
  }
1865
3605
  }
1866
- pauseActiveMedia() {
1867
- this.setQueuedMedia(null);
3606
+ hasActiveMedia() {
3607
+ const active_media = this.getActiveMedia();
3608
+ return active_media.length > 0;
3609
+ }
3610
+ getActiveMedia() {
1868
3611
  const elements = document.querySelectorAll("audio,video");
1869
3612
  const media_elements = Array.from(elements);
1870
- media_elements.forEach((media_element) => {
3613
+ return media_elements.filter((media_element) => {
1871
3614
  if (media_element.paused || media_element.ended) {
1872
- return;
3615
+ return false;
1873
3616
  }
1874
3617
  if (media_element.readyState < media_ready_state_default.HAVE_CURRENT_DATA) {
1875
- return;
3618
+ return false;
1876
3619
  }
3620
+ return true;
3621
+ });
3622
+ }
3623
+ pauseActiveMedia() {
3624
+ this.setQueuedMedia(null);
3625
+ const active_media = this.getActiveMedia();
3626
+ active_media.forEach((media_element) => {
1877
3627
  media_element.pause();
1878
3628
  });
1879
3629
  }
@@ -1914,7 +3664,7 @@
1914
3664
  var create_block_default = CreateBlockPage;
1915
3665
 
1916
3666
  // src/client/page/edit-block.ts
1917
- var import_errors8 = __toESM(require_src2());
3667
+ var import_errors10 = __toESM(require_src2());
1918
3668
  var EditBlockPage = class extends page_default {
1919
3669
  initEvents() {
1920
3670
  super.initEvents();
@@ -1931,7 +3681,7 @@
1931
3681
  }
1932
3682
  }
1933
3683
  if (form === void 0) {
1934
- throw new import_errors8.InvariantViolation(`
3684
+ throw new import_errors10.InvariantViolation(`
1935
3685
  Tried to read form for textarea, but it was not set
1936
3686
  `);
1937
3687
  }
@@ -1947,7 +3697,7 @@
1947
3697
  var edit_block_default = EditBlockPage;
1948
3698
 
1949
3699
  // src/client/page/view-custom.ts
1950
- var import_errors9 = __toESM(require_src2());
3700
+ var import_errors11 = __toESM(require_src2());
1951
3701
  var ViewCustomPage = class extends cursor_default {
1952
3702
  handleKey(key_code) {
1953
3703
  switch (key_code) {
@@ -1977,13 +3727,13 @@
1977
3727
  const link_id = `${block_id}-edit`;
1978
3728
  const link_element = document.getElementById(link_id);
1979
3729
  if (link_element === null) {
1980
- throw new import_errors9.InvariantViolation(`
3730
+ throw new import_errors11.InvariantViolation(`
1981
3731
  Unable to find edit link element for block: ${block_id}
1982
3732
  `);
1983
3733
  }
1984
3734
  const href = link_element.getAttribute("href");
1985
3735
  if (href === null) {
1986
- throw new import_errors9.InvariantViolation(`
3736
+ throw new import_errors11.InvariantViolation(`
1987
3737
  Unable to find edit link href for block: ${block_id}
1988
3738
  `);
1989
3739
  }
@@ -1996,7 +3746,7 @@
1996
3746
  const current_path = this.getCurrentBlockIndex();
1997
3747
  const top_level_index = parseInt(current_path, 10);
1998
3748
  if (isNaN(top_level_index)) {
1999
- throw new import_errors9.InvariantViolation(`Invalid index path: ${current_path}`);
3749
+ throw new import_errors11.InvariantViolation(`Invalid index path: ${current_path}`);
2000
3750
  }
2001
3751
  const add_block_links = document.querySelectorAll('[data-role="add_block_link"]');
2002
3752
  const link_index = (() => {
@@ -2008,14 +3758,14 @@
2008
3758
  })();
2009
3759
  const link = add_block_links[link_index];
2010
3760
  if (link === void 0) {
2011
- throw new import_errors9.InvariantViolation(`
3761
+ throw new import_errors11.InvariantViolation(`
2012
3762
  Tried to read link at index ${link_index},
2013
3763
  but it was not found
2014
3764
  `);
2015
3765
  }
2016
3766
  const href = link.getAttribute("href");
2017
3767
  if (href === null) {
2018
- throw new import_errors9.InvariantViolation(`
3768
+ throw new import_errors11.InvariantViolation(`
2019
3769
  Tried to read href for link at index ${link_index},
2020
3770
  but it was not set
2021
3771
  `);
@@ -2034,13 +3784,13 @@
2034
3784
  const link_id = `${block_id}-move`;
2035
3785
  const link_element = document.getElementById(link_id);
2036
3786
  if (link_element === null) {
2037
- throw new import_errors9.InvariantViolation(`
3787
+ throw new import_errors11.InvariantViolation(`
2038
3788
  Unable to find move link element for block: ${block_id}
2039
3789
  `);
2040
3790
  }
2041
3791
  const href = link_element.getAttribute("href");
2042
3792
  if (href === null) {
2043
- throw new import_errors9.InvariantViolation(`
3793
+ throw new import_errors11.InvariantViolation(`
2044
3794
  Unable to find move link href for block: ${block_id}
2045
3795
  `);
2046
3796
  }
@@ -2050,6 +3800,9 @@
2050
3800
  if (!this.isLoggedIn()) {
2051
3801
  return;
2052
3802
  }
3803
+ if (this.shiftIsPressed()) {
3804
+ return;
3805
+ }
2053
3806
  const block_element = this.getCurrentBlockElement();
2054
3807
  if (block_element === null) {
2055
3808
  return;
@@ -2058,13 +3811,13 @@
2058
3811
  const link_id = `${block_id}-hide`;
2059
3812
  const link_element = document.getElementById(link_id);
2060
3813
  if (link_element === null) {
2061
- throw new import_errors9.InvariantViolation(`
3814
+ throw new import_errors11.InvariantViolation(`
2062
3815
  Unable to find hide link element for block: ${block_id}
2063
3816
  `);
2064
3817
  }
2065
3818
  const href = link_element.getAttribute("href");
2066
3819
  if (href === null) {
2067
- throw new import_errors9.InvariantViolation(`
3820
+ throw new import_errors11.InvariantViolation(`
2068
3821
  Unable to find hide link href for block: ${block_id}
2069
3822
  `);
2070
3823
  }
@@ -2075,13 +3828,13 @@
2075
3828
  const link_id = `${block_id}-delete`;
2076
3829
  const link_element = document.getElementById(link_id);
2077
3830
  if (link_element === null) {
2078
- throw new import_errors9.InvariantViolation(`
3831
+ throw new import_errors11.InvariantViolation(`
2079
3832
  Unable to find deletion link element for block: ${block_id}
2080
3833
  `);
2081
3834
  }
2082
3835
  const href = link_element.getAttribute("href");
2083
3836
  if (href === null) {
2084
- throw new import_errors9.InvariantViolation(`
3837
+ throw new import_errors11.InvariantViolation(`
2085
3838
  Unable to find deletion link href for block: ${block_id}
2086
3839
  `);
2087
3840
  }
@@ -2110,7 +3863,7 @@
2110
3863
  var edit_custom_default = EditCustomPage;
2111
3864
 
2112
3865
  // src/client/page/confirm-delete-block.ts
2113
- var import_errors10 = __toESM(require_src2());
3866
+ var import_errors12 = __toESM(require_src2());
2114
3867
  var ConfirmDeleteBlockPage = class extends page_default {
2115
3868
  handleKey(key_code) {
2116
3869
  switch (key_code) {
@@ -2123,7 +3876,7 @@
2123
3876
  submitDeletionForm() {
2124
3877
  const element = document.getElementById("deletion-form");
2125
3878
  if (element === null) {
2126
- throw new import_errors10.InvariantViolation("Could not find deletion form element");
3879
+ throw new import_errors12.InvariantViolation("Could not find deletion form element");
2127
3880
  }
2128
3881
  const form = element;
2129
3882
  form.submit();
@@ -2132,7 +3885,7 @@
2132
3885
  var confirm_delete_block_default = ConfirmDeleteBlockPage;
2133
3886
 
2134
3887
  // src/client/page/confirm-hide-block.ts
2135
- var import_errors11 = __toESM(require_src2());
3888
+ var import_errors13 = __toESM(require_src2());
2136
3889
  var ConfirmHideBlockPage = class extends page_default {
2137
3890
  handleKey(key_code) {
2138
3891
  switch (key_code) {
@@ -2145,7 +3898,7 @@
2145
3898
  submitHideForm() {
2146
3899
  const element = document.getElementById("hide-form");
2147
3900
  if (element === null) {
2148
- throw new import_errors11.InvariantViolation("Could not find hide form element");
3901
+ throw new import_errors13.InvariantViolation("Could not find hide form element");
2149
3902
  }
2150
3903
  const form = element;
2151
3904
  form.submit();
@@ -2238,7 +3991,7 @@
2238
3991
  const page_type = meta_value;
2239
3992
  const page_types = Object.values(page_type_default);
2240
3993
  if (!page_types.includes(page_type)) {
2241
- throw new import_errors12.InvariantViolation(`
3994
+ throw new import_errors14.InvariantViolation(`
2242
3995
  Invalid page type: ${page_type}
2243
3996
  `);
2244
3997
  }