jit-viewer 1.2.1 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -13576,6 +13576,14 @@ const zhCNMessages = {
13576
13576
  "toolbar.print": "打印",
13577
13577
  "toolbar.download": "下载",
13578
13578
  "toolbar.more": "更多",
13579
+ "toolbar.videoPlay": "播放",
13580
+ "toolbar.videoPause": "暂停",
13581
+ "toolbar.videoRestart": "重播",
13582
+ "toolbar.videoMuted": "取消静音",
13583
+ "toolbar.videoUnmuted": "静音",
13584
+ "toolbar.videoSpeed": "倍速",
13585
+ "toolbar.videoProgress": "播放进度",
13586
+ "toolbar.videoVolume": "音量",
13579
13587
  "loading": "加载中...",
13580
13588
  "error.loadFailed": "文件加载失败",
13581
13589
  "error.unsupportedType": "不支持的文件类型",
@@ -13596,6 +13604,14 @@ const enMessages = {
13596
13604
  "toolbar.print": "Print",
13597
13605
  "toolbar.download": "Download",
13598
13606
  "toolbar.more": "More",
13607
+ "toolbar.videoPlay": "Play",
13608
+ "toolbar.videoPause": "Pause",
13609
+ "toolbar.videoRestart": "Restart",
13610
+ "toolbar.videoMuted": "Unmute",
13611
+ "toolbar.videoUnmuted": "Mute",
13612
+ "toolbar.videoSpeed": "Speed",
13613
+ "toolbar.videoProgress": "Progress",
13614
+ "toolbar.videoVolume": "Volume",
13599
13615
  "loading": "Loading...",
13600
13616
  "error.loadFailed": "Failed to load file",
13601
13617
  "error.unsupportedType": "Unsupported file type",
@@ -13780,6 +13796,8 @@ function createViewerState(options = {}) {
13780
13796
  const totalPages = /* @__PURE__ */ ref(1);
13781
13797
  const fullscreen2 = /* @__PURE__ */ ref(false);
13782
13798
  const pageController = /* @__PURE__ */ ref(null);
13799
+ const videoState = /* @__PURE__ */ ref(null);
13800
+ const videoController = /* @__PURE__ */ ref(null);
13783
13801
  const state = computed(() => ({
13784
13802
  mounted: mounted.value,
13785
13803
  loading: loading.value,
@@ -13792,7 +13810,8 @@ function createViewerState(options = {}) {
13792
13810
  current: currentPage.value,
13793
13811
  total: totalPages.value
13794
13812
  },
13795
- fullscreen: fullscreen2.value
13813
+ fullscreen: fullscreen2.value,
13814
+ video: videoState.value
13796
13815
  }));
13797
13816
  const setMounted = (value) => {
13798
13817
  mounted.value = value;
@@ -13811,6 +13830,8 @@ function createViewerState(options = {}) {
13811
13830
  rotate.value = initialRotate;
13812
13831
  currentPage.value = 1;
13813
13832
  totalPages.value = 1;
13833
+ videoState.value = null;
13834
+ videoController.value = null;
13814
13835
  error.value = null;
13815
13836
  };
13816
13837
  const clearFile = () => {
@@ -13901,6 +13922,44 @@ function createViewerState(options = {}) {
13901
13922
  const setFullscreen = (value) => {
13902
13923
  fullscreen2.value = value;
13903
13924
  };
13925
+ const setVideoState = (value) => {
13926
+ videoState.value = value;
13927
+ };
13928
+ const setVideoController = (controller) => {
13929
+ videoController.value = controller;
13930
+ };
13931
+ const playVideo = async () => {
13932
+ var _a, _b;
13933
+ await ((_b = (_a = videoController.value) == null ? void 0 : _a.play) == null ? void 0 : _b.call(_a));
13934
+ };
13935
+ const pauseVideo = () => {
13936
+ var _a, _b;
13937
+ (_b = (_a = videoController.value) == null ? void 0 : _a.pause) == null ? void 0 : _b.call(_a);
13938
+ };
13939
+ const toggleVideoPlayback = async () => {
13940
+ var _a, _b;
13941
+ await ((_b = (_a = videoController.value) == null ? void 0 : _a.togglePlayback) == null ? void 0 : _b.call(_a));
13942
+ };
13943
+ const seekVideo = (time) => {
13944
+ var _a, _b;
13945
+ (_b = (_a = videoController.value) == null ? void 0 : _a.seek) == null ? void 0 : _b.call(_a, time);
13946
+ };
13947
+ const restartVideo = async () => {
13948
+ var _a, _b;
13949
+ await ((_b = (_a = videoController.value) == null ? void 0 : _a.restart) == null ? void 0 : _b.call(_a));
13950
+ };
13951
+ const setVideoMuted = (muted) => {
13952
+ var _a, _b;
13953
+ (_b = (_a = videoController.value) == null ? void 0 : _a.setMuted) == null ? void 0 : _b.call(_a, muted);
13954
+ };
13955
+ const setVideoVolume = (volume) => {
13956
+ var _a, _b;
13957
+ (_b = (_a = videoController.value) == null ? void 0 : _a.setVolume) == null ? void 0 : _b.call(_a, volume);
13958
+ };
13959
+ const setVideoPlaybackRate = (rate) => {
13960
+ var _a, _b;
13961
+ (_b = (_a = videoController.value) == null ? void 0 : _a.setPlaybackRate) == null ? void 0 : _b.call(_a, rate);
13962
+ };
13904
13963
  const printFn = /* @__PURE__ */ ref(null);
13905
13964
  const setPrintFn = (fn) => {
13906
13965
  printFn.value = fn;
@@ -13925,6 +13984,8 @@ function createViewerState(options = {}) {
13925
13984
  currentPage,
13926
13985
  totalPages,
13927
13986
  fullscreen: fullscreen2,
13987
+ videoState,
13988
+ videoController,
13928
13989
  // Computed
13929
13990
  state,
13930
13991
  // Methods
@@ -13942,6 +14003,16 @@ function createViewerState(options = {}) {
13942
14003
  nextPage,
13943
14004
  setPageController,
13944
14005
  setFullscreen,
14006
+ setVideoState,
14007
+ setVideoController,
14008
+ playVideo,
14009
+ pauseVideo,
14010
+ toggleVideoPlayback,
14011
+ seekVideo,
14012
+ restartVideo,
14013
+ setVideoMuted,
14014
+ setVideoVolume,
14015
+ setVideoPlaybackRate,
13945
14016
  // Print
13946
14017
  print,
13947
14018
  setPrintFn
@@ -13956,13 +14027,13 @@ function useViewerState() {
13956
14027
  }
13957
14028
  return context;
13958
14029
  }
13959
- const _hoisted_1$g = ["disabled", "title"];
13960
- const _hoisted_2$b = { class: "jv-toolbar-btn__icon" };
13961
- const _hoisted_3$6 = {
14030
+ const _hoisted_1$h = ["disabled", "title"];
14031
+ const _hoisted_2$c = { class: "jv-toolbar-btn__icon" };
14032
+ const _hoisted_3$7 = {
13962
14033
  key: 0,
13963
14034
  class: "jv-toolbar-btn__label"
13964
14035
  };
13965
- const _sfc_main$j = /* @__PURE__ */ defineComponent({
14036
+ const _sfc_main$k = /* @__PURE__ */ defineComponent({
13966
14037
  __name: "ActionButton",
13967
14038
  props: {
13968
14039
  type: {},
@@ -13986,11 +14057,11 @@ const _sfc_main$j = /* @__PURE__ */ defineComponent({
13986
14057
  title: __props.title,
13987
14058
  onClick: handleClick
13988
14059
  }, [
13989
- createBaseVNode("span", _hoisted_2$b, [
14060
+ createBaseVNode("span", _hoisted_2$c, [
13990
14061
  renderSlot(_ctx.$slots, "default", {}, void 0, true)
13991
14062
  ]),
13992
- __props.label ? (openBlock(), createElementBlock("span", _hoisted_3$6, toDisplayString(__props.label), 1)) : createCommentVNode("", true)
13993
- ], 10, _hoisted_1$g);
14063
+ __props.label ? (openBlock(), createElementBlock("span", _hoisted_3$7, toDisplayString(__props.label), 1)) : createCommentVNode("", true)
14064
+ ], 10, _hoisted_1$h);
13994
14065
  };
13995
14066
  }
13996
14067
  });
@@ -14001,11 +14072,11 @@ const _export_sfc = (sfc, props) => {
14001
14072
  }
14002
14073
  return target;
14003
14074
  };
14004
- const ActionButton = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-9abd52f0"]]);
14005
- const _hoisted_1$f = { class: "jv-zoom-control" };
14006
- const _hoisted_2$a = { class: "jv-zoom-control__value" };
14075
+ const ActionButton = /* @__PURE__ */ _export_sfc(_sfc_main$k, [["__scopeId", "data-v-9abd52f0"]]);
14076
+ const _hoisted_1$g = { class: "jv-zoom-control" };
14077
+ const _hoisted_2$b = { class: "jv-zoom-control__value" };
14007
14078
  const ZOOM_STEP = 0.1;
14008
- const _sfc_main$i = /* @__PURE__ */ defineComponent({
14079
+ const _sfc_main$j = /* @__PURE__ */ defineComponent({
14009
14080
  __name: "ZoomControl",
14010
14081
  setup(__props) {
14011
14082
  const { t } = useLocale();
@@ -14020,7 +14091,7 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
14020
14091
  resetTransform();
14021
14092
  }
14022
14093
  return (_ctx, _cache) => {
14023
- return openBlock(), createElementBlock("div", _hoisted_1$f, [
14094
+ return openBlock(), createElementBlock("div", _hoisted_1$g, [
14024
14095
  createVNode(ActionButton, {
14025
14096
  type: "zoom-out",
14026
14097
  title: unref(t)("toolbar.zoomOut"),
@@ -14054,7 +14125,7 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
14054
14125
  ])]),
14055
14126
  _: 1
14056
14127
  }, 8, ["title"]),
14057
- createBaseVNode("span", _hoisted_2$a, toDisplayString(Math.round(unref(zoom) * 100)) + "%", 1),
14128
+ createBaseVNode("span", _hoisted_2$b, toDisplayString(Math.round(unref(zoom) * 100)) + "%", 1),
14058
14129
  createVNode(ActionButton, {
14059
14130
  type: "zoom-in",
14060
14131
  title: unref(t)("toolbar.zoomIn"),
@@ -14128,10 +14199,10 @@ const _sfc_main$i = /* @__PURE__ */ defineComponent({
14128
14199
  };
14129
14200
  }
14130
14201
  });
14131
- const ZoomControl = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-874ddbac"]]);
14132
- const _hoisted_1$e = { class: "jv-rotate-control" };
14202
+ const ZoomControl = /* @__PURE__ */ _export_sfc(_sfc_main$j, [["__scopeId", "data-v-874ddbac"]]);
14203
+ const _hoisted_1$f = { class: "jv-rotate-control" };
14133
14204
  const ROTATE_STEP = 90;
14134
- const _sfc_main$h = /* @__PURE__ */ defineComponent({
14205
+ const _sfc_main$i = /* @__PURE__ */ defineComponent({
14135
14206
  __name: "RotateControl",
14136
14207
  setup(__props) {
14137
14208
  const { t } = useLocale();
@@ -14143,7 +14214,7 @@ const _sfc_main$h = /* @__PURE__ */ defineComponent({
14143
14214
  setRotate(ROTATE_STEP);
14144
14215
  }
14145
14216
  return (_ctx, _cache) => {
14146
- return openBlock(), createElementBlock("div", _hoisted_1$e, [
14217
+ return openBlock(), createElementBlock("div", _hoisted_1$f, [
14147
14218
  createVNode(ActionButton, {
14148
14219
  type: "rotate-left",
14149
14220
  title: unref(t)("toolbar.rotateLeft"),
@@ -14182,22 +14253,22 @@ const _sfc_main$h = /* @__PURE__ */ defineComponent({
14182
14253
  };
14183
14254
  }
14184
14255
  });
14185
- const RotateControl = /* @__PURE__ */ _export_sfc(_sfc_main$h, [["__scopeId", "data-v-ad291658"]]);
14186
- const _hoisted_1$d = {
14256
+ const RotateControl = /* @__PURE__ */ _export_sfc(_sfc_main$i, [["__scopeId", "data-v-ad291658"]]);
14257
+ const _hoisted_1$e = {
14187
14258
  key: 0,
14188
14259
  viewBox: "0 0 24 24",
14189
14260
  fill: "none",
14190
14261
  stroke: "currentColor",
14191
14262
  "stroke-width": "2"
14192
14263
  };
14193
- const _hoisted_2$9 = {
14264
+ const _hoisted_2$a = {
14194
14265
  key: 1,
14195
14266
  viewBox: "0 0 24 24",
14196
14267
  fill: "none",
14197
14268
  stroke: "currentColor",
14198
14269
  "stroke-width": "2"
14199
14270
  };
14200
- const _sfc_main$g = /* @__PURE__ */ defineComponent({
14271
+ const _sfc_main$h = /* @__PURE__ */ defineComponent({
14201
14272
  __name: "FullscreenButton",
14202
14273
  setup(__props) {
14203
14274
  const { t } = useLocale();
@@ -14226,9 +14297,9 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
14226
14297
  onClick: toggleFullscreen
14227
14298
  }, {
14228
14299
  default: withCtx(() => [
14229
- !isFullscreen.value ? (openBlock(), createElementBlock("svg", _hoisted_1$d, [..._cache[0] || (_cache[0] = [
14300
+ !isFullscreen.value ? (openBlock(), createElementBlock("svg", _hoisted_1$e, [..._cache[0] || (_cache[0] = [
14230
14301
  createBaseVNode("path", { d: "M8 3H5a2 2 0 0 0-2 2v3m18 0V5a2 2 0 0 0-2-2h-3m0 18h3a2 2 0 0 0 2-2v-3M3 16v3a2 2 0 0 0 2 2h3" }, null, -1)
14231
- ])])) : (openBlock(), createElementBlock("svg", _hoisted_2$9, [..._cache[1] || (_cache[1] = [
14302
+ ])])) : (openBlock(), createElementBlock("svg", _hoisted_2$a, [..._cache[1] || (_cache[1] = [
14232
14303
  createBaseVNode("path", { d: "M8 3v3a2 2 0 0 1-2 2H3m18 0h-3a2 2 0 0 1-2-2V3m0 18v-3a2 2 0 0 1 2-2h3M3 16h3a2 2 0 0 1 2 2v3" }, null, -1)
14233
14304
  ])]))
14234
14305
  ]),
@@ -14237,18 +14308,18 @@ const _sfc_main$g = /* @__PURE__ */ defineComponent({
14237
14308
  };
14238
14309
  }
14239
14310
  });
14240
- const _hoisted_1$c = {
14311
+ const _hoisted_1$d = {
14241
14312
  key: 0,
14242
14313
  class: "jv-pagination"
14243
14314
  };
14244
- const _hoisted_2$8 = { class: "jv-pagination__info" };
14245
- const _sfc_main$f = /* @__PURE__ */ defineComponent({
14315
+ const _hoisted_2$9 = { class: "jv-pagination__info" };
14316
+ const _sfc_main$g = /* @__PURE__ */ defineComponent({
14246
14317
  __name: "Pagination",
14247
14318
  setup(__props) {
14248
14319
  const { t } = useLocale();
14249
14320
  const { currentPage, totalPages, prevPage, nextPage } = useViewerState();
14250
14321
  return (_ctx, _cache) => {
14251
- return unref(totalPages) > 1 ? (openBlock(), createElementBlock("div", _hoisted_1$c, [
14322
+ return unref(totalPages) > 1 ? (openBlock(), createElementBlock("div", _hoisted_1$d, [
14252
14323
  createVNode(ActionButton, {
14253
14324
  type: "prev",
14254
14325
  title: unref(t)("toolbar.prevPage"),
@@ -14267,7 +14338,7 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
14267
14338
  ])]),
14268
14339
  _: 1
14269
14340
  }, 8, ["title", "disabled", "onClick"]),
14270
- createBaseVNode("span", _hoisted_2$8, toDisplayString(unref(t)("toolbar.pageInfo", { current: unref(currentPage).toString(), total: unref(totalPages).toString() })), 1),
14341
+ createBaseVNode("span", _hoisted_2$9, toDisplayString(unref(t)("toolbar.pageInfo", { current: unref(currentPage).toString(), total: unref(totalPages).toString() })), 1),
14271
14342
  createVNode(ActionButton, {
14272
14343
  type: "next",
14273
14344
  title: unref(t)("toolbar.nextPage"),
@@ -14290,7 +14361,462 @@ const _sfc_main$f = /* @__PURE__ */ defineComponent({
14290
14361
  };
14291
14362
  }
14292
14363
  });
14293
- const Pagination = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-97c0759f"]]);
14364
+ const Pagination = /* @__PURE__ */ _export_sfc(_sfc_main$g, [["__scopeId", "data-v-97c0759f"]]);
14365
+ const _hoisted_1$c = {
14366
+ key: 0,
14367
+ viewBox: "0 0 24 24",
14368
+ fill: "currentColor"
14369
+ };
14370
+ const _hoisted_2$8 = {
14371
+ key: 1,
14372
+ viewBox: "0 0 24 24",
14373
+ fill: "currentColor"
14374
+ };
14375
+ const _hoisted_3$6 = {
14376
+ key: 2,
14377
+ class: "jv-video-toolbar__time"
14378
+ };
14379
+ const _hoisted_4$6 = ["title"];
14380
+ const _hoisted_5$4 = ["max", "value", "title"];
14381
+ const _hoisted_6$4 = {
14382
+ key: 0,
14383
+ viewBox: "0 0 24 24",
14384
+ fill: "none",
14385
+ stroke: "currentColor",
14386
+ "stroke-width": "2"
14387
+ };
14388
+ const _hoisted_7$4 = {
14389
+ key: 1,
14390
+ viewBox: "0 0 24 24",
14391
+ fill: "none",
14392
+ stroke: "currentColor",
14393
+ "stroke-width": "2"
14394
+ };
14395
+ const _hoisted_8$3 = ["value"];
14396
+ const _hoisted_9$2 = {
14397
+ key: 6,
14398
+ class: "jv-video-toolbar__rate"
14399
+ };
14400
+ const _hoisted_10$1 = ["value"];
14401
+ const _hoisted_11$1 = ["value"];
14402
+ const _hoisted_12$1 = {
14403
+ key: 7,
14404
+ class: "jv-video-toolbar__more"
14405
+ };
14406
+ const _hoisted_13$1 = {
14407
+ key: 0,
14408
+ class: "jv-video-toolbar__more-menu"
14409
+ };
14410
+ const _hoisted_14 = {
14411
+ key: 2,
14412
+ class: "jv-video-toolbar__menu-row"
14413
+ };
14414
+ const _hoisted_15 = {
14415
+ key: 3,
14416
+ class: "jv-video-toolbar__menu-row"
14417
+ };
14418
+ const _hoisted_16 = { class: "jv-video-toolbar__menu-label" };
14419
+ const _hoisted_17 = {
14420
+ key: 0,
14421
+ class: "jv-video-toolbar__progress-track jv-video-toolbar__progress-track--menu"
14422
+ };
14423
+ const _hoisted_18 = ["max", "value", "title"];
14424
+ const _hoisted_19 = {
14425
+ key: 5,
14426
+ class: "jv-video-toolbar__menu-row"
14427
+ };
14428
+ const _hoisted_20 = { class: "jv-video-toolbar__menu-label" };
14429
+ const _hoisted_21 = ["value"];
14430
+ const _hoisted_22 = {
14431
+ key: 6,
14432
+ class: "jv-video-toolbar__menu-row"
14433
+ };
14434
+ const _hoisted_23 = { class: "jv-video-toolbar__menu-label" };
14435
+ const _hoisted_24 = ["value"];
14436
+ const _hoisted_25 = ["value"];
14437
+ const _sfc_main$f = /* @__PURE__ */ defineComponent({
14438
+ __name: "VideoToolbarControls",
14439
+ props: {
14440
+ videoOptions: {},
14441
+ itemConfig: {}
14442
+ },
14443
+ setup(__props) {
14444
+ const props = __props;
14445
+ const playbackRates = [0.75, 1, 1.25, 1.5, 2];
14446
+ const defaultToolbarItems = ["playback", "restart", "time", "progress"];
14447
+ const defaultToolbarMoreItems = ["mute", "volume", "speed"];
14448
+ const availableControlItems = ["playback", "restart", "time", "progress", "mute", "volume", "speed"];
14449
+ const { t } = useLocale();
14450
+ const {
14451
+ videoState,
14452
+ toggleVideoPlayback,
14453
+ seekVideo,
14454
+ restartVideo,
14455
+ setVideoMuted,
14456
+ setVideoVolume,
14457
+ setVideoPlaybackRate
14458
+ } = useViewerState();
14459
+ const rootRef = /* @__PURE__ */ ref(null);
14460
+ const isMoreOpen = /* @__PURE__ */ ref(false);
14461
+ const rangeMax = computed(() => {
14462
+ var _a;
14463
+ return Math.max(((_a = videoState.value) == null ? void 0 : _a.duration) || 0, 0);
14464
+ });
14465
+ const progressPercent = computed(() => {
14466
+ const state = videoState.value;
14467
+ if (!(state == null ? void 0 : state.duration) || state.duration <= 0) {
14468
+ return 0;
14469
+ }
14470
+ return Math.min(state.currentTime / state.duration * 100, 100);
14471
+ });
14472
+ const toolbarConfig = computed(() => {
14473
+ var _a, _b, _c, _d, _e;
14474
+ const itemOptions = (_a = props.itemConfig) == null ? void 0 : _a.options;
14475
+ const hasItemOverride = Array.isArray(itemOptions == null ? void 0 : itemOptions.items) || Array.isArray((_b = props.videoOptions) == null ? void 0 : _b.toolbarItems);
14476
+ const hasMoreItemOverride = Array.isArray(itemOptions == null ? void 0 : itemOptions.moreItems) || Array.isArray((_c = props.videoOptions) == null ? void 0 : _c.toolbarMoreItems);
14477
+ const primaryItems = hasItemOverride ? normalizeControlItems((itemOptions == null ? void 0 : itemOptions.items) ?? ((_d = props.videoOptions) == null ? void 0 : _d.toolbarItems)) : defaultToolbarItems;
14478
+ const secondaryItems = hasMoreItemOverride ? normalizeControlItems((itemOptions == null ? void 0 : itemOptions.moreItems) ?? ((_e = props.videoOptions) == null ? void 0 : _e.toolbarMoreItems)) : hasItemOverride ? [] : defaultToolbarMoreItems;
14479
+ return {
14480
+ primary: primaryItems,
14481
+ more: secondaryItems.filter((item) => !primaryItems.includes(item))
14482
+ };
14483
+ });
14484
+ const toolbarItems = computed(() => toolbarConfig.value.primary);
14485
+ const moreItems = computed(() => toolbarConfig.value.more);
14486
+ function normalizeControlItems(items) {
14487
+ if (!Array.isArray(items)) {
14488
+ return [];
14489
+ }
14490
+ const uniqueItems = /* @__PURE__ */ new Set();
14491
+ items.forEach((item) => {
14492
+ if (availableControlItems.includes(item)) {
14493
+ uniqueItems.add(item);
14494
+ }
14495
+ });
14496
+ return [...uniqueItems];
14497
+ }
14498
+ function hasInlineItem(type) {
14499
+ return toolbarItems.value.includes(type);
14500
+ }
14501
+ function hasMoreItem(type) {
14502
+ return moreItems.value.includes(type);
14503
+ }
14504
+ function toggleMoreMenu() {
14505
+ isMoreOpen.value = !isMoreOpen.value;
14506
+ }
14507
+ function closeMoreMenu() {
14508
+ isMoreOpen.value = false;
14509
+ }
14510
+ function handleDocumentClick(event) {
14511
+ if (!isMoreOpen.value || !rootRef.value) {
14512
+ return;
14513
+ }
14514
+ const target = event.target;
14515
+ if (target && !rootRef.value.contains(target)) {
14516
+ closeMoreMenu();
14517
+ }
14518
+ }
14519
+ function handleDocumentKeydown(event) {
14520
+ if (event.key === "Escape") {
14521
+ closeMoreMenu();
14522
+ }
14523
+ }
14524
+ function handleTogglePlayback(shouldCloseMenu = false) {
14525
+ void toggleVideoPlayback();
14526
+ if (shouldCloseMenu) {
14527
+ closeMoreMenu();
14528
+ }
14529
+ }
14530
+ function handleInlineTogglePlayback() {
14531
+ handleTogglePlayback();
14532
+ }
14533
+ function handleRestart(shouldCloseMenu = false) {
14534
+ void restartVideo();
14535
+ if (shouldCloseMenu) {
14536
+ closeMoreMenu();
14537
+ }
14538
+ }
14539
+ function handleInlineRestart() {
14540
+ handleRestart();
14541
+ }
14542
+ function handleSeek(event) {
14543
+ const target = event.target;
14544
+ if (!target) {
14545
+ return;
14546
+ }
14547
+ seekVideo(Number.parseFloat(target.value));
14548
+ }
14549
+ function handleToggleMuted(shouldCloseMenu = false) {
14550
+ if (!videoState.value) {
14551
+ return;
14552
+ }
14553
+ setVideoMuted(!(videoState.value.muted || videoState.value.volume === 0));
14554
+ if (shouldCloseMenu) {
14555
+ closeMoreMenu();
14556
+ }
14557
+ }
14558
+ function handleInlineToggleMuted() {
14559
+ handleToggleMuted();
14560
+ }
14561
+ function handleVolume(event) {
14562
+ const target = event.target;
14563
+ if (!target) {
14564
+ return;
14565
+ }
14566
+ setVideoVolume(Number.parseFloat(target.value));
14567
+ }
14568
+ function handlePlaybackRate(event) {
14569
+ const target = event.target;
14570
+ if (!target) {
14571
+ return;
14572
+ }
14573
+ setVideoPlaybackRate(Number.parseFloat(target.value));
14574
+ }
14575
+ function formatDuration(duration) {
14576
+ if (!Number.isFinite(duration) || duration <= 0) {
14577
+ return "00:00";
14578
+ }
14579
+ const totalSeconds = Math.floor(duration);
14580
+ const hours = Math.floor(totalSeconds / 3600);
14581
+ const minutes = Math.floor(totalSeconds % 3600 / 60);
14582
+ const seconds = totalSeconds % 60;
14583
+ if (hours > 0) {
14584
+ return [hours, minutes, seconds].map((value) => value.toString().padStart(2, "0")).join(":");
14585
+ }
14586
+ return [minutes, seconds].map((value) => value.toString().padStart(2, "0")).join(":");
14587
+ }
14588
+ onMounted(() => {
14589
+ document.addEventListener("click", handleDocumentClick);
14590
+ document.addEventListener("keydown", handleDocumentKeydown);
14591
+ });
14592
+ onUnmounted(() => {
14593
+ document.removeEventListener("click", handleDocumentClick);
14594
+ document.removeEventListener("keydown", handleDocumentKeydown);
14595
+ });
14596
+ return (_ctx, _cache) => {
14597
+ return unref(videoState) ? (openBlock(), createElementBlock("div", {
14598
+ key: 0,
14599
+ ref_key: "rootRef",
14600
+ ref: rootRef,
14601
+ class: "jv-video-toolbar"
14602
+ }, [
14603
+ hasInlineItem("playback") ? (openBlock(), createBlock(ActionButton, {
14604
+ key: 0,
14605
+ type: "video-playback",
14606
+ title: unref(videoState).paused ? unref(t)("toolbar.videoPlay") : unref(t)("toolbar.videoPause"),
14607
+ label: unref(videoState).paused ? unref(t)("toolbar.videoPlay") : unref(t)("toolbar.videoPause"),
14608
+ onClick: handleInlineTogglePlayback
14609
+ }, {
14610
+ default: withCtx(() => [
14611
+ unref(videoState).paused ? (openBlock(), createElementBlock("svg", _hoisted_1$c, [..._cache[3] || (_cache[3] = [
14612
+ createBaseVNode("path", { d: "M8 5v14l11-7z" }, null, -1)
14613
+ ])])) : (openBlock(), createElementBlock("svg", _hoisted_2$8, [..._cache[4] || (_cache[4] = [
14614
+ createBaseVNode("path", { d: "M8 5h3v14H8zm5 0h3v14h-3z" }, null, -1)
14615
+ ])]))
14616
+ ]),
14617
+ _: 1
14618
+ }, 8, ["title", "label"])) : createCommentVNode("", true),
14619
+ hasInlineItem("restart") ? (openBlock(), createBlock(ActionButton, {
14620
+ key: 1,
14621
+ type: "video-restart",
14622
+ title: unref(t)("toolbar.videoRestart"),
14623
+ onClick: handleInlineRestart
14624
+ }, {
14625
+ default: withCtx(() => [..._cache[5] || (_cache[5] = [
14626
+ createBaseVNode("svg", {
14627
+ viewBox: "0 0 24 24",
14628
+ fill: "none",
14629
+ stroke: "currentColor",
14630
+ "stroke-width": "2"
14631
+ }, [
14632
+ createBaseVNode("polyline", { points: "1 4 1 10 7 10" }),
14633
+ createBaseVNode("path", { d: "M3.51 15a9 9 0 1 0 .49-9.36L1 10" })
14634
+ ], -1)
14635
+ ])]),
14636
+ _: 1
14637
+ }, 8, ["title"])) : createCommentVNode("", true),
14638
+ hasInlineItem("time") ? (openBlock(), createElementBlock("div", _hoisted_3$6, toDisplayString(formatDuration(unref(videoState).currentTime)) + " / " + toDisplayString(formatDuration(unref(videoState).duration)), 1)) : createCommentVNode("", true),
14639
+ hasInlineItem("progress") ? (openBlock(), createElementBlock(Fragment, { key: 3 }, [
14640
+ unref(videoState).disableSeek ? (openBlock(), createElementBlock("div", {
14641
+ key: 0,
14642
+ class: "jv-video-toolbar__progress-track",
14643
+ title: unref(t)("toolbar.videoProgress")
14644
+ }, [
14645
+ createBaseVNode("div", {
14646
+ class: "jv-video-toolbar__progress-fill",
14647
+ style: normalizeStyle({ width: `${progressPercent.value}%` })
14648
+ }, null, 4)
14649
+ ], 8, _hoisted_4$6)) : (openBlock(), createElementBlock("input", {
14650
+ key: 1,
14651
+ class: "jv-video-toolbar__progress",
14652
+ type: "range",
14653
+ min: "0",
14654
+ max: rangeMax.value,
14655
+ value: unref(videoState).currentTime,
14656
+ step: "0.1",
14657
+ title: unref(t)("toolbar.videoProgress"),
14658
+ onInput: handleSeek
14659
+ }, null, 40, _hoisted_5$4))
14660
+ ], 64)) : createCommentVNode("", true),
14661
+ hasInlineItem("mute") ? (openBlock(), createBlock(ActionButton, {
14662
+ key: 4,
14663
+ type: "video-mute",
14664
+ title: unref(videoState).muted || unref(videoState).volume === 0 ? unref(t)("toolbar.videoMuted") : unref(t)("toolbar.videoUnmuted"),
14665
+ onClick: handleInlineToggleMuted
14666
+ }, {
14667
+ default: withCtx(() => [
14668
+ unref(videoState).muted || unref(videoState).volume === 0 ? (openBlock(), createElementBlock("svg", _hoisted_6$4, [..._cache[6] || (_cache[6] = [
14669
+ createBaseVNode("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }, null, -1),
14670
+ createBaseVNode("line", {
14671
+ x1: "23",
14672
+ y1: "9",
14673
+ x2: "17",
14674
+ y2: "15"
14675
+ }, null, -1),
14676
+ createBaseVNode("line", {
14677
+ x1: "17",
14678
+ y1: "9",
14679
+ x2: "23",
14680
+ y2: "15"
14681
+ }, null, -1)
14682
+ ])])) : (openBlock(), createElementBlock("svg", _hoisted_7$4, [..._cache[7] || (_cache[7] = [
14683
+ createBaseVNode("polygon", { points: "11 5 6 9 2 9 2 15 6 15 11 19 11 5" }, null, -1),
14684
+ createBaseVNode("path", { d: "M15.54 8.46a5 5 0 0 1 0 7.07" }, null, -1),
14685
+ createBaseVNode("path", { d: "M19.07 4.93a10 10 0 0 1 0 14.14" }, null, -1)
14686
+ ])]))
14687
+ ]),
14688
+ _: 1
14689
+ }, 8, ["title"])) : createCommentVNode("", true),
14690
+ hasInlineItem("volume") ? (openBlock(), createElementBlock("input", {
14691
+ key: 5,
14692
+ class: "jv-video-toolbar__volume",
14693
+ type: "range",
14694
+ min: "0",
14695
+ max: "1",
14696
+ step: "0.05",
14697
+ value: unref(videoState).muted ? 0 : unref(videoState).volume,
14698
+ onInput: handleVolume
14699
+ }, null, 40, _hoisted_8$3)) : createCommentVNode("", true),
14700
+ hasInlineItem("speed") ? (openBlock(), createElementBlock("label", _hoisted_9$2, [
14701
+ createBaseVNode("span", null, toDisplayString(unref(t)("toolbar.videoSpeed")), 1),
14702
+ createBaseVNode("select", {
14703
+ value: unref(videoState).playbackRate,
14704
+ onChange: handlePlaybackRate
14705
+ }, [
14706
+ (openBlock(), createElementBlock(Fragment, null, renderList(playbackRates, (rate) => {
14707
+ return createBaseVNode("option", {
14708
+ key: rate,
14709
+ value: rate
14710
+ }, toDisplayString(rate) + "x ", 9, _hoisted_11$1);
14711
+ }), 64))
14712
+ ], 40, _hoisted_10$1)
14713
+ ])) : createCommentVNode("", true),
14714
+ moreItems.value.length ? (openBlock(), createElementBlock("div", _hoisted_12$1, [
14715
+ createVNode(ActionButton, {
14716
+ type: "video-more",
14717
+ title: unref(t)("toolbar.more"),
14718
+ label: unref(t)("toolbar.more"),
14719
+ onClick: toggleMoreMenu
14720
+ }, {
14721
+ default: withCtx(() => [..._cache[8] || (_cache[8] = [
14722
+ createBaseVNode("svg", {
14723
+ viewBox: "0 0 24 24",
14724
+ fill: "currentColor"
14725
+ }, [
14726
+ createBaseVNode("circle", {
14727
+ cx: "5",
14728
+ cy: "12",
14729
+ r: "2"
14730
+ }),
14731
+ createBaseVNode("circle", {
14732
+ cx: "12",
14733
+ cy: "12",
14734
+ r: "2"
14735
+ }),
14736
+ createBaseVNode("circle", {
14737
+ cx: "19",
14738
+ cy: "12",
14739
+ r: "2"
14740
+ })
14741
+ ], -1)
14742
+ ])]),
14743
+ _: 1
14744
+ }, 8, ["title", "label"]),
14745
+ isMoreOpen.value ? (openBlock(), createElementBlock("div", _hoisted_13$1, [
14746
+ hasMoreItem("playback") ? (openBlock(), createElementBlock("button", {
14747
+ key: 0,
14748
+ type: "button",
14749
+ class: "jv-video-toolbar__menu-action",
14750
+ onClick: _cache[0] || (_cache[0] = ($event) => handleTogglePlayback(true))
14751
+ }, toDisplayString(unref(videoState).paused ? unref(t)("toolbar.videoPlay") : unref(t)("toolbar.videoPause")), 1)) : createCommentVNode("", true),
14752
+ hasMoreItem("restart") ? (openBlock(), createElementBlock("button", {
14753
+ key: 1,
14754
+ type: "button",
14755
+ class: "jv-video-toolbar__menu-action",
14756
+ onClick: _cache[1] || (_cache[1] = ($event) => handleRestart(true))
14757
+ }, toDisplayString(unref(t)("toolbar.videoRestart")), 1)) : createCommentVNode("", true),
14758
+ hasMoreItem("time") ? (openBlock(), createElementBlock("div", _hoisted_14, [
14759
+ createBaseVNode("span", null, toDisplayString(formatDuration(unref(videoState).currentTime)) + " / " + toDisplayString(formatDuration(unref(videoState).duration)), 1)
14760
+ ])) : createCommentVNode("", true),
14761
+ hasMoreItem("progress") ? (openBlock(), createElementBlock("div", _hoisted_15, [
14762
+ createBaseVNode("span", _hoisted_16, toDisplayString(unref(t)("toolbar.videoProgress")), 1),
14763
+ unref(videoState).disableSeek ? (openBlock(), createElementBlock("div", _hoisted_17, [
14764
+ createBaseVNode("div", {
14765
+ class: "jv-video-toolbar__progress-fill",
14766
+ style: normalizeStyle({ width: `${progressPercent.value}%` })
14767
+ }, null, 4)
14768
+ ])) : (openBlock(), createElementBlock("input", {
14769
+ key: 1,
14770
+ class: "jv-video-toolbar__progress jv-video-toolbar__progress--menu",
14771
+ type: "range",
14772
+ min: "0",
14773
+ max: rangeMax.value,
14774
+ value: unref(videoState).currentTime,
14775
+ step: "0.1",
14776
+ title: unref(t)("toolbar.videoProgress"),
14777
+ onInput: handleSeek
14778
+ }, null, 40, _hoisted_18))
14779
+ ])) : createCommentVNode("", true),
14780
+ hasMoreItem("mute") ? (openBlock(), createElementBlock("button", {
14781
+ key: 4,
14782
+ type: "button",
14783
+ class: "jv-video-toolbar__menu-action",
14784
+ onClick: _cache[2] || (_cache[2] = ($event) => handleToggleMuted(true))
14785
+ }, toDisplayString(unref(videoState).muted || unref(videoState).volume === 0 ? unref(t)("toolbar.videoMuted") : unref(t)("toolbar.videoUnmuted")), 1)) : createCommentVNode("", true),
14786
+ hasMoreItem("volume") ? (openBlock(), createElementBlock("label", _hoisted_19, [
14787
+ createBaseVNode("span", _hoisted_20, toDisplayString(unref(t)("toolbar.videoVolume")), 1),
14788
+ createBaseVNode("input", {
14789
+ class: "jv-video-toolbar__volume jv-video-toolbar__volume--menu",
14790
+ type: "range",
14791
+ min: "0",
14792
+ max: "1",
14793
+ step: "0.05",
14794
+ value: unref(videoState).muted ? 0 : unref(videoState).volume,
14795
+ onInput: handleVolume
14796
+ }, null, 40, _hoisted_21)
14797
+ ])) : createCommentVNode("", true),
14798
+ hasMoreItem("speed") ? (openBlock(), createElementBlock("label", _hoisted_22, [
14799
+ createBaseVNode("span", _hoisted_23, toDisplayString(unref(t)("toolbar.videoSpeed")), 1),
14800
+ createBaseVNode("select", {
14801
+ class: "jv-video-toolbar__select--menu",
14802
+ value: unref(videoState).playbackRate,
14803
+ onChange: handlePlaybackRate
14804
+ }, [
14805
+ (openBlock(), createElementBlock(Fragment, null, renderList(playbackRates, (rate) => {
14806
+ return createBaseVNode("option", {
14807
+ key: rate,
14808
+ value: rate
14809
+ }, toDisplayString(rate) + "x ", 9, _hoisted_25);
14810
+ }), 64))
14811
+ ], 40, _hoisted_24)
14812
+ ])) : createCommentVNode("", true)
14813
+ ])) : createCommentVNode("", true)
14814
+ ])) : createCommentVNode("", true)
14815
+ ], 512)) : createCommentVNode("", true);
14816
+ };
14817
+ }
14818
+ });
14819
+ const VideoToolbarControls = /* @__PURE__ */ _export_sfc(_sfc_main$f, [["__scopeId", "data-v-80052329"]]);
14294
14820
  const _hoisted_1$b = {
14295
14821
  key: 0,
14296
14822
  class: "jv-toolbar__top"
@@ -14302,43 +14828,43 @@ const _hoisted_3$5 = {
14302
14828
  };
14303
14829
  const _hoisted_4$5 = { class: "jv-toolbar__center" };
14304
14830
  const _hoisted_5$3 = { class: "jv-toolbar__right" };
14305
- const _hoisted_6$2 = {
14831
+ const _hoisted_6$3 = {
14306
14832
  key: 1,
14307
14833
  class: "jv-toolbar__bottom"
14308
14834
  };
14309
- const _hoisted_7$2 = { class: "jv-toolbar__left" };
14310
- const _hoisted_8$1 = { class: "jv-toolbar__center" };
14311
- const _hoisted_9 = { class: "jv-toolbar__right" };
14835
+ const _hoisted_7$3 = { class: "jv-toolbar__left" };
14836
+ const _hoisted_8$2 = { class: "jv-toolbar__center" };
14837
+ const _hoisted_9$1 = { class: "jv-toolbar__right" };
14312
14838
  const _sfc_main$e = /* @__PURE__ */ defineComponent({
14313
14839
  __name: "Toolbar",
14314
14840
  props: {
14315
14841
  config: {},
14316
- visible: { type: Boolean, default: true }
14842
+ visible: { type: Boolean, default: true },
14843
+ videoOptions: {}
14317
14844
  },
14318
14845
  setup(__props) {
14319
14846
  const props = __props;
14320
14847
  const { t } = useLocale();
14321
- const { filename, fileSource } = useViewerState();
14322
- const defaultItems = [
14323
- "zoom",
14324
- "rotate",
14325
- "fullscreen",
14326
- "pagination",
14327
- "download"
14328
- ];
14848
+ const { filename, fileSource, fileType } = useViewerState();
14849
+ const defaultItems = computed(() => {
14850
+ if (fileType.value === "video") {
14851
+ return ["zoom", "fullscreen", "video", "download"];
14852
+ }
14853
+ return ["zoom", "rotate", "fullscreen", "pagination", "download"];
14854
+ });
14329
14855
  const toolbarConfig = computed(() => {
14330
14856
  const config = props.config;
14331
14857
  if (typeof config === "boolean") {
14332
14858
  if (config === false) {
14333
14859
  return { items: [], position: "both" };
14334
14860
  }
14335
- return { items: defaultItems.map((type) => ({ type })), position: "both" };
14861
+ return { items: defaultItems.value.map((type) => ({ type })), position: "both" };
14336
14862
  }
14337
14863
  if (!config) {
14338
- return { items: defaultItems.map((type) => ({ type })), position: "both" };
14864
+ return { items: defaultItems.value.map((type) => ({ type })), position: "both" };
14339
14865
  }
14340
14866
  return {
14341
- items: config.items || defaultItems.map((type) => ({ type })),
14867
+ items: config.items || defaultItems.value.map((type) => ({ type })),
14342
14868
  position: config.position || "both"
14343
14869
  };
14344
14870
  });
@@ -14358,6 +14884,10 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
14358
14884
  var _a;
14359
14885
  return ((_a = toolbarConfig.value.items) == null ? void 0 : _a.some((item) => item.type === type)) ?? false;
14360
14886
  }
14887
+ function getItem(type) {
14888
+ var _a;
14889
+ return (_a = toolbarConfig.value.items) == null ? void 0 : _a.find((item) => item.type === type);
14890
+ }
14361
14891
  async function handleDownload() {
14362
14892
  if (fileSource.value) {
14363
14893
  await downloadFile(fileSource.value, filename.value);
@@ -14380,20 +14910,26 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
14380
14910
  renderSlot(_ctx.$slots, "top-right", {}, () => [
14381
14911
  hasItem("zoom") ? (openBlock(), createBlock(ZoomControl, { key: 0 })) : createCommentVNode("", true),
14382
14912
  hasItem("rotate") ? (openBlock(), createBlock(RotateControl, { key: 1 })) : createCommentVNode("", true),
14383
- hasItem("fullscreen") ? (openBlock(), createBlock(_sfc_main$g, { key: 2 })) : createCommentVNode("", true)
14913
+ hasItem("fullscreen") ? (openBlock(), createBlock(_sfc_main$h, { key: 2 })) : createCommentVNode("", true)
14384
14914
  ], true)
14385
14915
  ])
14386
14916
  ])) : createCommentVNode("", true),
14387
- showBottom.value ? (openBlock(), createElementBlock("div", _hoisted_6$2, [
14388
- createBaseVNode("div", _hoisted_7$2, [
14917
+ showBottom.value ? (openBlock(), createElementBlock("div", _hoisted_6$3, [
14918
+ createBaseVNode("div", _hoisted_7$3, [
14389
14919
  renderSlot(_ctx.$slots, "bottom-left", {}, () => [
14390
14920
  hasItem("pagination") ? (openBlock(), createBlock(Pagination, { key: 0 })) : createCommentVNode("", true)
14391
14921
  ], true)
14392
14922
  ]),
14393
- createBaseVNode("div", _hoisted_8$1, [
14394
- renderSlot(_ctx.$slots, "bottom-center", {}, void 0, true)
14923
+ createBaseVNode("div", _hoisted_8$2, [
14924
+ renderSlot(_ctx.$slots, "bottom-center", {}, () => [
14925
+ unref(fileType) === "video" && hasItem("video") ? (openBlock(), createBlock(VideoToolbarControls, {
14926
+ key: 0,
14927
+ "video-options": __props.videoOptions,
14928
+ "item-config": getItem("video")
14929
+ }, null, 8, ["video-options", "item-config"])) : createCommentVNode("", true)
14930
+ ], true)
14395
14931
  ]),
14396
- createBaseVNode("div", _hoisted_9, [
14932
+ createBaseVNode("div", _hoisted_9$1, [
14397
14933
  renderSlot(_ctx.$slots, "bottom-right", {}, () => [
14398
14934
  hasItem("download") ? (openBlock(), createBlock(ActionButton, {
14399
14935
  key: 0,
@@ -14427,7 +14963,7 @@ const _sfc_main$e = /* @__PURE__ */ defineComponent({
14427
14963
  };
14428
14964
  }
14429
14965
  });
14430
- const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-74d3b30f"]]);
14966
+ const Toolbar = /* @__PURE__ */ _export_sfc(_sfc_main$e, [["__scopeId", "data-v-c43b7d04"]]);
14431
14967
  var commonjsGlobal = typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : {};
14432
14968
  function getDefaultExportFromCjs(x) {
14433
14969
  return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
@@ -62456,11 +62992,11 @@ const _hoisted_2$6 = { class: "jv-csv-meta" };
62456
62992
  const _hoisted_3$4 = { class: "jv-csv-meta" };
62457
62993
  const _hoisted_4$4 = { class: "jv-csv-scroll" };
62458
62994
  const _hoisted_5$2 = { class: "jv-csv-stage" };
62459
- const _hoisted_6$1 = {
62995
+ const _hoisted_6$2 = {
62460
62996
  key: 0,
62461
62997
  class: "jv-csv-empty"
62462
62998
  };
62463
- const _hoisted_7$1 = { class: "jv-csv-index" };
62999
+ const _hoisted_7$2 = { class: "jv-csv-index" };
62464
63000
  const _sfc_main$b = /* @__PURE__ */ defineComponent({
62465
63001
  __name: "CsvRender",
62466
63002
  props: {
@@ -62676,7 +63212,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
62676
63212
  ]),
62677
63213
  createBaseVNode("div", _hoisted_4$4, [
62678
63214
  createBaseVNode("div", _hoisted_5$2, [
62679
- !dataRows.value.length ? (openBlock(), createElementBlock("div", _hoisted_6$1, "CSV 内容为空")) : (openBlock(), createElementBlock("div", {
63215
+ !dataRows.value.length ? (openBlock(), createElementBlock("div", _hoisted_6$2, "CSV 内容为空")) : (openBlock(), createElementBlock("div", {
62680
63216
  key: 1,
62681
63217
  ref_key: "scrollRef",
62682
63218
  ref: scrollRef,
@@ -62710,7 +63246,7 @@ const _sfc_main$b = /* @__PURE__ */ defineComponent({
62710
63246
  return openBlock(), createElementBlock("tr", {
62711
63247
  key: `row-${rowIndex}`
62712
63248
  }, [
62713
- createBaseVNode("td", _hoisted_7$1, toDisplayString(rowIndex + 2), 1),
63249
+ createBaseVNode("td", _hoisted_7$2, toDisplayString(rowIndex + 2), 1),
62714
63250
  (openBlock(true), createElementBlock(Fragment, null, renderList(row, (cell, cellIndex) => {
62715
63251
  return openBlock(), createElementBlock("td", {
62716
63252
  key: `cell-${rowIndex}-${cellIndex}`
@@ -129728,23 +130264,53 @@ const _hoisted_2$2 = {
129728
130264
  class: "jv-video-stage"
129729
130265
  };
129730
130266
  const _hoisted_3$2 = { class: "jv-video-loading" };
129731
- const _hoisted_4$2 = ["src", "title"];
130267
+ const _hoisted_4$2 = ["src", "title", "controls", "autoplay", "muted", "loop"];
129732
130268
  const _hoisted_5$1 = {
130269
+ key: 2,
130270
+ class: "jv-video-controls__timeline"
130271
+ };
130272
+ const _hoisted_6$1 = {
130273
+ key: 0,
130274
+ class: "jv-video-controls__progress-track"
130275
+ };
130276
+ const _hoisted_7$1 = ["max", "value"];
130277
+ const _hoisted_8$1 = {
130278
+ key: 3,
130279
+ class: "jv-video-controls__time"
130280
+ };
130281
+ const _hoisted_9 = ["value"];
130282
+ const _hoisted_10 = {
130283
+ key: 6,
130284
+ class: "jv-video-controls__rate"
130285
+ };
130286
+ const _hoisted_11 = ["value"];
130287
+ const _hoisted_12 = ["value"];
130288
+ const _hoisted_13 = {
129733
130289
  key: 0,
129734
130290
  class: "jv-video-info"
129735
130291
  };
130292
+ const VIDEO_PROGRESS_MEMORY_KEY = "__JIT_VIEWER_VIDEO_PROGRESS_MEMORY__";
129736
130293
  const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129737
130294
  __name: "VideoRender",
129738
130295
  props: {
129739
130296
  source: {},
129740
130297
  zoom: { default: 1 },
129741
130298
  proxyUrl: {},
129742
- requestAdapter: {}
130299
+ requestAdapter: {},
130300
+ videoOptions: {},
130301
+ preferExternalControls: { type: Boolean }
129743
130302
  },
129744
- emits: ["load", "error"],
129745
- setup(__props, { emit: __emit }) {
130303
+ emits: ["load", "error", "stateChange", "play", "pause", "ended", "timeUpdate", "seekingBlocked"],
130304
+ setup(__props, { expose: __expose, emit: __emit }) {
129746
130305
  const props = __props;
129747
130306
  const emit2 = __emit;
130307
+ function getVideoProgressMemoryStore() {
130308
+ const scope = globalThis;
130309
+ if (!scope[VIDEO_PROGRESS_MEMORY_KEY]) {
130310
+ scope[VIDEO_PROGRESS_MEMORY_KEY] = /* @__PURE__ */ new Map();
130311
+ }
130312
+ return scope[VIDEO_PROGRESS_MEMORY_KEY];
130313
+ }
129748
130314
  const containerRef = /* @__PURE__ */ ref();
129749
130315
  const videoRef = /* @__PURE__ */ ref();
129750
130316
  const loading = /* @__PURE__ */ ref(true);
@@ -129752,6 +130318,66 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129752
130318
  const videoSrc = /* @__PURE__ */ ref("");
129753
130319
  const videoName = /* @__PURE__ */ ref("");
129754
130320
  const videoInfo = /* @__PURE__ */ ref(null);
130321
+ const playbackState = /* @__PURE__ */ ref({
130322
+ currentTime: 0,
130323
+ duration: 0,
130324
+ paused: true,
130325
+ ended: false,
130326
+ muted: false,
130327
+ volume: 1,
130328
+ playbackRate: 1,
130329
+ disableSeek: false
130330
+ });
130331
+ let objectUrl = null;
130332
+ let lastKnownTime = 0;
130333
+ let lastPersistedTime = -1;
130334
+ let allowProgrammaticSeek = false;
130335
+ const videoOptions = computed(() => props.videoOptions || {});
130336
+ const controlsEnabled = computed(() => videoOptions.value.controls !== false);
130337
+ const disableSeek = computed(() => Boolean(videoOptions.value.disableSeek));
130338
+ const useCustomControls = computed(() => {
130339
+ if (typeof videoOptions.value.customControls === "boolean") {
130340
+ return videoOptions.value.customControls;
130341
+ }
130342
+ if (disableSeek.value) {
130343
+ return true;
130344
+ }
130345
+ if (videoOptions.value.nativeControls === false) {
130346
+ return true;
130347
+ }
130348
+ return false;
130349
+ });
130350
+ const showNativeControls = computed(() => {
130351
+ if (!controlsEnabled.value) {
130352
+ return false;
130353
+ }
130354
+ if (typeof videoOptions.value.nativeControls === "boolean") {
130355
+ return videoOptions.value.nativeControls;
130356
+ }
130357
+ return !useCustomControls.value;
130358
+ });
130359
+ const showCustomControls = computed(() => {
130360
+ return controlsEnabled.value && useCustomControls.value && !props.preferExternalControls;
130361
+ });
130362
+ const autoplay = computed(() => Boolean(videoOptions.value.autoplay));
130363
+ const muted = computed(() => Boolean(videoOptions.value.muted));
130364
+ const loop = computed(() => Boolean(videoOptions.value.loop));
130365
+ const rangeMax = computed(() => Math.max(playbackState.value.duration || 0, 0));
130366
+ const defaultCustomControlItems = ["playback", "restart", "progress", "time", "mute", "volume", "speed"];
130367
+ const customControlItems = computed(() => {
130368
+ const configuredItems = videoOptions.value.customControlItems;
130369
+ return configuredItems && configuredItems.length > 0 ? configuredItems : defaultCustomControlItems;
130370
+ });
130371
+ const progressPercent = computed(() => {
130372
+ if (!playbackState.value.duration || playbackState.value.duration <= 0) {
130373
+ return 0;
130374
+ }
130375
+ return Math.min(playbackState.value.currentTime / playbackState.value.duration * 100, 100);
130376
+ });
130377
+ const playbackRates = [0.75, 1, 1.25, 1.5, 2];
130378
+ function hasCustomControl(type) {
130379
+ return customControlItems.value.includes(type);
130380
+ }
129755
130381
  const stageStyle = computed(() => {
129756
130382
  if (props.zoom === 1) {
129757
130383
  return {};
@@ -129761,22 +130387,153 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129761
130387
  transformOrigin: "top center"
129762
130388
  };
129763
130389
  });
130390
+ function normalizeResumeStorage() {
130391
+ const value = videoOptions.value.resumePlayback;
130392
+ if (!value) {
130393
+ return null;
130394
+ }
130395
+ if (value === true) {
130396
+ return "local";
130397
+ }
130398
+ return value;
130399
+ }
130400
+ function getStorageAdapter(mode) {
130401
+ try {
130402
+ if (mode === "local" && typeof window !== "undefined" && window.localStorage) {
130403
+ return window.localStorage;
130404
+ }
130405
+ if (mode === "session" && typeof window !== "undefined" && window.sessionStorage) {
130406
+ return window.sessionStorage;
130407
+ }
130408
+ } catch {
130409
+ return null;
130410
+ }
130411
+ return null;
130412
+ }
130413
+ function getResumeKey() {
130414
+ if (videoOptions.value.resumeKey) {
130415
+ return `jv:video-progress:${videoOptions.value.resumeKey}`;
130416
+ }
130417
+ const source = props.source;
130418
+ if (typeof source === "string") {
130419
+ return `jv:video-progress:url:${source}`;
130420
+ }
130421
+ if (source instanceof File) {
130422
+ return `jv:video-progress:file:${source.name}:${source.size}:${source.lastModified}`;
130423
+ }
130424
+ if (source instanceof Blob) {
130425
+ return `jv:video-progress:blob:${source.size}:${source.type || "unknown"}`;
130426
+ }
130427
+ if (source instanceof ArrayBuffer) {
130428
+ return `jv:video-progress:buffer:${source.byteLength}`;
130429
+ }
130430
+ if (source && typeof source === "object" && "url" in source) {
130431
+ return `jv:video-progress:request:${source.url}`;
130432
+ }
130433
+ return `jv:video-progress:name:${getFilename(source)}`;
130434
+ }
130435
+ function readProgress() {
130436
+ const mode = normalizeResumeStorage();
130437
+ if (!mode) {
130438
+ return 0;
130439
+ }
130440
+ const key = getResumeKey();
130441
+ if (mode === "memory") {
130442
+ return getVideoProgressMemoryStore().get(key) || 0;
130443
+ }
130444
+ const storage = getStorageAdapter(mode);
130445
+ if (!storage) {
130446
+ return getVideoProgressMemoryStore().get(key) || 0;
130447
+ }
130448
+ const raw = storage.getItem(key);
130449
+ const parsed = raw ? Number.parseFloat(raw) : 0;
130450
+ return Number.isFinite(parsed) && parsed > 0 ? parsed : 0;
130451
+ }
130452
+ function writeProgress(time) {
130453
+ const mode = normalizeResumeStorage();
130454
+ if (!mode) {
130455
+ return;
130456
+ }
130457
+ const key = getResumeKey();
130458
+ const normalizedTime = Number.isFinite(time) && time > 0 ? time : 0;
130459
+ if (mode === "memory") {
130460
+ if (normalizedTime > 0) {
130461
+ getVideoProgressMemoryStore().set(key, normalizedTime);
130462
+ } else {
130463
+ getVideoProgressMemoryStore().delete(key);
130464
+ }
130465
+ return;
130466
+ }
130467
+ const storage = getStorageAdapter(mode);
130468
+ if (!storage) {
130469
+ if (normalizedTime > 0) {
130470
+ getVideoProgressMemoryStore().set(key, normalizedTime);
130471
+ } else {
130472
+ getVideoProgressMemoryStore().delete(key);
130473
+ }
130474
+ return;
130475
+ }
130476
+ if (normalizedTime > 0) {
130477
+ storage.setItem(key, normalizedTime.toString());
130478
+ } else {
130479
+ storage.removeItem(key);
130480
+ }
130481
+ }
130482
+ function persistProgress(time, force = false) {
130483
+ if (!force && lastPersistedTime >= 0 && Math.abs(time - lastPersistedTime) < 1) {
130484
+ return;
130485
+ }
130486
+ writeProgress(time);
130487
+ lastPersistedTime = time;
130488
+ }
130489
+ function getPlaybackState() {
130490
+ const video = videoRef.value;
130491
+ if (!video) {
130492
+ return {
130493
+ ...playbackState.value,
130494
+ disableSeek: disableSeek.value
130495
+ };
130496
+ }
130497
+ return {
130498
+ currentTime: Number.isFinite(video.currentTime) ? video.currentTime : 0,
130499
+ duration: Number.isFinite(video.duration) ? video.duration : playbackState.value.duration,
130500
+ paused: video.paused,
130501
+ ended: video.ended,
130502
+ muted: video.muted,
130503
+ volume: video.volume,
130504
+ playbackRate: video.playbackRate,
130505
+ disableSeek: disableSeek.value
130506
+ };
130507
+ }
130508
+ function syncPlaybackState() {
130509
+ playbackState.value = getPlaybackState();
130510
+ return playbackState.value;
130511
+ }
130512
+ function syncAndEmitStateChange() {
130513
+ const state = syncPlaybackState();
130514
+ emit2("stateChange", state);
130515
+ return state;
130516
+ }
129764
130517
  function cleanupObjectUrl() {
129765
- if (videoSrc.value.startsWith("blob:")) {
129766
- URL.revokeObjectURL(videoSrc.value);
130518
+ if (objectUrl == null ? void 0 : objectUrl.startsWith("blob:")) {
130519
+ URL.revokeObjectURL(objectUrl);
129767
130520
  }
130521
+ objectUrl = null;
129768
130522
  videoSrc.value = "";
129769
130523
  }
129770
130524
  async function loadVideo() {
129771
130525
  try {
129772
130526
  loading.value = true;
129773
130527
  error.value = null;
130528
+ lastKnownTime = 0;
130529
+ lastPersistedTime = -1;
129774
130530
  cleanupObjectUrl();
129775
130531
  const blob = await fileToBlob(props.source, {
129776
130532
  proxyUrl: props.proxyUrl,
129777
130533
  requestAdapter: props.requestAdapter
129778
130534
  });
129779
- videoSrc.value = URL.createObjectURL(blob);
130535
+ objectUrl = URL.createObjectURL(blob);
130536
+ videoSrc.value = objectUrl;
129780
130537
  videoName.value = getFilename(props.source);
129781
130538
  videoInfo.value = {
129782
130539
  width: 0,
@@ -129784,30 +130541,216 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129784
130541
  duration: 0,
129785
130542
  size: blob.size
129786
130543
  };
130544
+ playbackState.value = {
130545
+ currentTime: 0,
130546
+ duration: 0,
130547
+ paused: true,
130548
+ ended: false,
130549
+ muted: muted.value,
130550
+ volume: 1,
130551
+ playbackRate: videoOptions.value.playbackRate || 1,
130552
+ disableSeek: disableSeek.value
130553
+ };
129787
130554
  } catch (err) {
129788
130555
  loading.value = false;
129789
130556
  error.value = err;
129790
130557
  emit2("error", err);
129791
130558
  }
129792
130559
  }
130560
+ function applyResumeProgress() {
130561
+ const video = videoRef.value;
130562
+ if (!video) {
130563
+ return;
130564
+ }
130565
+ const resumeTime = readProgress();
130566
+ if (resumeTime <= 0 || !Number.isFinite(video.duration) || video.duration <= 0) {
130567
+ return;
130568
+ }
130569
+ const safeTime = Math.min(Math.max(resumeTime, 0), Math.max(video.duration - 1, 0));
130570
+ if (safeTime <= 0) {
130571
+ return;
130572
+ }
130573
+ allowProgrammaticSeek = true;
130574
+ video.currentTime = safeTime;
130575
+ lastKnownTime = safeTime;
130576
+ syncPlaybackState();
130577
+ }
129793
130578
  function handleLoadedMetadata() {
129794
- if (!videoRef.value || !videoInfo.value) {
130579
+ const video = videoRef.value;
130580
+ if (!video || !videoInfo.value) {
129795
130581
  return;
129796
130582
  }
130583
+ if (typeof videoOptions.value.playbackRate === "number" && Number.isFinite(videoOptions.value.playbackRate)) {
130584
+ video.playbackRate = videoOptions.value.playbackRate;
130585
+ }
129797
130586
  videoInfo.value = {
129798
130587
  ...videoInfo.value,
129799
- width: videoRef.value.videoWidth,
129800
- height: videoRef.value.videoHeight,
129801
- duration: videoRef.value.duration
130588
+ width: video.videoWidth,
130589
+ height: video.videoHeight,
130590
+ duration: video.duration
129802
130591
  };
130592
+ syncPlaybackState();
130593
+ applyResumeProgress();
130594
+ syncAndEmitStateChange();
129803
130595
  loading.value = false;
129804
130596
  emit2("load");
129805
130597
  }
130598
+ function handlePlay() {
130599
+ var _a, _b;
130600
+ const state = syncAndEmitStateChange();
130601
+ emit2("play", state);
130602
+ (_b = (_a = videoOptions.value).onPlay) == null ? void 0 : _b.call(_a, state);
130603
+ }
130604
+ function handlePause() {
130605
+ var _a, _b;
130606
+ const state = syncAndEmitStateChange();
130607
+ persistProgress(state.currentTime, true);
130608
+ emit2("pause", state);
130609
+ (_b = (_a = videoOptions.value).onPause) == null ? void 0 : _b.call(_a, state);
130610
+ }
130611
+ function handleEnded() {
130612
+ var _a, _b;
130613
+ persistProgress(0, true);
130614
+ const state = syncAndEmitStateChange();
130615
+ emit2("ended", state);
130616
+ (_b = (_a = videoOptions.value).onEnded) == null ? void 0 : _b.call(_a, state);
130617
+ }
130618
+ function handleTimeUpdate() {
130619
+ var _a, _b;
130620
+ const state = syncAndEmitStateChange();
130621
+ lastKnownTime = state.currentTime;
130622
+ persistProgress(state.currentTime);
130623
+ emit2("timeUpdate", state);
130624
+ (_b = (_a = videoOptions.value).onTimeUpdate) == null ? void 0 : _b.call(_a, state);
130625
+ }
130626
+ function handleSeeking() {
130627
+ const video = videoRef.value;
130628
+ if (!video) {
130629
+ return;
130630
+ }
130631
+ if (allowProgrammaticSeek) {
130632
+ allowProgrammaticSeek = false;
130633
+ lastKnownTime = video.currentTime;
130634
+ return;
130635
+ }
130636
+ if (!disableSeek.value) {
130637
+ lastKnownTime = video.currentTime;
130638
+ return;
130639
+ }
130640
+ allowProgrammaticSeek = true;
130641
+ video.currentTime = lastKnownTime;
130642
+ const state = syncAndEmitStateChange();
130643
+ emit2("seekingBlocked", state);
130644
+ }
130645
+ function handleVideoClick() {
130646
+ if (!showCustomControls.value) {
130647
+ return;
130648
+ }
130649
+ void togglePlayback();
130650
+ }
130651
+ function handleProgressInput(event) {
130652
+ const target = event.target;
130653
+ if (!target) {
130654
+ return;
130655
+ }
130656
+ seek(Number.parseFloat(target.value));
130657
+ }
130658
+ function handleVolumeInput(event) {
130659
+ const target = event.target;
130660
+ const video = videoRef.value;
130661
+ if (!target || !video) {
130662
+ return;
130663
+ }
130664
+ const nextVolume = Number.parseFloat(target.value);
130665
+ video.volume = Number.isFinite(nextVolume) ? Math.min(Math.max(nextVolume, 0), 1) : video.volume;
130666
+ video.muted = video.volume === 0;
130667
+ syncAndEmitStateChange();
130668
+ }
130669
+ function toggleMuted() {
130670
+ const video = videoRef.value;
130671
+ if (!video) {
130672
+ return;
130673
+ }
130674
+ video.muted = !video.muted;
130675
+ syncAndEmitStateChange();
130676
+ }
130677
+ function handlePlaybackRateChange(event) {
130678
+ const target = event.target;
130679
+ const video = videoRef.value;
130680
+ if (!target || !video) {
130681
+ return;
130682
+ }
130683
+ const nextRate = Number.parseFloat(target.value);
130684
+ if (!Number.isFinite(nextRate)) {
130685
+ return;
130686
+ }
130687
+ video.playbackRate = nextRate;
130688
+ syncAndEmitStateChange();
130689
+ }
130690
+ function restartVideo() {
130691
+ seek(0);
130692
+ void play();
130693
+ }
130694
+ function setMuted(nextMuted) {
130695
+ if (!videoRef.value) {
130696
+ return;
130697
+ }
130698
+ videoRef.value.muted = nextMuted;
130699
+ syncAndEmitStateChange();
130700
+ }
130701
+ function setVolume(nextVolume) {
130702
+ if (!videoRef.value || !Number.isFinite(nextVolume)) {
130703
+ return;
130704
+ }
130705
+ const safeVolume = Math.min(Math.max(nextVolume, 0), 1);
130706
+ videoRef.value.volume = safeVolume;
130707
+ videoRef.value.muted = safeVolume === 0;
130708
+ syncAndEmitStateChange();
130709
+ }
130710
+ function setPlaybackRate(nextRate) {
130711
+ if (!videoRef.value || !Number.isFinite(nextRate)) {
130712
+ return;
130713
+ }
130714
+ videoRef.value.playbackRate = nextRate;
130715
+ syncAndEmitStateChange();
130716
+ }
129806
130717
  function handleVideoError() {
129807
130718
  loading.value = false;
129808
130719
  error.value = new Error("视频加载失败");
129809
130720
  emit2("error", error.value);
129810
130721
  }
130722
+ async function play() {
130723
+ if (!videoRef.value) {
130724
+ return;
130725
+ }
130726
+ await videoRef.value.play();
130727
+ }
130728
+ function pause() {
130729
+ var _a;
130730
+ (_a = videoRef.value) == null ? void 0 : _a.pause();
130731
+ }
130732
+ async function togglePlayback() {
130733
+ if (!videoRef.value) {
130734
+ return;
130735
+ }
130736
+ if (videoRef.value.paused) {
130737
+ await videoRef.value.play();
130738
+ return;
130739
+ }
130740
+ videoRef.value.pause();
130741
+ }
130742
+ function seek(time) {
130743
+ const video = videoRef.value;
130744
+ if (!video || !Number.isFinite(time)) {
130745
+ return;
130746
+ }
130747
+ const safeTime = Math.min(Math.max(time, 0), Number.isFinite(video.duration) ? video.duration : time);
130748
+ allowProgrammaticSeek = true;
130749
+ video.currentTime = safeTime;
130750
+ lastKnownTime = safeTime;
130751
+ persistProgress(safeTime, true);
130752
+ syncAndEmitStateChange();
130753
+ }
129811
130754
  function formatFileSize(bytes) {
129812
130755
  if (bytes === 0) {
129813
130756
  return "0 B";
@@ -129831,7 +130774,25 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129831
130774
  return [minutes, seconds].map((value) => value.toString().padStart(2, "0")).join(":");
129832
130775
  }
129833
130776
  watch(() => props.source, loadVideo, { immediate: true });
130777
+ watch(() => videoOptions.value.playbackRate, (playbackRate) => {
130778
+ if (videoRef.value && typeof playbackRate === "number" && Number.isFinite(playbackRate)) {
130779
+ videoRef.value.playbackRate = playbackRate;
130780
+ syncPlaybackState();
130781
+ }
130782
+ });
130783
+ __expose({
130784
+ play,
130785
+ pause,
130786
+ togglePlayback,
130787
+ seek,
130788
+ restart: restartVideo,
130789
+ setMuted,
130790
+ setVolume,
130791
+ setPlaybackRate,
130792
+ getState: () => syncPlaybackState()
130793
+ });
129834
130794
  onUnmounted(() => {
130795
+ persistProgress(syncPlaybackState().currentTime, true);
129835
130796
  cleanupObjectUrl();
129836
130797
  });
129837
130798
  return (_ctx, _cache) => {
@@ -129884,24 +130845,99 @@ const _sfc_main$3 = /* @__PURE__ */ defineComponent({
129884
130845
  class: "jv-video-player",
129885
130846
  src: videoSrc.value,
129886
130847
  title: videoName.value,
129887
- controls: "",
130848
+ controls: showNativeControls.value,
130849
+ autoplay: autoplay.value,
130850
+ muted: muted.value,
130851
+ loop: loop.value,
129888
130852
  preload: "metadata",
129889
130853
  playsinline: "",
130854
+ onClick: handleVideoClick,
129890
130855
  onLoadedmetadata: handleLoadedMetadata,
130856
+ onPlay: handlePlay,
130857
+ onPause: handlePause,
130858
+ onEnded: handleEnded,
130859
+ onTimeupdate: handleTimeUpdate,
130860
+ onSeeking: handleSeeking,
129891
130861
  onError: handleVideoError
129892
- }, null, 40, _hoisted_4$2)) : createCommentVNode("", true)
130862
+ }, null, 40, _hoisted_4$2)) : createCommentVNode("", true),
130863
+ videoRef.value && showCustomControls.value ? (openBlock(), createElementBlock("div", {
130864
+ key: 1,
130865
+ class: normalizeClass(["jv-video-controls", { "jv-video-controls--compact": disableSeek.value }])
130866
+ }, [
130867
+ hasCustomControl("playback") ? (openBlock(), createElementBlock("button", {
130868
+ key: 0,
130869
+ type: "button",
130870
+ class: "jv-video-controls__btn",
130871
+ onClick: togglePlayback
130872
+ }, toDisplayString(playbackState.value.paused ? "播放" : "暂停"), 1)) : createCommentVNode("", true),
130873
+ hasCustomControl("restart") ? (openBlock(), createElementBlock("button", {
130874
+ key: 1,
130875
+ type: "button",
130876
+ class: "jv-video-controls__btn jv-video-controls__btn--ghost",
130877
+ onClick: restartVideo
130878
+ }, " 重播 ")) : createCommentVNode("", true),
130879
+ hasCustomControl("progress") ? (openBlock(), createElementBlock("div", _hoisted_5$1, [
130880
+ disableSeek.value ? (openBlock(), createElementBlock("div", _hoisted_6$1, [
130881
+ createBaseVNode("div", {
130882
+ class: "jv-video-controls__progress-fill",
130883
+ style: normalizeStyle({ width: `${progressPercent.value}%` })
130884
+ }, null, 4)
130885
+ ])) : (openBlock(), createElementBlock("input", {
130886
+ key: 1,
130887
+ class: "jv-video-controls__range",
130888
+ type: "range",
130889
+ min: "0",
130890
+ max: rangeMax.value,
130891
+ value: playbackState.value.currentTime,
130892
+ step: "0.1",
130893
+ onInput: handleProgressInput
130894
+ }, null, 40, _hoisted_7$1))
130895
+ ])) : createCommentVNode("", true),
130896
+ hasCustomControl("time") ? (openBlock(), createElementBlock("span", _hoisted_8$1, toDisplayString(formatDuration(playbackState.value.currentTime)) + " / " + toDisplayString(formatDuration(playbackState.value.duration)), 1)) : createCommentVNode("", true),
130897
+ hasCustomControl("mute") ? (openBlock(), createElementBlock("button", {
130898
+ key: 4,
130899
+ type: "button",
130900
+ class: "jv-video-controls__btn jv-video-controls__btn--ghost",
130901
+ onClick: toggleMuted
130902
+ }, toDisplayString(playbackState.value.muted || playbackState.value.volume === 0 ? "静音中" : "声音"), 1)) : createCommentVNode("", true),
130903
+ hasCustomControl("volume") ? (openBlock(), createElementBlock("input", {
130904
+ key: 5,
130905
+ class: "jv-video-controls__volume",
130906
+ type: "range",
130907
+ min: "0",
130908
+ max: "1",
130909
+ step: "0.05",
130910
+ value: playbackState.value.muted ? 0 : playbackState.value.volume,
130911
+ onInput: handleVolumeInput
130912
+ }, null, 40, _hoisted_9)) : createCommentVNode("", true),
130913
+ hasCustomControl("speed") ? (openBlock(), createElementBlock("label", _hoisted_10, [
130914
+ _cache[2] || (_cache[2] = createBaseVNode("span", null, "倍速", -1)),
130915
+ createBaseVNode("select", {
130916
+ value: playbackState.value.playbackRate,
130917
+ onChange: handlePlaybackRateChange
130918
+ }, [
130919
+ (openBlock(), createElementBlock(Fragment, null, renderList(playbackRates, (rate) => {
130920
+ return createBaseVNode("option", {
130921
+ key: rate,
130922
+ value: rate
130923
+ }, toDisplayString(rate) + "x ", 9, _hoisted_12);
130924
+ }), 64))
130925
+ ], 40, _hoisted_11)
130926
+ ])) : createCommentVNode("", true)
130927
+ ], 2)) : createCommentVNode("", true)
129893
130928
  ], 4),
129894
- videoInfo.value ? (openBlock(), createElementBlock("div", _hoisted_5$1, [
130929
+ videoInfo.value ? (openBlock(), createElementBlock("div", _hoisted_13, [
129895
130930
  createBaseVNode("span", null, toDisplayString(videoInfo.value.width) + " × " + toDisplayString(videoInfo.value.height), 1),
129896
130931
  createBaseVNode("span", null, toDisplayString(formatDuration(videoInfo.value.duration)), 1),
129897
- createBaseVNode("span", null, toDisplayString(formatFileSize(videoInfo.value.size)), 1)
130932
+ createBaseVNode("span", null, toDisplayString(formatFileSize(videoInfo.value.size)), 1),
130933
+ createBaseVNode("span", null, toDisplayString(formatDuration(playbackState.value.currentTime)), 1)
129898
130934
  ])) : createCommentVNode("", true)
129899
130935
  ]))
129900
130936
  ], 512);
129901
130937
  };
129902
130938
  }
129903
130939
  });
129904
- const VideoRender = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-39a588be"]]);
130940
+ const VideoRender = /* @__PURE__ */ _export_sfc(_sfc_main$3, [["__scopeId", "data-v-3724591d"]]);
129905
130941
  const _hoisted_1$2 = {
129906
130942
  key: 0,
129907
130943
  class: "jv-cad-error"
@@ -130044,7 +131080,7 @@ const _sfc_main$2 = /* @__PURE__ */ defineComponent({
130044
131080
  if (!dxfHostRef.value) {
130045
131081
  throw new Error("DXF container is not ready");
130046
131082
  }
130047
- const { DxfViewer } = await import("./index-DKpKxg1L.js");
131083
+ const { DxfViewer } = await import("./index-BXB1uz9p.js");
130048
131084
  destroyDxfViewer();
130049
131085
  dxfViewer.value = new DxfViewer(dxfHostRef.value, {
130050
131086
  autoResize: true,
@@ -130452,6 +131488,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130452
131488
  proxyUrl: {},
130453
131489
  requestAdapter: {},
130454
131490
  cad: {},
131491
+ video: {},
130455
131492
  onReady: {},
130456
131493
  onError: {},
130457
131494
  onLoad: {},
@@ -130466,6 +131503,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130466
131503
  const viewerRef = /* @__PURE__ */ ref();
130467
131504
  const contentRef = /* @__PURE__ */ ref();
130468
131505
  const ofdRenderRef = /* @__PURE__ */ ref(null);
131506
+ const videoRenderRef = /* @__PURE__ */ ref(null);
130469
131507
  const brandingRef = /* @__PURE__ */ ref();
130470
131508
  let viewerRoot = null;
130471
131509
  let copyrightObserver = null;
@@ -130507,6 +131545,17 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130507
131545
  const showToolbar = computed(() => props.toolbar !== false);
130508
131546
  const pdfRenderMode = computed(() => props.pdfRender ?? "inset");
130509
131547
  const cadOptions = computed(() => props.cad);
131548
+ const videoOptions = computed(() => props.video);
131549
+ const showToolbarVideoControls = computed(() => {
131550
+ var _a2;
131551
+ if (fileType.value !== "video" || props.toolbar === false) {
131552
+ return false;
131553
+ }
131554
+ if (props.toolbar === true || props.toolbar === void 0) {
131555
+ return true;
131556
+ }
131557
+ return ((_a2 = props.toolbar.items) == null ? void 0 : _a2.some((item) => item.type === "video")) ?? false;
131558
+ });
130510
131559
  const toolbarConfig = computed(() => {
130511
131560
  if (props.toolbar === true || props.toolbar === void 0) {
130512
131561
  return void 0;
@@ -130525,6 +131574,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130525
131574
  function handleLoad() {
130526
131575
  var _a2;
130527
131576
  setLoading(false);
131577
+ if (fileType.value === "video") {
131578
+ updateVideoState(getVideoState());
131579
+ }
130528
131580
  emit2("load");
130529
131581
  events.emit("load");
130530
131582
  (_a2 = props.onLoad) == null ? void 0 : _a2.call(props);
@@ -130539,6 +131591,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130539
131591
  function handleOfdPageChange(pageInfo) {
130540
131592
  state.setPage(pageInfo.current, pageInfo.total);
130541
131593
  }
131594
+ function updateVideoState(nextState) {
131595
+ state.setVideoState(nextState);
131596
+ }
131597
+ function handleVideoPlay(nextState) {
131598
+ updateVideoState(nextState);
131599
+ events.emit("video:play", nextState);
131600
+ }
131601
+ function handleVideoStateChange(nextState) {
131602
+ updateVideoState(nextState);
131603
+ }
131604
+ function handleVideoPause(nextState) {
131605
+ updateVideoState(nextState);
131606
+ events.emit("video:pause", nextState);
131607
+ }
131608
+ function handleVideoEnded(nextState) {
131609
+ updateVideoState(nextState);
131610
+ events.emit("video:ended", nextState);
131611
+ }
131612
+ function handleVideoTimeUpdate(nextState) {
131613
+ updateVideoState(nextState);
131614
+ events.emit("video:timeupdate", nextState);
131615
+ }
131616
+ function handleVideoSeekingBlocked(nextState) {
131617
+ updateVideoState(nextState);
131618
+ events.emit("video:seeking-blocked", nextState);
131619
+ }
130542
131620
  function syncPageController() {
130543
131621
  if (fileType.value !== "ofd") {
130544
131622
  state.setPageController(null);
@@ -130563,6 +131641,52 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130563
131641
  }
130564
131642
  });
130565
131643
  }
131644
+ function syncVideoController() {
131645
+ if (fileType.value !== "video") {
131646
+ state.setVideoController(null);
131647
+ return;
131648
+ }
131649
+ state.setVideoController({
131650
+ play: () => {
131651
+ var _a2, _b2;
131652
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.play) == null ? void 0 : _b2.call(_a2);
131653
+ },
131654
+ pause: () => {
131655
+ var _a2, _b2;
131656
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.pause) == null ? void 0 : _b2.call(_a2);
131657
+ },
131658
+ togglePlayback: () => {
131659
+ var _a2, _b2;
131660
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.togglePlayback) == null ? void 0 : _b2.call(_a2);
131661
+ },
131662
+ seek: (time) => {
131663
+ var _a2, _b2;
131664
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.seek) == null ? void 0 : _b2.call(_a2, time);
131665
+ },
131666
+ restart: () => {
131667
+ var _a2, _b2;
131668
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.restart) == null ? void 0 : _b2.call(_a2);
131669
+ },
131670
+ setMuted: (muted) => {
131671
+ var _a2, _b2;
131672
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.setMuted) == null ? void 0 : _b2.call(_a2, muted);
131673
+ },
131674
+ setVolume: (volume) => {
131675
+ var _a2, _b2;
131676
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.setVolume) == null ? void 0 : _b2.call(_a2, volume);
131677
+ },
131678
+ setPlaybackRate: (rate) => {
131679
+ var _a2, _b2;
131680
+ return (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.setPlaybackRate) == null ? void 0 : _b2.call(_a2, rate);
131681
+ }
131682
+ });
131683
+ }
131684
+ function getVideoState() {
131685
+ var _a2, _b2;
131686
+ const nextState = ((_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.getState) == null ? void 0 : _b2.call(_a2)) || state.videoState.value || null;
131687
+ updateVideoState(nextState);
131688
+ return nextState;
131689
+ }
130566
131690
  function resolveViewerRoot() {
130567
131691
  var _a2;
130568
131692
  if (viewerRoot && document.body.contains(viewerRoot)) {
@@ -130840,6 +131964,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130840
131964
  try {
130841
131965
  setLoading(true);
130842
131966
  setError(null);
131967
+ updateVideoState(null);
130843
131968
  setFile(file, filename2, type);
130844
131969
  } catch (err) {
130845
131970
  handleError2(err);
@@ -130860,6 +131985,7 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130860
131985
  }
130861
131986
  });
130862
131987
  watch(fileType, syncPageController, { immediate: true });
131988
+ watch(fileType, syncVideoController, { immediate: true });
130863
131989
  onMounted(() => {
130864
131990
  var _a2;
130865
131991
  state.setPrintFn(() => {
@@ -130880,6 +132006,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130880
132006
  onUnmounted(() => {
130881
132007
  stopCopyrightProtection();
130882
132008
  state.setPageController(null);
132009
+ state.setVideoController(null);
132010
+ updateVideoState(null);
130883
132011
  destroy();
130884
132012
  });
130885
132013
  __expose({
@@ -130914,6 +132042,23 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130914
132042
  await downloadFile2(fileSource.value, state.filename.value);
130915
132043
  }
130916
132044
  },
132045
+ playVideo: async () => {
132046
+ var _a2, _b2;
132047
+ await ((_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.play) == null ? void 0 : _b2.call(_a2));
132048
+ },
132049
+ pauseVideo: () => {
132050
+ var _a2, _b2;
132051
+ (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.pause) == null ? void 0 : _b2.call(_a2);
132052
+ },
132053
+ toggleVideoPlayback: async () => {
132054
+ var _a2, _b2;
132055
+ await ((_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.togglePlayback) == null ? void 0 : _b2.call(_a2));
132056
+ },
132057
+ seekVideo: (time) => {
132058
+ var _a2, _b2;
132059
+ (_b2 = (_a2 = videoRenderRef.value) == null ? void 0 : _a2.seek) == null ? void 0 : _b2.call(_a2, time);
132060
+ },
132061
+ getVideoState,
130917
132062
  setTheme,
130918
132063
  setLocale,
130919
132064
  setToolbar: (config) => {
@@ -130935,8 +132080,9 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
130935
132080
  showToolbar.value ? (openBlock(), createBlock(Toolbar, {
130936
132081
  key: 0,
130937
132082
  config: toolbarConfig.value,
130938
- visible: toolbarVisible.value
130939
- }, null, 8, ["config", "visible"])) : createCommentVNode("", true),
132083
+ visible: toolbarVisible.value,
132084
+ "video-options": videoOptions.value
132085
+ }, null, 8, ["config", "visible", "video-options"])) : createCommentVNode("", true),
130940
132086
  createBaseVNode("div", {
130941
132087
  ref_key: "contentRef",
130942
132088
  ref: contentRef,
@@ -131065,13 +132211,23 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
131065
132211
  onError: handleError2
131066
132212
  }, null, 8, ["source", "zoom"])) : unref(fileType) === "video" ? (openBlock(), createBlock(unref(VideoRender), {
131067
132213
  key: 10,
132214
+ ref_key: "videoRenderRef",
132215
+ ref: videoRenderRef,
131068
132216
  source: unref(fileSource),
131069
132217
  zoom: unref(zoom),
131070
132218
  "proxy-url": proxyUrl.value,
131071
132219
  "request-adapter": requestAdapter.value,
132220
+ "video-options": videoOptions.value,
132221
+ "prefer-external-controls": showToolbarVideoControls.value,
131072
132222
  onLoad: handleLoad,
131073
- onError: handleError2
131074
- }, null, 8, ["source", "zoom", "proxy-url", "request-adapter"])) : unref(fileType) === "cad" ? (openBlock(), createBlock(unref(CadRender), {
132223
+ onError: handleError2,
132224
+ onStateChange: handleVideoStateChange,
132225
+ onPlay: handleVideoPlay,
132226
+ onPause: handleVideoPause,
132227
+ onEnded: handleVideoEnded,
132228
+ onTimeUpdate: handleVideoTimeUpdate,
132229
+ onSeekingBlocked: handleVideoSeekingBlocked
132230
+ }, null, 8, ["source", "zoom", "proxy-url", "request-adapter", "video-options", "prefer-external-controls"])) : unref(fileType) === "cad" ? (openBlock(), createBlock(unref(CadRender), {
131075
132231
  key: 11,
131076
132232
  source: unref(fileSource),
131077
132233
  filename: unref(filename),
@@ -131109,17 +132265,32 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
131109
132265
  };
131110
132266
  }
131111
132267
  });
131112
- const Viewer = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-e261aa6d"]]);
132268
+ const Viewer = /* @__PURE__ */ _export_sfc(_sfc_main, [["__scopeId", "data-v-77e0f7de"]]);
131113
132269
  function createViewer(options) {
131114
132270
  const events = createEventBus();
131115
132271
  let app = null;
131116
132272
  let container = null;
131117
132273
  let viewerComponent = null;
131118
132274
  const runtimeOptions = /* @__PURE__ */ reactive({ ...options });
132275
+ const listenerRegistry = /* @__PURE__ */ new Map();
132276
+ const lifecycleEvents = /* @__PURE__ */ new Set(["ready", "load", "error", "destroy"]);
131119
132277
  const updateOptions = async (nextOptions) => {
131120
132278
  Object.assign(runtimeOptions, nextOptions);
131121
132279
  await nextTick();
131122
132280
  };
132281
+ const bindCustomEventListeners = () => {
132282
+ if (!(viewerComponent == null ? void 0 : viewerComponent.on)) {
132283
+ return;
132284
+ }
132285
+ listenerRegistry.forEach((handlers, event) => {
132286
+ if (lifecycleEvents.has(event)) {
132287
+ return;
132288
+ }
132289
+ handlers.forEach((handler) => {
132290
+ viewerComponent.on(event, handler);
132291
+ });
132292
+ });
132293
+ };
131123
132294
  const mergedOptions = {
131124
132295
  ...runtimeOptions,
131125
132296
  onReady: () => {
@@ -131165,6 +132336,8 @@ function createViewer(options) {
131165
132336
  }
131166
132337
  });
131167
132338
  app.mount(container);
132339
+ await nextTick();
132340
+ bindCustomEventListeners();
131168
132341
  return Promise.resolve();
131169
132342
  },
131170
132343
  destroy() {
@@ -131228,6 +132401,26 @@ function createViewer(options) {
131228
132401
  await downloadFile(file.source, file.filename);
131229
132402
  }
131230
132403
  },
132404
+ async playVideo() {
132405
+ var _a;
132406
+ await ((_a = viewerComponent == null ? void 0 : viewerComponent.playVideo) == null ? void 0 : _a.call(viewerComponent));
132407
+ },
132408
+ pauseVideo() {
132409
+ var _a;
132410
+ (_a = viewerComponent == null ? void 0 : viewerComponent.pauseVideo) == null ? void 0 : _a.call(viewerComponent);
132411
+ },
132412
+ async toggleVideoPlayback() {
132413
+ var _a;
132414
+ await ((_a = viewerComponent == null ? void 0 : viewerComponent.toggleVideoPlayback) == null ? void 0 : _a.call(viewerComponent));
132415
+ },
132416
+ seekVideo(time) {
132417
+ var _a;
132418
+ (_a = viewerComponent == null ? void 0 : viewerComponent.seekVideo) == null ? void 0 : _a.call(viewerComponent, time);
132419
+ },
132420
+ getVideoState() {
132421
+ var _a;
132422
+ return ((_a = viewerComponent == null ? void 0 : viewerComponent.getVideoState) == null ? void 0 : _a.call(viewerComponent)) || null;
132423
+ },
131231
132424
  setTheme(theme) {
131232
132425
  updateOptions({ theme });
131233
132426
  },
@@ -131238,10 +132431,26 @@ function createViewer(options) {
131238
132431
  updateOptions({ toolbar: config });
131239
132432
  },
131240
132433
  on(event, handler) {
132434
+ var _a;
131241
132435
  events.on(event, handler);
132436
+ if (!listenerRegistry.has(event)) {
132437
+ listenerRegistry.set(event, /* @__PURE__ */ new Set());
132438
+ }
132439
+ listenerRegistry.get(event).add(handler);
132440
+ if (!lifecycleEvents.has(event)) {
132441
+ (_a = viewerComponent == null ? void 0 : viewerComponent.on) == null ? void 0 : _a.call(viewerComponent, event, handler);
132442
+ }
131242
132443
  },
131243
132444
  off(event, handler) {
132445
+ var _a, _b, _c;
131244
132446
  events.off(event, handler);
132447
+ (_a = listenerRegistry.get(event)) == null ? void 0 : _a.delete(handler);
132448
+ if (((_b = listenerRegistry.get(event)) == null ? void 0 : _b.size) === 0) {
132449
+ listenerRegistry.delete(event);
132450
+ }
132451
+ if (!lifecycleEvents.has(event)) {
132452
+ (_c = viewerComponent == null ? void 0 : viewerComponent.off) == null ? void 0 : _c.call(viewerComponent, event, handler);
132453
+ }
131245
132454
  },
131246
132455
  getState() {
131247
132456
  var _a;
@@ -131254,7 +132463,8 @@ function createViewer(options) {
131254
132463
  zoom: 1,
131255
132464
  rotate: 0,
131256
132465
  page: { current: 1, total: 1 },
131257
- fullscreen: false
132466
+ fullscreen: false,
132467
+ video: null
131258
132468
  };
131259
132469
  }
131260
132470
  };