superdoc 2.18.1-next.5 → 2.19.0-next.10
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.
- package/dist/chunks/{create-super-doc-ui-C3HDE1IE.es.js → create-super-doc-ui-CSZSAgxc.cjs} +1454 -1
- package/dist/chunks/{create-super-doc-ui-Gxk1m05U.cjs → create-super-doc-ui-DMe-GQEe.es.js} +1376 -66
- package/dist/chunks/pdf.worker.min-BgWCk_Cj.cjs +4 -0
- package/dist/chunks/pdf.worker.min-t-CYmkGJ.es.js +4 -0
- package/dist/collaboration-upgrade-engine.cjs +1 -1
- package/dist/collaboration-upgrade-engine.es.js +1 -1
- package/dist/document-api/src/contract/command-catalog.d.ts +1 -1
- package/dist/document-api/src/contract/metadata-types.d.ts +1 -1
- package/dist/document-api/src/contract/operation-definitions.d.ts +18 -0
- package/dist/document-api/src/diff/diff.types.d.ts +9 -1
- package/dist/document-api/src/diff/index.d.ts +1 -1
- package/dist/document-api/src/index.d.ts +4 -3
- package/dist/document-api/src/selection/selection.d.ts +6 -2
- package/dist/document-api/src/selection/selection.types.d.ts +75 -0
- package/dist/document-api/src/types/track-changes.types.d.ts +35 -2
- package/dist/document-api/src/validation-primitives.d.ts +1 -1
- package/dist/document-api/src/watermarks/watermarks.d.ts +4 -1
- package/dist/document-api/src/watermarks/watermarks.types.d.ts +34 -0
- package/dist/layout-engine/contracts/src/index.d.ts +15 -0
- package/dist/layout-engine/contracts/src/resolved-layout.d.ts +3 -1
- package/dist/layout-engine/painters/dom/src/index.d.ts +2 -0
- package/dist/layout-engine/painters/dom/src/runs/tab-run.d.ts +1 -1
- package/dist/public/ui-react.cjs +1 -1
- package/dist/public/ui-react.es.js +1 -1
- package/dist/public/ui-vue.cjs +1 -1
- package/dist/public/ui-vue.es.js +1 -1
- package/dist/public/ui.cjs +1 -1
- package/dist/public/ui.es.js +1 -1
- package/dist/style.css +618 -102
- package/dist/style.layered.css +619 -103
- package/dist/superdoc/src/components/surfaces/WatermarkSurface.vue.d.ts +16 -0
- package/dist/superdoc/src/components/surfaces/watermark-surface-runtime.d.ts +8 -0
- package/dist/superdoc/src/core/SuperDoc.d.ts +8 -7
- package/dist/superdoc/src/core/types/index.d.ts +36 -18
- package/dist/superdoc/src/internal/toolbar/built-in/OverflowMenu.vue.d.ts +93 -1
- package/dist/superdoc/src/internal/toolbar/built-in/Toolbar.vue.d.ts +3 -1
- package/dist/superdoc/src/internal/toolbar/built-in/ToolbarDropdown.vue.d.ts +1 -0
- package/dist/superdoc/src/internal/toolbar/built-in/toolbarIcons.d.ts +1 -0
- package/dist/superdoc/src/internal/toolbar/built-in/toolbarTexts.d.ts +1 -0
- package/dist/superdoc/src/internal/toolbar/built-in-toolbar.d.ts +3 -0
- package/dist/superdoc/src/public/ui/types.d.ts +10 -1
- package/dist/superdoc/src/public/ui/watermark-controller.d.ts +32 -0
- package/dist/superdoc/src/public/ui/watermark-dialog-state.d.ts +66 -0
- package/dist/superdoc/src/public/ui/watermark-draft.d.ts +6 -0
- package/dist/superdoc/src/public/ui.d.cts +12 -0
- package/dist/superdoc/src/public/ui.d.ts +1 -1
- package/dist/superdoc.cjs +116 -176
- package/dist/superdoc.es.js +114 -174
- package/dist-cdn/style.layered.css +1 -1
- package/dist-cdn/superdoc.min.css +1 -1
- package/dist-cdn/superdoc.min.js +38 -37
- package/package.json +3 -2
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
const require__plugin_vue_export_helper = require("./_plugin-vue_export-helper-SDR04tiH.cjs");
|
|
2
|
+
let vue = require("vue");
|
|
1
3
|
//#region src/internal/diagnostics/interaction-history.ts
|
|
2
4
|
var recorders = /* @__PURE__ */ new WeakMap();
|
|
3
5
|
var nextSession = 0;
|
|
@@ -534,6 +536,1311 @@ function shallowEqual(a, b) {
|
|
|
534
536
|
return true;
|
|
535
537
|
}
|
|
536
538
|
//#endregion
|
|
539
|
+
//#region src/internal/toolbar/image-upload.js
|
|
540
|
+
/**
|
|
541
|
+
* Interactive image acquisition for the built-in toolbar (SD-3567).
|
|
542
|
+
*
|
|
543
|
+
* The toolbar image button routes through the shared controller command
|
|
544
|
+
* `image` → `create.image`, which requires a base64 PNG/JPEG data-URI `src`.
|
|
545
|
+
* This module owns the browser file picker and the File → data-URI
|
|
546
|
+
* conversion; the toolbar dispatches the resulting payload through the
|
|
547
|
+
* normal controller command path.
|
|
548
|
+
*/
|
|
549
|
+
/** Accept filter for the picker: PNG and JPEG only (V1 parity; OOXML-native formats). */
|
|
550
|
+
var IMAGE_PICKER_ACCEPT = ".png,.jpg,.jpeg,image/png,image/jpeg";
|
|
551
|
+
var SUPPORTED_IMAGE_MIME_TYPES = /* @__PURE__ */ new Set([
|
|
552
|
+
"image/png",
|
|
553
|
+
"image/jpeg",
|
|
554
|
+
"image/jpg"
|
|
555
|
+
]);
|
|
556
|
+
var SUPPORTED_IMAGE_EXTENSIONS = /\.(png|jpe?g)$/i;
|
|
557
|
+
/**
|
|
558
|
+
* Whether a picked/dropped file is an insertable image (PNG/JPEG). Falls back
|
|
559
|
+
* to the file extension when the browser reports no MIME type.
|
|
560
|
+
* @param {File | null | undefined} file
|
|
561
|
+
* @returns {boolean}
|
|
562
|
+
*/
|
|
563
|
+
function isSupportedImageFile(file) {
|
|
564
|
+
if (!file) return false;
|
|
565
|
+
const type = typeof file.type === "string" ? file.type.toLowerCase() : "";
|
|
566
|
+
if (type) return SUPPORTED_IMAGE_MIME_TYPES.has(type);
|
|
567
|
+
return SUPPORTED_IMAGE_EXTENSIONS.test(String(file.name ?? ""));
|
|
568
|
+
}
|
|
569
|
+
/**
|
|
570
|
+
* Read a File/Blob into a base64 data URI.
|
|
571
|
+
*
|
|
572
|
+
* Some browsers/OSes deliver picked files with an empty `type`; the picker
|
|
573
|
+
* accepts those by extension, but `readAsDataURL` would then produce an
|
|
574
|
+
* `application/octet-stream` data URI that `create.image` rejects. Rewrite
|
|
575
|
+
* the media type from the filename so extension-accepted files still insert.
|
|
576
|
+
* @param {Blob & { name?: string }} file
|
|
577
|
+
* @returns {Promise<string>}
|
|
578
|
+
*/
|
|
579
|
+
function fileToDataUri(file) {
|
|
580
|
+
return new Promise((resolve, reject) => {
|
|
581
|
+
const reader = new FileReader();
|
|
582
|
+
reader.onload = () => resolve(normalizeImageDataUri(String(reader.result), file));
|
|
583
|
+
reader.onerror = () => reject(reader.error ?? /* @__PURE__ */ new Error("image-read-failed"));
|
|
584
|
+
reader.readAsDataURL(file);
|
|
585
|
+
});
|
|
586
|
+
}
|
|
587
|
+
/**
|
|
588
|
+
* Ensure a data URI read from a supported file carries a PNG/JPEG media type.
|
|
589
|
+
* Leaves URIs already typed as a supported image (or uninferable ones) alone.
|
|
590
|
+
* @param {string} dataUri
|
|
591
|
+
* @param {(Blob & { name?: string }) | null | undefined} file
|
|
592
|
+
* @returns {string}
|
|
593
|
+
*/
|
|
594
|
+
function normalizeImageDataUri(dataUri, file) {
|
|
595
|
+
const match = /^data:([^;,]*);base64,/.exec(dataUri);
|
|
596
|
+
if (!match) return dataUri;
|
|
597
|
+
const mime = match[1].toLowerCase();
|
|
598
|
+
if (SUPPORTED_IMAGE_MIME_TYPES.has(mime)) return dataUri;
|
|
599
|
+
const name = String(file?.name ?? "");
|
|
600
|
+
const inferred = /\.jpe?g$/i.test(name) ? "image/jpeg" : /\.png$/i.test(name) ? "image/png" : null;
|
|
601
|
+
if (!inferred) return dataUri;
|
|
602
|
+
return `data:${inferred};base64,${dataUri.slice(match[0].length)}`;
|
|
603
|
+
}
|
|
604
|
+
/**
|
|
605
|
+
* Resolve the `create.image` src for a picked file. Uses the consumer's
|
|
606
|
+
* `handleImageUpload` callback when configured (V1 contract:
|
|
607
|
+
* `(file: File) => Promise<string>`). A returned non-data URL is fetched and
|
|
608
|
+
* embedded, because `create.image` requires an embedded base64 data URI.
|
|
609
|
+
* @param {File} file
|
|
610
|
+
* @param {((file: File) => Promise<string>) | null | undefined} handleImageUpload
|
|
611
|
+
* @returns {Promise<string>}
|
|
612
|
+
*/
|
|
613
|
+
async function resolveImageSrc(file, handleImageUpload) {
|
|
614
|
+
if (typeof handleImageUpload === "function") {
|
|
615
|
+
const result = await handleImageUpload(file);
|
|
616
|
+
if (typeof result !== "string" || result.trim() === "") throw new Error("handleImageUpload returned an empty result");
|
|
617
|
+
if (result.startsWith("data:")) return result;
|
|
618
|
+
return embedRemoteImage(result, file);
|
|
619
|
+
}
|
|
620
|
+
return fileToDataUri(file);
|
|
621
|
+
}
|
|
622
|
+
/**
|
|
623
|
+
* Fetch a remote image URL and embed it as a data URI. Object-store /
|
|
624
|
+
* presigned URLs often respond `application/octet-stream`, so keep a filename
|
|
625
|
+
* hint (URL path, falling back to the originally picked file) for the media
|
|
626
|
+
* type normalization in `fileToDataUri`.
|
|
627
|
+
* @param {string} url
|
|
628
|
+
* @param {File | null | undefined} pickedFile
|
|
629
|
+
* @returns {Promise<string>}
|
|
630
|
+
*/
|
|
631
|
+
async function embedRemoteImage(url, pickedFile) {
|
|
632
|
+
const response = await fetch(url);
|
|
633
|
+
if (!response.ok) throw new Error(`image fetch failed: ${response.status}`);
|
|
634
|
+
const blob = await response.blob();
|
|
635
|
+
const name = (/\.(?:png|jpe?g)(?:$|[?#])/i.test(url) ? url.split(/[?#]/)[0] : "") || pickedFile?.name || "";
|
|
636
|
+
return fileToDataUri(name ? Object.assign(blob, { name }) : blob);
|
|
637
|
+
}
|
|
638
|
+
/**
|
|
639
|
+
* Hidden `<input type=file>` picker bound to one toolbar instance. The input
|
|
640
|
+
* stays attached (hidden) so automation and tests can drive it; `destroy()`
|
|
641
|
+
* removes it. Picking a file calls `onPick(file)`; an unsupported type or a
|
|
642
|
+
* failed pick routes through `onError(error)`.
|
|
643
|
+
*
|
|
644
|
+
* @param {{
|
|
645
|
+
* ownerDocument?: Document,
|
|
646
|
+
* onPick?: (file: File) => unknown,
|
|
647
|
+
* onError?: (error: Error) => void,
|
|
648
|
+
* }} options
|
|
649
|
+
* @returns {{ input: HTMLInputElement, open: () => void, destroy: () => void }}
|
|
650
|
+
*/
|
|
651
|
+
function createImageFilePicker({ ownerDocument = document, onPick, onError } = {}) {
|
|
652
|
+
const input = ownerDocument.createElement("input");
|
|
653
|
+
input.type = "file";
|
|
654
|
+
input.accept = IMAGE_PICKER_ACCEPT;
|
|
655
|
+
input.hidden = true;
|
|
656
|
+
input.tabIndex = -1;
|
|
657
|
+
input.setAttribute("data-superdoc-image-picker", "true");
|
|
658
|
+
input.setAttribute("aria-hidden", "true");
|
|
659
|
+
input.addEventListener("change", () => {
|
|
660
|
+
const file = input.files && input.files[0];
|
|
661
|
+
input.value = "";
|
|
662
|
+
if (!file) return;
|
|
663
|
+
if (!isSupportedImageFile(file)) {
|
|
664
|
+
onError?.(/* @__PURE__ */ new Error(`unsupported image type: ${file.type || file.name}`));
|
|
665
|
+
return;
|
|
666
|
+
}
|
|
667
|
+
try {
|
|
668
|
+
const result = onPick?.(file);
|
|
669
|
+
if (result && typeof result.then === "function") result.catch((error) => onError?.(error));
|
|
670
|
+
} catch (error) {
|
|
671
|
+
onError?.(error);
|
|
672
|
+
}
|
|
673
|
+
});
|
|
674
|
+
ownerDocument.body?.appendChild(input);
|
|
675
|
+
return {
|
|
676
|
+
input,
|
|
677
|
+
open() {
|
|
678
|
+
input.click();
|
|
679
|
+
},
|
|
680
|
+
destroy() {
|
|
681
|
+
input.remove();
|
|
682
|
+
}
|
|
683
|
+
};
|
|
684
|
+
}
|
|
685
|
+
//#endregion
|
|
686
|
+
//#region src/components/surfaces/WatermarkSurface.vue?vue&type=script&setup=true&lang.ts
|
|
687
|
+
var _hoisted_1 = { class: "sd-watermark__body" };
|
|
688
|
+
var _hoisted_2 = { class: "sd-watermark__settings" };
|
|
689
|
+
var _hoisted_3 = ["disabled"];
|
|
690
|
+
var _hoisted_4 = { class: "sd-watermark__field" };
|
|
691
|
+
var _hoisted_5 = ["value"];
|
|
692
|
+
var _hoisted_6 = ["value"];
|
|
693
|
+
var _hoisted_7 = { class: "sd-watermark__field" };
|
|
694
|
+
var _hoisted_8 = ["value"];
|
|
695
|
+
var _hoisted_9 = ["disabled"];
|
|
696
|
+
var _hoisted_10 = { class: "sd-watermark__selection-list" };
|
|
697
|
+
var _hoisted_11 = [
|
|
698
|
+
"value",
|
|
699
|
+
"checked",
|
|
700
|
+
"onChange"
|
|
701
|
+
];
|
|
702
|
+
var _hoisted_12 = ["disabled"];
|
|
703
|
+
var _hoisted_13 = {
|
|
704
|
+
key: 0,
|
|
705
|
+
class: "sd-watermark__notice"
|
|
706
|
+
};
|
|
707
|
+
var _hoisted_14 = {
|
|
708
|
+
key: 1,
|
|
709
|
+
class: "sd-watermark__notice"
|
|
710
|
+
};
|
|
711
|
+
var _hoisted_15 = ["disabled"];
|
|
712
|
+
var _hoisted_16 = { class: "sd-watermark__types" };
|
|
713
|
+
var _hoisted_17 = [
|
|
714
|
+
"name",
|
|
715
|
+
"value",
|
|
716
|
+
"checked",
|
|
717
|
+
"onChange"
|
|
718
|
+
];
|
|
719
|
+
var _hoisted_18 = { class: "sd-watermark__field" };
|
|
720
|
+
var _hoisted_19 = ["value"];
|
|
721
|
+
var _hoisted_20 = {
|
|
722
|
+
class: "sd-watermark__presets",
|
|
723
|
+
"aria-label": "Text presets"
|
|
724
|
+
};
|
|
725
|
+
var _hoisted_21 = ["onClick"];
|
|
726
|
+
var _hoisted_22 = { class: "sd-watermark__font-row" };
|
|
727
|
+
var _hoisted_23 = { class: "sd-watermark__field" };
|
|
728
|
+
var _hoisted_24 = ["value"];
|
|
729
|
+
var _hoisted_25 = ["value"];
|
|
730
|
+
var _hoisted_26 = { class: "sd-watermark__field sd-watermark__size" };
|
|
731
|
+
var _hoisted_27 = ["list", "value"];
|
|
732
|
+
var _hoisted_28 = ["id"];
|
|
733
|
+
var _hoisted_29 = ["value"];
|
|
734
|
+
var _hoisted_30 = { class: "sd-watermark__styles" };
|
|
735
|
+
var _hoisted_31 = ["aria-pressed"];
|
|
736
|
+
var _hoisted_32 = ["aria-pressed"];
|
|
737
|
+
var _hoisted_33 = { class: "sd-watermark__field sd-watermark__font-color" };
|
|
738
|
+
var _hoisted_34 = { class: "sd-watermark__color" };
|
|
739
|
+
var _hoisted_35 = ["value"];
|
|
740
|
+
var _hoisted_36 = ["value"];
|
|
741
|
+
var _hoisted_37 = { class: "sd-watermark__picture" };
|
|
742
|
+
var _hoisted_38 = ["src"];
|
|
743
|
+
var _hoisted_39 = ["accept"];
|
|
744
|
+
var _hoisted_40 = { class: "sd-watermark__field" };
|
|
745
|
+
var _hoisted_41 = ["value"];
|
|
746
|
+
var _hoisted_42 = {
|
|
747
|
+
key: 0,
|
|
748
|
+
value: "custom",
|
|
749
|
+
disabled: ""
|
|
750
|
+
};
|
|
751
|
+
var _hoisted_43 = ["value"];
|
|
752
|
+
var _hoisted_44 = { class: "sd-watermark__check" };
|
|
753
|
+
var _hoisted_45 = ["checked"];
|
|
754
|
+
var _hoisted_46 = { class: "sd-watermark__check" };
|
|
755
|
+
var _hoisted_47 = ["checked"];
|
|
756
|
+
var _hoisted_48 = {
|
|
757
|
+
key: 2,
|
|
758
|
+
class: "sd-watermark__field sd-watermark__transparency"
|
|
759
|
+
};
|
|
760
|
+
var _hoisted_49 = ["for"];
|
|
761
|
+
var _hoisted_50 = { class: "sd-watermark__range" };
|
|
762
|
+
var _hoisted_51 = ["id", "value"];
|
|
763
|
+
var _hoisted_52 = ["value"];
|
|
764
|
+
var _hoisted_53 = {
|
|
765
|
+
key: 3,
|
|
766
|
+
class: "sd-watermark__orientation"
|
|
767
|
+
};
|
|
768
|
+
var _hoisted_54 = [
|
|
769
|
+
"name",
|
|
770
|
+
"value",
|
|
771
|
+
"checked",
|
|
772
|
+
"onChange"
|
|
773
|
+
];
|
|
774
|
+
var _hoisted_55 = {
|
|
775
|
+
key: 4,
|
|
776
|
+
class: "sd-watermark__notice"
|
|
777
|
+
};
|
|
778
|
+
var _hoisted_56 = {
|
|
779
|
+
key: 5,
|
|
780
|
+
class: "sd-watermark__notice"
|
|
781
|
+
};
|
|
782
|
+
var _hoisted_57 = ["aria-busy"];
|
|
783
|
+
var _hoisted_58 = { class: "sd-watermark__page" };
|
|
784
|
+
var _hoisted_59 = [
|
|
785
|
+
"src",
|
|
786
|
+
"width",
|
|
787
|
+
"height"
|
|
788
|
+
];
|
|
789
|
+
var _hoisted_60 = { key: 1 };
|
|
790
|
+
var _hoisted_61 = { class: "sd-watermark__impact" };
|
|
791
|
+
var _hoisted_62 = {
|
|
792
|
+
key: 0,
|
|
793
|
+
class: "sd-watermark__impact-details"
|
|
794
|
+
};
|
|
795
|
+
var _hoisted_63 = {
|
|
796
|
+
key: 0,
|
|
797
|
+
class: "sd-watermark__error",
|
|
798
|
+
role: "alert"
|
|
799
|
+
};
|
|
800
|
+
var _hoisted_64 = ["disabled"];
|
|
801
|
+
var _hoisted_65 = { class: "sd-watermark__footer sd-dialog-footer" };
|
|
802
|
+
var _hoisted_66 = {
|
|
803
|
+
role: "status",
|
|
804
|
+
"aria-live": "polite"
|
|
805
|
+
};
|
|
806
|
+
var _hoisted_67 = { class: "sd-watermark__actions" };
|
|
807
|
+
var _hoisted_68 = ["disabled"];
|
|
808
|
+
var WatermarkSurface_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ (0, vue.defineComponent)({
|
|
809
|
+
__name: "WatermarkSurface",
|
|
810
|
+
props: {
|
|
811
|
+
model: {},
|
|
812
|
+
surfaceId: { default: "" },
|
|
813
|
+
mode: {},
|
|
814
|
+
request: {},
|
|
815
|
+
resolve: {},
|
|
816
|
+
close: {
|
|
817
|
+
type: Function,
|
|
818
|
+
default: () => {}
|
|
819
|
+
}
|
|
820
|
+
},
|
|
821
|
+
setup(__props) {
|
|
822
|
+
const props = __props;
|
|
823
|
+
const snapshot = (0, vue.shallowRef)(props.model.getSnapshot());
|
|
824
|
+
const fileInput = (0, vue.ref)(null);
|
|
825
|
+
const filePending = (0, vue.ref)(false);
|
|
826
|
+
const localError = (0, vue.ref)("");
|
|
827
|
+
let fileGeneration = 0;
|
|
828
|
+
let unsubscribe;
|
|
829
|
+
const presets = [
|
|
830
|
+
"DRAFT",
|
|
831
|
+
"CONFIDENTIAL",
|
|
832
|
+
"DO NOT COPY"
|
|
833
|
+
];
|
|
834
|
+
const types = [
|
|
835
|
+
{
|
|
836
|
+
value: "none",
|
|
837
|
+
label: "No watermark"
|
|
838
|
+
},
|
|
839
|
+
{
|
|
840
|
+
value: "text",
|
|
841
|
+
label: "Text"
|
|
842
|
+
},
|
|
843
|
+
{
|
|
844
|
+
value: "picture",
|
|
845
|
+
label: "Picture"
|
|
846
|
+
}
|
|
847
|
+
];
|
|
848
|
+
const busy = (0, vue.computed)(() => snapshot.value.phase === "loading" || snapshot.value.phase === "applying");
|
|
849
|
+
const editable = (0, vue.computed)(() => !busy.value && !snapshot.value.readonlyReason);
|
|
850
|
+
const canApply = (0, vue.computed)(() => snapshot.value.canApply && !busy.value && !filePending.value && !snapshot.value.stale);
|
|
851
|
+
const error = (0, vue.computed)(() => localError.value || snapshot.value.error);
|
|
852
|
+
const status = (0, vue.computed)(() => {
|
|
853
|
+
if (filePending.value) return "Preparing picture…";
|
|
854
|
+
if (snapshot.value.phase === "loading") return "Loading watermarks…";
|
|
855
|
+
if (snapshot.value.phase === "applying") return "Applying changes; closing will not cancel them.";
|
|
856
|
+
if (snapshot.value.phase === "previewing") return "Updating preview…";
|
|
857
|
+
return snapshot.value.dirty ? "Changes apply when you choose Apply" : "No changes";
|
|
858
|
+
});
|
|
859
|
+
const fontOptions = (0, vue.computed)(() => {
|
|
860
|
+
const { fonts, draft } = snapshot.value;
|
|
861
|
+
return fonts.some((font) => font.value === draft.fontFamily) ? fonts : [{
|
|
862
|
+
value: draft.fontFamily,
|
|
863
|
+
label: draft.fontFamily
|
|
864
|
+
}, ...fonts];
|
|
865
|
+
});
|
|
866
|
+
function cancelPreparation() {
|
|
867
|
+
fileGeneration += 1;
|
|
868
|
+
filePending.value = false;
|
|
869
|
+
}
|
|
870
|
+
function patch(patch) {
|
|
871
|
+
if (!editable.value) return;
|
|
872
|
+
localError.value = "";
|
|
873
|
+
props.model.patchDraft(patch);
|
|
874
|
+
}
|
|
875
|
+
function changeScope(event, field) {
|
|
876
|
+
const value = event.target.value;
|
|
877
|
+
cancelPreparation();
|
|
878
|
+
props.model.setScope(field === "section" ? value || null : snapshot.value.sectionId, field === "variant" ? value : snapshot.value.variant);
|
|
879
|
+
}
|
|
880
|
+
function selectWatermark(id, event) {
|
|
881
|
+
cancelPreparation();
|
|
882
|
+
const selected = new Set(snapshot.value.selectedIds);
|
|
883
|
+
if (event.target.checked) selected.add(id);
|
|
884
|
+
else selected.delete(id);
|
|
885
|
+
props.model.selectWatermarks([...selected]);
|
|
886
|
+
}
|
|
887
|
+
async function choosePicture(event) {
|
|
888
|
+
const input = event.target;
|
|
889
|
+
const file = input.files?.[0];
|
|
890
|
+
input.value = "";
|
|
891
|
+
if (!file || !editable.value) return;
|
|
892
|
+
cancelPreparation();
|
|
893
|
+
localError.value = "";
|
|
894
|
+
if (!isSupportedImageFile(file)) {
|
|
895
|
+
localError.value = "Choose a PNG or JPEG picture.";
|
|
896
|
+
return;
|
|
897
|
+
}
|
|
898
|
+
const generation = fileGeneration;
|
|
899
|
+
filePending.value = true;
|
|
900
|
+
try {
|
|
901
|
+
const src = await fileToDataUri(file);
|
|
902
|
+
if (generation !== fileGeneration) return;
|
|
903
|
+
patch({
|
|
904
|
+
src,
|
|
905
|
+
pictureName: file.name,
|
|
906
|
+
kind: "picture"
|
|
907
|
+
});
|
|
908
|
+
} catch {
|
|
909
|
+
if (generation === fileGeneration) localError.value = "The picture could not be read. Choose it again.";
|
|
910
|
+
} finally {
|
|
911
|
+
if (generation === fileGeneration) filePending.value = false;
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
async function apply() {
|
|
915
|
+
if (!canApply.value) return;
|
|
916
|
+
try {
|
|
917
|
+
await props.model.apply();
|
|
918
|
+
} catch {
|
|
919
|
+
localError.value = "The watermark could not be applied. Try again.";
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
async function reload() {
|
|
923
|
+
cancelPreparation();
|
|
924
|
+
localError.value = "";
|
|
925
|
+
try {
|
|
926
|
+
await props.model.reload();
|
|
927
|
+
} catch {
|
|
928
|
+
localError.value = "Watermarks could not be loaded. Try again.";
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
function close() {
|
|
932
|
+
cancelPreparation();
|
|
933
|
+
props.close("user-cancelled");
|
|
934
|
+
}
|
|
935
|
+
(0, vue.watch)([
|
|
936
|
+
() => snapshot.value.draft.kind,
|
|
937
|
+
() => snapshot.value.sectionId,
|
|
938
|
+
() => snapshot.value.variant,
|
|
939
|
+
() => snapshot.value.selectedIds.join("\0")
|
|
940
|
+
], cancelPreparation);
|
|
941
|
+
(0, vue.onMounted)(() => {
|
|
942
|
+
unsubscribe = props.model.subscribe((value) => {
|
|
943
|
+
snapshot.value = value;
|
|
944
|
+
});
|
|
945
|
+
snapshot.value = props.model.getSnapshot();
|
|
946
|
+
});
|
|
947
|
+
(0, vue.onBeforeUnmount)(() => {
|
|
948
|
+
cancelPreparation();
|
|
949
|
+
unsubscribe?.();
|
|
950
|
+
});
|
|
951
|
+
return (_ctx, _cache) => {
|
|
952
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("form", {
|
|
953
|
+
class: "sd-watermark sd-dialog-content",
|
|
954
|
+
onSubmit: (0, vue.withModifiers)(apply, ["prevent"])
|
|
955
|
+
}, [
|
|
956
|
+
(0, vue.createElementVNode)("header", { class: "sd-watermark__header sd-dialog-header" }, [_cache[17] || (_cache[17] = (0, vue.createElementVNode)("h2", null, "Watermark", -1)), (0, vue.createElementVNode)("button", {
|
|
957
|
+
type: "button",
|
|
958
|
+
class: "sd-dialog-close",
|
|
959
|
+
"aria-label": "Close watermark dialog",
|
|
960
|
+
onClick: close
|
|
961
|
+
}, [..._cache[16] || (_cache[16] = [(0, vue.createElementVNode)("svg", {
|
|
962
|
+
width: "16",
|
|
963
|
+
height: "16",
|
|
964
|
+
viewBox: "0 0 16 16",
|
|
965
|
+
"aria-hidden": "true"
|
|
966
|
+
}, [(0, vue.createElementVNode)("path", {
|
|
967
|
+
d: "m4 4 8 8m0-8-8 8",
|
|
968
|
+
fill: "none",
|
|
969
|
+
stroke: "currentColor",
|
|
970
|
+
"stroke-width": "1.5",
|
|
971
|
+
"stroke-linecap": "round"
|
|
972
|
+
})], -1)])])]),
|
|
973
|
+
(0, vue.createElementVNode)("div", _hoisted_1, [(0, vue.createElementVNode)("div", _hoisted_2, [
|
|
974
|
+
(0, vue.createElementVNode)("fieldset", {
|
|
975
|
+
class: "sd-watermark__scope",
|
|
976
|
+
disabled: busy.value
|
|
977
|
+
}, [
|
|
978
|
+
_cache[22] || (_cache[22] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark scope", -1)),
|
|
979
|
+
(0, vue.createElementVNode)("label", _hoisted_4, [_cache[19] || (_cache[19] = (0, vue.createElementVNode)("span", null, "Apply to", -1)), (0, vue.createElementVNode)("select", {
|
|
980
|
+
"aria-label": "Apply to",
|
|
981
|
+
value: snapshot.value.sectionId ?? "",
|
|
982
|
+
onChange: _cache[0] || (_cache[0] = ($event) => changeScope($event, "section"))
|
|
983
|
+
}, [_cache[18] || (_cache[18] = (0, vue.createElementVNode)("option", { value: "" }, "Entire document", -1)), ((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.sections, (section) => {
|
|
984
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
985
|
+
key: section.id,
|
|
986
|
+
value: section.id
|
|
987
|
+
}, (0, vue.toDisplayString)(section.label), 9, _hoisted_6);
|
|
988
|
+
}), 128))], 40, _hoisted_5)]),
|
|
989
|
+
(0, vue.createElementVNode)("label", _hoisted_7, [_cache[21] || (_cache[21] = (0, vue.createElementVNode)("span", null, "Page type", -1)), (0, vue.createElementVNode)("select", {
|
|
990
|
+
"aria-label": "Page type",
|
|
991
|
+
value: snapshot.value.variant,
|
|
992
|
+
onChange: _cache[1] || (_cache[1] = ($event) => changeScope($event, "variant"))
|
|
993
|
+
}, [..._cache[20] || (_cache[20] = [
|
|
994
|
+
(0, vue.createElementVNode)("option", { value: "all" }, "All applicable", -1),
|
|
995
|
+
(0, vue.createElementVNode)("option", { value: "default" }, "Default", -1),
|
|
996
|
+
(0, vue.createElementVNode)("option", { value: "first" }, "First", -1),
|
|
997
|
+
(0, vue.createElementVNode)("option", { value: "even" }, "Even", -1)
|
|
998
|
+
])], 40, _hoisted_8)])
|
|
999
|
+
], 8, _hoisted_3),
|
|
1000
|
+
snapshot.value.items.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("fieldset", {
|
|
1001
|
+
key: 0,
|
|
1002
|
+
class: "sd-watermark__selection",
|
|
1003
|
+
disabled: busy.value
|
|
1004
|
+
}, [
|
|
1005
|
+
_cache[23] || (_cache[23] = (0, vue.createElementVNode)("legend", null, "Watermarks to edit", -1)),
|
|
1006
|
+
(0, vue.createElementVNode)("div", _hoisted_10, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.items, (item) => {
|
|
1007
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("label", {
|
|
1008
|
+
key: item.id,
|
|
1009
|
+
class: "sd-watermark__check"
|
|
1010
|
+
}, [(0, vue.createElementVNode)("input", {
|
|
1011
|
+
type: "checkbox",
|
|
1012
|
+
value: item.id,
|
|
1013
|
+
checked: snapshot.value.selectedIds.includes(item.id),
|
|
1014
|
+
onChange: ($event) => selectWatermark(item.id, $event)
|
|
1015
|
+
}, null, 40, _hoisted_11), (0, vue.createElementVNode)("span", null, [(0, vue.createTextVNode)((0, vue.toDisplayString)(item.label), 1), (0, vue.createElementVNode)("small", null, (0, vue.toDisplayString)(item.locations), 1)])]);
|
|
1016
|
+
}), 128))]),
|
|
1017
|
+
(0, vue.createElementVNode)("button", {
|
|
1018
|
+
type: "button",
|
|
1019
|
+
disabled: !editable.value,
|
|
1020
|
+
onClick: _cache[2] || (_cache[2] = ($event) => __props.model.selectWatermarks([]))
|
|
1021
|
+
}, "Add watermark", 8, _hoisted_12),
|
|
1022
|
+
snapshot.value.selectedIds.length > 1 ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_13, " Applying uses the settings below for all " + (0, vue.toDisplayString)(snapshot.value.selectedIds.length) + " selected copies. ", 1)) : (0, vue.createCommentVNode)("", true)
|
|
1023
|
+
], 8, _hoisted_9)) : (0, vue.createCommentVNode)("", true),
|
|
1024
|
+
snapshot.value.readonlyReason ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_14, (0, vue.toDisplayString)(snapshot.value.readonlyReason), 1)) : (0, vue.createCommentVNode)("", true),
|
|
1025
|
+
(0, vue.createElementVNode)("fieldset", {
|
|
1026
|
+
class: (0, vue.normalizeClass)(["sd-watermark__draft", { "sd-watermark__draft--text": snapshot.value.draft.kind === "text" }]),
|
|
1027
|
+
disabled: !editable.value
|
|
1028
|
+
}, [
|
|
1029
|
+
_cache[40] || (_cache[40] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark settings", -1)),
|
|
1030
|
+
(0, vue.createElementVNode)("fieldset", _hoisted_16, [_cache[24] || (_cache[24] = (0, vue.createElementVNode)("legend", { class: "sd-watermark__sr-only" }, "Watermark type", -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(types, (type) => {
|
|
1031
|
+
return (0, vue.createElementVNode)("label", {
|
|
1032
|
+
key: type.value,
|
|
1033
|
+
class: (0, vue.normalizeClass)({ "is-selected": snapshot.value.draft.kind === type.value })
|
|
1034
|
+
}, [(0, vue.createElementVNode)("input", {
|
|
1035
|
+
type: "radio",
|
|
1036
|
+
name: `watermark-type-${__props.surfaceId}`,
|
|
1037
|
+
value: type.value,
|
|
1038
|
+
checked: snapshot.value.draft.kind === type.value,
|
|
1039
|
+
onChange: ($event) => patch({ kind: type.value })
|
|
1040
|
+
}, null, 40, _hoisted_17), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(type.value === "none" && snapshot.value.items.length > 1 && snapshot.value.selectedIds.length ? "Remove selected" : type.label), 1)], 2);
|
|
1041
|
+
}), 64))]),
|
|
1042
|
+
snapshot.value.draft.kind === "text" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 0 }, [
|
|
1043
|
+
(0, vue.createElementVNode)("label", _hoisted_18, [_cache[25] || (_cache[25] = (0, vue.createElementVNode)("span", null, "Text", -1)), (0, vue.createElementVNode)("input", {
|
|
1044
|
+
"aria-label": "Watermark text",
|
|
1045
|
+
type: "text",
|
|
1046
|
+
value: snapshot.value.draft.text,
|
|
1047
|
+
onInput: _cache[3] || (_cache[3] = ($event) => patch({ text: $event.target.value }))
|
|
1048
|
+
}, null, 40, _hoisted_19)]),
|
|
1049
|
+
(0, vue.createElementVNode)("div", _hoisted_20, [((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(presets, (preset) => {
|
|
1050
|
+
return (0, vue.createElementVNode)("button", {
|
|
1051
|
+
key: preset,
|
|
1052
|
+
type: "button",
|
|
1053
|
+
onClick: ($event) => patch({ text: preset })
|
|
1054
|
+
}, (0, vue.toDisplayString)(preset), 9, _hoisted_21);
|
|
1055
|
+
}), 64))]),
|
|
1056
|
+
(0, vue.createElementVNode)("div", _hoisted_22, [
|
|
1057
|
+
(0, vue.createElementVNode)("label", _hoisted_23, [_cache[26] || (_cache[26] = (0, vue.createElementVNode)("span", null, "Font", -1)), (0, vue.createElementVNode)("select", {
|
|
1058
|
+
"aria-label": "Font",
|
|
1059
|
+
value: snapshot.value.draft.fontFamily,
|
|
1060
|
+
onChange: _cache[4] || (_cache[4] = ($event) => patch({ fontFamily: $event.target.value }))
|
|
1061
|
+
}, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(fontOptions.value, (font) => {
|
|
1062
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("option", {
|
|
1063
|
+
key: font.value,
|
|
1064
|
+
value: font.value
|
|
1065
|
+
}, (0, vue.toDisplayString)(font.label), 9, _hoisted_25);
|
|
1066
|
+
}), 128))], 40, _hoisted_24)]),
|
|
1067
|
+
(0, vue.createElementVNode)("label", _hoisted_26, [
|
|
1068
|
+
_cache[28] || (_cache[28] = (0, vue.createElementVNode)("span", null, "Size (pt)", -1)),
|
|
1069
|
+
(0, vue.createElementVNode)("input", {
|
|
1070
|
+
"aria-label": "Font size",
|
|
1071
|
+
list: `watermark-sizes-${__props.surfaceId}`,
|
|
1072
|
+
value: snapshot.value.draft.fontSize === "auto" ? "Auto" : snapshot.value.draft.fontSize,
|
|
1073
|
+
onChange: _cache[5] || (_cache[5] = ($event) => patch({ fontSize: $event.target.value.toLowerCase() === "auto" ? "auto" : Number($event.target.value) }))
|
|
1074
|
+
}, null, 40, _hoisted_27),
|
|
1075
|
+
(0, vue.createElementVNode)("datalist", { id: `watermark-sizes-${__props.surfaceId}` }, [_cache[27] || (_cache[27] = (0, vue.createElementVNode)("option", { value: "Auto" }, null, -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)([
|
|
1076
|
+
24,
|
|
1077
|
+
36,
|
|
1078
|
+
48,
|
|
1079
|
+
72,
|
|
1080
|
+
96
|
|
1081
|
+
], (size) => {
|
|
1082
|
+
return (0, vue.createElementVNode)("option", {
|
|
1083
|
+
key: size,
|
|
1084
|
+
value: size
|
|
1085
|
+
}, null, 8, _hoisted_29);
|
|
1086
|
+
}), 64))], 8, _hoisted_28)
|
|
1087
|
+
]),
|
|
1088
|
+
(0, vue.createElementVNode)("div", _hoisted_30, [(0, vue.createElementVNode)("button", {
|
|
1089
|
+
type: "button",
|
|
1090
|
+
"aria-label": "Bold",
|
|
1091
|
+
"aria-pressed": snapshot.value.draft.bold,
|
|
1092
|
+
onClick: _cache[6] || (_cache[6] = ($event) => patch({ bold: !snapshot.value.draft.bold }))
|
|
1093
|
+
}, [..._cache[29] || (_cache[29] = [(0, vue.createElementVNode)("b", null, "B", -1)])], 8, _hoisted_31), (0, vue.createElementVNode)("button", {
|
|
1094
|
+
type: "button",
|
|
1095
|
+
"aria-label": "Italic",
|
|
1096
|
+
"aria-pressed": snapshot.value.draft.italic,
|
|
1097
|
+
onClick: _cache[7] || (_cache[7] = ($event) => patch({ italic: !snapshot.value.draft.italic }))
|
|
1098
|
+
}, [..._cache[30] || (_cache[30] = [(0, vue.createElementVNode)("i", null, "I", -1)])], 8, _hoisted_32)])
|
|
1099
|
+
]),
|
|
1100
|
+
(0, vue.createElementVNode)("label", _hoisted_33, [_cache[31] || (_cache[31] = (0, vue.createElementVNode)("span", null, "Font color", -1)), (0, vue.createElementVNode)("span", _hoisted_34, [(0, vue.createElementVNode)("input", {
|
|
1101
|
+
type: "color",
|
|
1102
|
+
"aria-label": "Choose font color",
|
|
1103
|
+
value: snapshot.value.draft.color,
|
|
1104
|
+
onInput: _cache[8] || (_cache[8] = ($event) => patch({ color: $event.target.value }))
|
|
1105
|
+
}, null, 40, _hoisted_35), (0, vue.createElementVNode)("input", {
|
|
1106
|
+
type: "text",
|
|
1107
|
+
"aria-label": "Font color",
|
|
1108
|
+
value: snapshot.value.draft.color,
|
|
1109
|
+
spellcheck: "false",
|
|
1110
|
+
onInput: _cache[9] || (_cache[9] = ($event) => patch({ color: $event.target.value }))
|
|
1111
|
+
}, null, 40, _hoisted_36)])])
|
|
1112
|
+
], 64)) : (0, vue.createCommentVNode)("", true),
|
|
1113
|
+
snapshot.value.draft.kind === "picture" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, { key: 1 }, [
|
|
1114
|
+
(0, vue.createElementVNode)("div", _hoisted_37, [
|
|
1115
|
+
snapshot.value.draft.src ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
|
|
1116
|
+
key: 0,
|
|
1117
|
+
src: snapshot.value.draft.src,
|
|
1118
|
+
alt: "Selected picture"
|
|
1119
|
+
}, null, 8, _hoisted_38)) : (0, vue.createCommentVNode)("", true),
|
|
1120
|
+
(0, vue.createElementVNode)("div", null, [(0, vue.createElementVNode)("strong", null, (0, vue.toDisplayString)(snapshot.value.draft.pictureName || "No picture selected"), 1), _cache[32] || (_cache[32] = (0, vue.createElementVNode)("small", null, "PNG or JPEG", -1))]),
|
|
1121
|
+
(0, vue.createElementVNode)("button", {
|
|
1122
|
+
type: "button",
|
|
1123
|
+
onClick: _cache[10] || (_cache[10] = ($event) => fileInput.value?.click())
|
|
1124
|
+
}, (0, vue.toDisplayString)(snapshot.value.draft.pictureName ? "Replace picture" : "Choose picture"), 1),
|
|
1125
|
+
(0, vue.createElementVNode)("input", {
|
|
1126
|
+
ref_key: "fileInput",
|
|
1127
|
+
ref: fileInput,
|
|
1128
|
+
type: "file",
|
|
1129
|
+
accept: (0, vue.unref)(IMAGE_PICKER_ACCEPT),
|
|
1130
|
+
"aria-label": "Choose watermark picture",
|
|
1131
|
+
hidden: "",
|
|
1132
|
+
onChange: choosePicture
|
|
1133
|
+
}, null, 40, _hoisted_39)
|
|
1134
|
+
]),
|
|
1135
|
+
(0, vue.createElementVNode)("label", _hoisted_40, [_cache[34] || (_cache[34] = (0, vue.createElementVNode)("span", null, "Scale", -1)), (0, vue.createElementVNode)("select", {
|
|
1136
|
+
"aria-label": "Picture scale",
|
|
1137
|
+
value: snapshot.value.draft.customSize ? "custom" : snapshot.value.draft.scalePercent,
|
|
1138
|
+
onChange: _cache[11] || (_cache[11] = ($event) => patch({ scalePercent: $event.target.value === "auto" ? "auto" : Number($event.target.value) }))
|
|
1139
|
+
}, [
|
|
1140
|
+
snapshot.value.draft.customSize ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("option", _hoisted_42, "Custom size retained")) : (0, vue.createCommentVNode)("", true),
|
|
1141
|
+
_cache[33] || (_cache[33] = (0, vue.createElementVNode)("option", { value: "auto" }, "Auto", -1)),
|
|
1142
|
+
((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)([
|
|
1143
|
+
50,
|
|
1144
|
+
100,
|
|
1145
|
+
150,
|
|
1146
|
+
200,
|
|
1147
|
+
500
|
|
1148
|
+
], (scale) => {
|
|
1149
|
+
return (0, vue.createElementVNode)("option", {
|
|
1150
|
+
key: scale,
|
|
1151
|
+
value: scale
|
|
1152
|
+
}, (0, vue.toDisplayString)(scale) + "%", 9, _hoisted_43);
|
|
1153
|
+
}), 64))
|
|
1154
|
+
], 40, _hoisted_41)]),
|
|
1155
|
+
(0, vue.createElementVNode)("label", _hoisted_44, [(0, vue.createElementVNode)("input", {
|
|
1156
|
+
type: "checkbox",
|
|
1157
|
+
checked: snapshot.value.draft.lockAspectRatio,
|
|
1158
|
+
onChange: _cache[12] || (_cache[12] = ($event) => patch({ lockAspectRatio: $event.target.checked }))
|
|
1159
|
+
}, null, 40, _hoisted_45), _cache[35] || (_cache[35] = (0, vue.createElementVNode)("span", null, "Preserve aspect ratio", -1))]),
|
|
1160
|
+
(0, vue.createElementVNode)("label", _hoisted_46, [(0, vue.createElementVNode)("input", {
|
|
1161
|
+
type: "checkbox",
|
|
1162
|
+
checked: snapshot.value.draft.washout,
|
|
1163
|
+
onChange: _cache[13] || (_cache[13] = ($event) => patch({ washout: $event.target.checked }))
|
|
1164
|
+
}, null, 40, _hoisted_47), _cache[36] || (_cache[36] = (0, vue.createElementVNode)("span", null, [(0, vue.createTextVNode)("Washout"), (0, vue.createElementVNode)("small", null, "Lighten the picture's colors.")], -1))])
|
|
1165
|
+
], 64)) : (0, vue.createCommentVNode)("", true),
|
|
1166
|
+
snapshot.value.draft.kind !== "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_48, [
|
|
1167
|
+
(0, vue.createElementVNode)("label", { for: `watermark-transparency-${__props.surfaceId}` }, "Transparency", 8, _hoisted_49),
|
|
1168
|
+
(0, vue.createElementVNode)("div", _hoisted_50, [(0, vue.createElementVNode)("input", {
|
|
1169
|
+
id: `watermark-transparency-${__props.surfaceId}`,
|
|
1170
|
+
type: "range",
|
|
1171
|
+
min: "0",
|
|
1172
|
+
max: "100",
|
|
1173
|
+
step: "1",
|
|
1174
|
+
"aria-label": "Transparency",
|
|
1175
|
+
value: snapshot.value.draft.transparency,
|
|
1176
|
+
onInput: _cache[14] || (_cache[14] = ($event) => patch({ transparency: Number($event.target.value) }))
|
|
1177
|
+
}, null, 40, _hoisted_51), (0, vue.createElementVNode)("label", null, [(0, vue.createElementVNode)("input", {
|
|
1178
|
+
type: "number",
|
|
1179
|
+
min: "0",
|
|
1180
|
+
max: "100",
|
|
1181
|
+
step: "any",
|
|
1182
|
+
"aria-label": "Transparency percentage",
|
|
1183
|
+
value: snapshot.value.draft.transparency,
|
|
1184
|
+
onInput: _cache[15] || (_cache[15] = ($event) => patch({ transparency: Number($event.target.value) }))
|
|
1185
|
+
}, null, 40, _hoisted_52), _cache[37] || (_cache[37] = (0, vue.createElementVNode)("span", null, "%", -1))])]),
|
|
1186
|
+
_cache[38] || (_cache[38] = (0, vue.createElementVNode)("small", null, "0% opaque, 100% transparent", -1))
|
|
1187
|
+
])) : (0, vue.createCommentVNode)("", true),
|
|
1188
|
+
snapshot.value.draft.kind !== "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("fieldset", _hoisted_53, [_cache[39] || (_cache[39] = (0, vue.createElementVNode)("legend", null, "Orientation", -1)), ((0, vue.openBlock)(), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(["horizontal", "diagonal"], (orientation) => {
|
|
1189
|
+
return (0, vue.createElementVNode)("label", { key: orientation }, [(0, vue.createElementVNode)("input", {
|
|
1190
|
+
type: "radio",
|
|
1191
|
+
name: `watermark-orientation-${__props.surfaceId}`,
|
|
1192
|
+
value: orientation,
|
|
1193
|
+
checked: !snapshot.value.draft.customOrientation && snapshot.value.draft.orientation === orientation,
|
|
1194
|
+
onChange: ($event) => patch({ orientation })
|
|
1195
|
+
}, null, 40, _hoisted_54), (0, vue.createElementVNode)("span", null, (0, vue.toDisplayString)(orientation === "horizontal" ? "Horizontal" : "Diagonal"), 1)]);
|
|
1196
|
+
}), 64))])) : (0, vue.createCommentVNode)("", true),
|
|
1197
|
+
snapshot.value.draft.customPlacement ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_55, "Custom placement retained.")) : (0, vue.createCommentVNode)("", true),
|
|
1198
|
+
snapshot.value.draft.kind === "none" ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_56, (0, vue.toDisplayString)(snapshot.value.selectedIds.length ? "The selected watermark will be removed when you apply." : "Choose Text or Picture to add a watermark."), 1)) : (0, vue.createCommentVNode)("", true)
|
|
1199
|
+
], 10, _hoisted_15)
|
|
1200
|
+
]), (0, vue.createElementVNode)("aside", {
|
|
1201
|
+
class: "sd-watermark__preview",
|
|
1202
|
+
"aria-label": "Watermark preview",
|
|
1203
|
+
"aria-busy": snapshot.value.phase === "previewing"
|
|
1204
|
+
}, [
|
|
1205
|
+
_cache[41] || (_cache[41] = (0, vue.createElementVNode)("h3", null, "Preview", -1)),
|
|
1206
|
+
(0, vue.createElementVNode)("div", _hoisted_58, [snapshot.value.preview ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("img", {
|
|
1207
|
+
key: 0,
|
|
1208
|
+
src: snapshot.value.preview.url,
|
|
1209
|
+
width: snapshot.value.preview.width,
|
|
1210
|
+
height: snapshot.value.preview.height,
|
|
1211
|
+
alt: "Watermark on a sample page"
|
|
1212
|
+
}, null, 8, _hoisted_59)) : ((0, vue.openBlock)(), (0, vue.createElementBlock)("p", _hoisted_60, (0, vue.toDisplayString)(snapshot.value.phase === "loading" || snapshot.value.phase === "previewing" ? "Preparing preview…" : snapshot.value.draft.kind === "none" ? "No watermark in this preview" : "Preview unavailable"), 1))]),
|
|
1213
|
+
_cache[42] || (_cache[42] = (0, vue.createElementVNode)("p", { class: "sd-watermark__caption" }, "Preview at the selected page size", -1)),
|
|
1214
|
+
(0, vue.createElementVNode)("p", _hoisted_61, (0, vue.toDisplayString)(snapshot.value.impact), 1),
|
|
1215
|
+
snapshot.value.impactDetails?.length ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("details", _hoisted_62, [(0, vue.createElementVNode)("summary", null, "View " + (0, vue.toDisplayString)(snapshot.value.impactDetails.length) + " affected locations", 1), (0, vue.createElementVNode)("ul", null, [((0, vue.openBlock)(true), (0, vue.createElementBlock)(vue.Fragment, null, (0, vue.renderList)(snapshot.value.impactDetails, (location) => {
|
|
1216
|
+
return (0, vue.openBlock)(), (0, vue.createElementBlock)("li", { key: location }, (0, vue.toDisplayString)(location), 1);
|
|
1217
|
+
}), 128))])])) : (0, vue.createCommentVNode)("", true)
|
|
1218
|
+
], 8, _hoisted_57)]),
|
|
1219
|
+
error.value || snapshot.value.stale ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("div", _hoisted_63, [(0, vue.createElementVNode)("p", null, (0, vue.toDisplayString)(error.value || "The document changed. Review the latest state before applying."), 1), snapshot.value.stale || snapshot.value.error ? ((0, vue.openBlock)(), (0, vue.createElementBlock)("button", {
|
|
1220
|
+
key: 0,
|
|
1221
|
+
type: "button",
|
|
1222
|
+
disabled: busy.value,
|
|
1223
|
+
onClick: reload
|
|
1224
|
+
}, " Review latest state ", 8, _hoisted_64)) : (0, vue.createCommentVNode)("", true)])) : (0, vue.createCommentVNode)("", true),
|
|
1225
|
+
(0, vue.createElementVNode)("footer", _hoisted_65, [(0, vue.createElementVNode)("p", _hoisted_66, (0, vue.toDisplayString)(status.value), 1), (0, vue.createElementVNode)("div", _hoisted_67, [(0, vue.createElementVNode)("button", {
|
|
1226
|
+
type: "button",
|
|
1227
|
+
class: "sd-dialog-secondary",
|
|
1228
|
+
onClick: close
|
|
1229
|
+
}, "Cancel"), (0, vue.createElementVNode)("button", {
|
|
1230
|
+
type: "submit",
|
|
1231
|
+
class: "sd-watermark__apply sd-dialog-primary",
|
|
1232
|
+
disabled: !canApply.value
|
|
1233
|
+
}, (0, vue.toDisplayString)(snapshot.value.phase === "applying" ? "Applying…" : snapshot.value.draft.kind === "none" ? snapshot.value.items.length > 1 ? "Remove selected watermark" : "Remove watermark" : "Apply watermark"), 9, _hoisted_68)])])
|
|
1234
|
+
], 32);
|
|
1235
|
+
};
|
|
1236
|
+
}
|
|
1237
|
+
});
|
|
1238
|
+
//#endregion
|
|
1239
|
+
//#region src/components/surfaces/WatermarkSurface.vue
|
|
1240
|
+
var WatermarkSurface_default = /* @__PURE__ */ require__plugin_vue_export_helper._plugin_vue_export_helper_default(WatermarkSurface_vue_vue_type_script_setup_true_lang_default, [["__scopeId", "data-v-df56c82c"]]);
|
|
1241
|
+
//#endregion
|
|
1242
|
+
//#region src/components/surfaces/watermark-surface-runtime.js
|
|
1243
|
+
/**
|
|
1244
|
+
* Keeps Vue rendering and post-dismissal announcements outside the public type graph.
|
|
1245
|
+
* @param {(() => HTMLElement | null) | undefined} getContainer
|
|
1246
|
+
*/
|
|
1247
|
+
function createWatermarkSurfaceRuntime(getContainer) {
|
|
1248
|
+
/** @type {HTMLDivElement | null} */
|
|
1249
|
+
let status = null;
|
|
1250
|
+
let disposed = false;
|
|
1251
|
+
return {
|
|
1252
|
+
component: WatermarkSurface_default,
|
|
1253
|
+
captureFocusReturn() {
|
|
1254
|
+
const document = getContainer?.()?.ownerDocument;
|
|
1255
|
+
const opener = document?.activeElement;
|
|
1256
|
+
const item = opener?.closest("[data-sd-part=\"toolbar-item\"]") ?? opener?.querySelector("[data-sd-part=\"toolbar-item\"]");
|
|
1257
|
+
const container = (item?.closest("[data-sd-part=\"toolbar\"]"))?.parentElement;
|
|
1258
|
+
const isWatermarkEntry = item?.querySelector("[data-item=\"btn-watermark\"], [data-item=\"btn-overflow\"]");
|
|
1259
|
+
/** @param {() => boolean} isCurrent */
|
|
1260
|
+
return async (isCurrent) => {
|
|
1261
|
+
await (0, vue.nextTick)();
|
|
1262
|
+
if (disposed || !isCurrent() || !isWatermarkEntry || opener?.isConnected || !container?.isConnected) return;
|
|
1263
|
+
if (document?.activeElement !== document?.body) return;
|
|
1264
|
+
const currentToolbar = container.querySelector("[data-sd-part=\"toolbar\"]");
|
|
1265
|
+
for (const name of ["watermark", "overflow"]) {
|
|
1266
|
+
const target = currentToolbar?.querySelector(`[data-item="btn-${name}"]`)?.closest("[data-sd-part=\"toolbar-item\"]");
|
|
1267
|
+
if (target instanceof HTMLElement && target.getClientRects().length && target.getAttribute("aria-disabled") !== "true") {
|
|
1268
|
+
target.focus({ preventScroll: true });
|
|
1269
|
+
return;
|
|
1270
|
+
}
|
|
1271
|
+
}
|
|
1272
|
+
};
|
|
1273
|
+
},
|
|
1274
|
+
mount() {
|
|
1275
|
+
const container = getContainer?.();
|
|
1276
|
+
if (disposed || status || !container?.ownerDocument) return;
|
|
1277
|
+
status = container.ownerDocument.createElement("div");
|
|
1278
|
+
status.setAttribute("role", "status");
|
|
1279
|
+
status.setAttribute("aria-live", "polite");
|
|
1280
|
+
status.setAttribute("aria-atomic", "true");
|
|
1281
|
+
Object.assign(status.style, {
|
|
1282
|
+
position: "absolute",
|
|
1283
|
+
width: "1px",
|
|
1284
|
+
height: "1px",
|
|
1285
|
+
overflow: "hidden",
|
|
1286
|
+
clipPath: "inset(50%)",
|
|
1287
|
+
whiteSpace: "nowrap"
|
|
1288
|
+
});
|
|
1289
|
+
container.appendChild(status);
|
|
1290
|
+
},
|
|
1291
|
+
/** @param {string} message */
|
|
1292
|
+
announce(message) {
|
|
1293
|
+
if (!disposed && status) status.textContent = message;
|
|
1294
|
+
},
|
|
1295
|
+
destroy() {
|
|
1296
|
+
disposed = true;
|
|
1297
|
+
status?.remove();
|
|
1298
|
+
status = null;
|
|
1299
|
+
}
|
|
1300
|
+
};
|
|
1301
|
+
}
|
|
1302
|
+
//#endregion
|
|
1303
|
+
//#region src/public/ui/watermark-draft.ts
|
|
1304
|
+
function placementState(placement) {
|
|
1305
|
+
const customOrientation = placement?.rotationDegrees != null && ![0, 315].includes(placement.rotationDegrees);
|
|
1306
|
+
return {
|
|
1307
|
+
customOrientation,
|
|
1308
|
+
customPlacement: Boolean(customOrientation || placement?.behindText === false || placement?.horizontal && (placement.horizontal.alignment !== "center" || placement.horizontal.offsetPt) || placement?.vertical && (placement.vertical.alignment !== "center" || placement.vertical.offsetPt))
|
|
1309
|
+
};
|
|
1310
|
+
}
|
|
1311
|
+
function createWatermarkDraft(item) {
|
|
1312
|
+
const value = item?.watermark;
|
|
1313
|
+
const placement = value?.placement ? structuredClone(value.placement) : void 0;
|
|
1314
|
+
const picture = value?.kind === "picture" ? value : void 0;
|
|
1315
|
+
const text = value?.kind === "text" ? value : void 0;
|
|
1316
|
+
const rotation = placement?.rotationDegrees ?? (picture ? 0 : text?.orientation === "horizontal" ? 0 : 315);
|
|
1317
|
+
return {
|
|
1318
|
+
kind: value?.kind ?? "none",
|
|
1319
|
+
geometryKind: value?.kind ?? null,
|
|
1320
|
+
text: text?.text ?? "DRAFT",
|
|
1321
|
+
fontFamily: text?.fontFamily ?? "Calibri",
|
|
1322
|
+
fontSize: text?.fontSizePt ?? "auto",
|
|
1323
|
+
bold: text?.bold ?? false,
|
|
1324
|
+
italic: text?.italic ?? false,
|
|
1325
|
+
color: text?.color ?? "#C0C0C0",
|
|
1326
|
+
transparency: (1 - (value?.opacity ?? .5)) * 100,
|
|
1327
|
+
orientation: rotation === 0 ? "horizontal" : "diagonal",
|
|
1328
|
+
scalePercent: picture?.scalePercent ?? "auto",
|
|
1329
|
+
washout: picture?.washout ?? true,
|
|
1330
|
+
lockAspectRatio: picture?.lockAspectRatio ?? true,
|
|
1331
|
+
pictureName: picture ? "Image in this document" : "",
|
|
1332
|
+
sourceWatermarkId: picture ? item?.watermarkId : void 0,
|
|
1333
|
+
widthPt: picture?.widthPt,
|
|
1334
|
+
heightPt: picture?.heightPt,
|
|
1335
|
+
placement,
|
|
1336
|
+
...placementState(placement),
|
|
1337
|
+
customSize: Boolean(picture && (placement?.widthPt != null || picture.widthPt != null))
|
|
1338
|
+
};
|
|
1339
|
+
}
|
|
1340
|
+
function patchWatermarkDraft(draft, patch) {
|
|
1341
|
+
const next = {
|
|
1342
|
+
...draft,
|
|
1343
|
+
...patch
|
|
1344
|
+
};
|
|
1345
|
+
if (patch.kind && patch.kind !== "none") {
|
|
1346
|
+
if (patch.kind !== draft.geometryKind) {
|
|
1347
|
+
next.placement = void 0;
|
|
1348
|
+
next.widthPt = void 0;
|
|
1349
|
+
next.heightPt = void 0;
|
|
1350
|
+
next.customSize = false;
|
|
1351
|
+
next.orientation = patch.kind === "picture" ? "horizontal" : "diagonal";
|
|
1352
|
+
}
|
|
1353
|
+
next.geometryKind = patch.kind;
|
|
1354
|
+
}
|
|
1355
|
+
if (patch.orientation !== void 0) next.placement = {
|
|
1356
|
+
...next.placement,
|
|
1357
|
+
rotationDegrees: patch.orientation === "diagonal" ? 315 : 0
|
|
1358
|
+
};
|
|
1359
|
+
if (patch.scalePercent !== void 0 || patch.src !== void 0) {
|
|
1360
|
+
const { widthPt: _width, heightPt: _height, ...placement } = next.placement ?? {};
|
|
1361
|
+
next.placement = Object.keys(placement).length ? placement : void 0;
|
|
1362
|
+
next.widthPt = void 0;
|
|
1363
|
+
next.heightPt = void 0;
|
|
1364
|
+
next.customSize = false;
|
|
1365
|
+
}
|
|
1366
|
+
return {
|
|
1367
|
+
...next,
|
|
1368
|
+
...placementState(next.placement)
|
|
1369
|
+
};
|
|
1370
|
+
}
|
|
1371
|
+
function getWatermarkDraftError(draft) {
|
|
1372
|
+
if (draft.kind === "none") return null;
|
|
1373
|
+
if (!Number.isFinite(draft.transparency) || draft.transparency < 0 || draft.transparency > 100) return "Transparency must be between 0 and 100%.";
|
|
1374
|
+
if (draft.kind === "picture") return draft.src || draft.sourceWatermarkId ? null : "Choose a picture.";
|
|
1375
|
+
if (!draft.text.trim()) return "Enter watermark text.";
|
|
1376
|
+
if (draft.fontSize !== "auto" && (!Number.isFinite(draft.fontSize) || draft.fontSize <= 0)) return "Enter a positive font size or choose Auto.";
|
|
1377
|
+
if (!/^#[\da-f]{6}$/i.test(draft.color)) return "Enter a six-digit hex color.";
|
|
1378
|
+
if (!draft.fontFamily.trim()) return "Choose a font.";
|
|
1379
|
+
return null;
|
|
1380
|
+
}
|
|
1381
|
+
function toWatermarkInput(draft) {
|
|
1382
|
+
const shared = {
|
|
1383
|
+
opacity: 1 - draft.transparency / 100,
|
|
1384
|
+
...draft.placement ? { placement: draft.placement } : {}
|
|
1385
|
+
};
|
|
1386
|
+
if (draft.kind === "text") return {
|
|
1387
|
+
kind: "text",
|
|
1388
|
+
text: draft.text,
|
|
1389
|
+
fontFamily: draft.fontFamily,
|
|
1390
|
+
fontSizePt: draft.fontSize,
|
|
1391
|
+
bold: draft.bold,
|
|
1392
|
+
italic: draft.italic,
|
|
1393
|
+
color: draft.color,
|
|
1394
|
+
orientation: draft.orientation,
|
|
1395
|
+
...shared
|
|
1396
|
+
};
|
|
1397
|
+
if (draft.kind !== "picture") throw new Error("A removal has no watermark input.");
|
|
1398
|
+
return {
|
|
1399
|
+
kind: "picture",
|
|
1400
|
+
...draft.src ? { src: draft.src } : { source: {
|
|
1401
|
+
kind: "existing",
|
|
1402
|
+
watermarkId: draft.sourceWatermarkId
|
|
1403
|
+
} },
|
|
1404
|
+
scalePercent: draft.scalePercent,
|
|
1405
|
+
washout: draft.washout,
|
|
1406
|
+
lockAspectRatio: draft.lockAspectRatio,
|
|
1407
|
+
...draft.widthPt != null ? { widthPt: draft.widthPt } : {},
|
|
1408
|
+
...draft.heightPt != null ? { heightPt: draft.heightPt } : {},
|
|
1409
|
+
...shared
|
|
1410
|
+
};
|
|
1411
|
+
}
|
|
1412
|
+
//#endregion
|
|
1413
|
+
//#region src/public/ui/watermark-controller.ts
|
|
1414
|
+
var PAGE_TYPES = {
|
|
1415
|
+
default: "Default pages",
|
|
1416
|
+
first: "First page",
|
|
1417
|
+
even: "Even pages"
|
|
1418
|
+
};
|
|
1419
|
+
var STALE_MESSAGE = "The document changed while this dialog was open. Review the latest watermark before applying.";
|
|
1420
|
+
function scopeSlots(sections, sectionId, variant) {
|
|
1421
|
+
return sections.filter((section) => sectionId == null || section.address.sectionId === sectionId).flatMap((section) => {
|
|
1422
|
+
return (variant === "all" ? [
|
|
1423
|
+
"default",
|
|
1424
|
+
...section.titlePage ? ["first"] : [],
|
|
1425
|
+
...section.oddEvenHeadersFooters ? ["even"] : []
|
|
1426
|
+
] : [variant]).map((variant) => ({
|
|
1427
|
+
kind: "headerFooterSlot",
|
|
1428
|
+
section: section.address,
|
|
1429
|
+
headerFooterKind: "header",
|
|
1430
|
+
variant
|
|
1431
|
+
}));
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
function slotKey(slot) {
|
|
1435
|
+
return `${slot.section.sectionId}:${slot.variant}`;
|
|
1436
|
+
}
|
|
1437
|
+
function failureMessage(error) {
|
|
1438
|
+
return error instanceof Error ? error.message : "The watermark could not be updated. Try again.";
|
|
1439
|
+
}
|
|
1440
|
+
function createWatermarkController(options) {
|
|
1441
|
+
const surface = createWatermarkSurfaceRuntime(options.getContainer);
|
|
1442
|
+
const workflowOptions = {
|
|
1443
|
+
...options,
|
|
1444
|
+
announce: (message) => {
|
|
1445
|
+
surface.announce(message);
|
|
1446
|
+
options.announce?.(message);
|
|
1447
|
+
}
|
|
1448
|
+
};
|
|
1449
|
+
let active = null;
|
|
1450
|
+
let destroyed = false;
|
|
1451
|
+
let openGeneration = 0;
|
|
1452
|
+
function close() {
|
|
1453
|
+
const previous = active;
|
|
1454
|
+
active = null;
|
|
1455
|
+
previous?.dispose();
|
|
1456
|
+
previous?.handle.close();
|
|
1457
|
+
}
|
|
1458
|
+
function open() {
|
|
1459
|
+
if (destroyed) return {
|
|
1460
|
+
ok: false,
|
|
1461
|
+
reason: "not-ready"
|
|
1462
|
+
};
|
|
1463
|
+
const editor = options.getEditor();
|
|
1464
|
+
if (!editor) return {
|
|
1465
|
+
ok: false,
|
|
1466
|
+
reason: "not-ready"
|
|
1467
|
+
};
|
|
1468
|
+
if (!editor.doc?.watermarks?.list || !editor.doc.sections?.list) return {
|
|
1469
|
+
ok: false,
|
|
1470
|
+
reason: "document-api-unavailable"
|
|
1471
|
+
};
|
|
1472
|
+
if (!options.openSurface || !editor.doc.watermarks.apply || !editor.host?.watermarkPreview) return {
|
|
1473
|
+
ok: false,
|
|
1474
|
+
reason: "operation-unavailable"
|
|
1475
|
+
};
|
|
1476
|
+
const generation = ++openGeneration;
|
|
1477
|
+
const restoreFocus = surface.captureFocusReturn();
|
|
1478
|
+
close();
|
|
1479
|
+
surface.mount();
|
|
1480
|
+
const workflow = createDialogWorkflow(editor, workflowOptions, () => {
|
|
1481
|
+
if (active?.handle === handle) close();
|
|
1482
|
+
});
|
|
1483
|
+
let handle;
|
|
1484
|
+
try {
|
|
1485
|
+
handle = options.openSurface({
|
|
1486
|
+
mode: "dialog",
|
|
1487
|
+
ariaLabel: "Watermark",
|
|
1488
|
+
component: surface.component,
|
|
1489
|
+
props: { model: workflow.model },
|
|
1490
|
+
dialog: { maxWidth: 700 }
|
|
1491
|
+
});
|
|
1492
|
+
} catch {
|
|
1493
|
+
workflow.dispose();
|
|
1494
|
+
return {
|
|
1495
|
+
ok: false,
|
|
1496
|
+
reason: "operation-unavailable"
|
|
1497
|
+
};
|
|
1498
|
+
}
|
|
1499
|
+
active = {
|
|
1500
|
+
handle,
|
|
1501
|
+
dispose: workflow.dispose
|
|
1502
|
+
};
|
|
1503
|
+
handle.result.then((outcome) => {
|
|
1504
|
+
workflow.dispose();
|
|
1505
|
+
if (active?.handle === handle) active = null;
|
|
1506
|
+
if (outcome.status === "closed" || outcome.status === "submitted") restoreFocus(() => !destroyed && generation === openGeneration && active === null);
|
|
1507
|
+
});
|
|
1508
|
+
workflow.model.reload();
|
|
1509
|
+
return { ok: true };
|
|
1510
|
+
}
|
|
1511
|
+
return {
|
|
1512
|
+
open,
|
|
1513
|
+
close,
|
|
1514
|
+
destroy() {
|
|
1515
|
+
destroyed = true;
|
|
1516
|
+
close();
|
|
1517
|
+
surface.destroy();
|
|
1518
|
+
}
|
|
1519
|
+
};
|
|
1520
|
+
}
|
|
1521
|
+
function createDialogWorkflow(editor, options, onSuccess) {
|
|
1522
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
1523
|
+
let alive = true;
|
|
1524
|
+
let generation = 0;
|
|
1525
|
+
let timer;
|
|
1526
|
+
let catalog = [];
|
|
1527
|
+
let sections = [];
|
|
1528
|
+
let revision = "";
|
|
1529
|
+
let originalDraft = JSON.stringify(createWatermarkDraft());
|
|
1530
|
+
let preparedInput = null;
|
|
1531
|
+
let snapshot = {
|
|
1532
|
+
phase: "loading",
|
|
1533
|
+
draft: createWatermarkDraft(),
|
|
1534
|
+
sections: [],
|
|
1535
|
+
sectionId: null,
|
|
1536
|
+
variant: "all",
|
|
1537
|
+
items: [],
|
|
1538
|
+
selectedIds: [],
|
|
1539
|
+
fonts: [...options.getFonts()],
|
|
1540
|
+
dirty: false,
|
|
1541
|
+
canApply: false,
|
|
1542
|
+
error: null,
|
|
1543
|
+
stale: false,
|
|
1544
|
+
readonlyReason: null,
|
|
1545
|
+
impact: "",
|
|
1546
|
+
impactDetails: [],
|
|
1547
|
+
preview: null
|
|
1548
|
+
};
|
|
1549
|
+
const current = (token) => alive && token === generation && options.getEditor() === editor;
|
|
1550
|
+
const editable = () => options.getMode() === "editing";
|
|
1551
|
+
function publish(patch) {
|
|
1552
|
+
if (!alive) return;
|
|
1553
|
+
snapshot = {
|
|
1554
|
+
...snapshot,
|
|
1555
|
+
...patch
|
|
1556
|
+
};
|
|
1557
|
+
for (const listener of listeners) listener(snapshot);
|
|
1558
|
+
}
|
|
1559
|
+
function invalidate() {
|
|
1560
|
+
clearTimeout(timer);
|
|
1561
|
+
preparedInput = null;
|
|
1562
|
+
return ++generation;
|
|
1563
|
+
}
|
|
1564
|
+
function location(slot) {
|
|
1565
|
+
const section = sections.find((item) => item.address.sectionId === slot.section.sectionId);
|
|
1566
|
+
const inactive = slot.variant === "first" ? !section?.titlePage : slot.variant === "even" ? !section?.oddEvenHeadersFooters : false;
|
|
1567
|
+
return `Section ${(section?.index ?? 0) + 1}, ${PAGE_TYPES[slot.variant].toLowerCase()}${inactive ? " (inactive)" : ""}`;
|
|
1568
|
+
}
|
|
1569
|
+
function scopedItems() {
|
|
1570
|
+
if (snapshot.sectionId == null && snapshot.variant === "all") return catalog;
|
|
1571
|
+
const keys = new Set(scopeSlots(sections, snapshot.sectionId, snapshot.variant).map(slotKey));
|
|
1572
|
+
return catalog.filter((item) => item.effectiveIn.some((slot) => keys.has(slotKey(slot))));
|
|
1573
|
+
}
|
|
1574
|
+
function publishCatalog() {
|
|
1575
|
+
publish({ items: scopedItems().map((item) => ({
|
|
1576
|
+
id: item.watermarkId,
|
|
1577
|
+
label: item.watermark.kind === "text" ? item.watermark.text : "Picture watermark",
|
|
1578
|
+
locations: item.effectiveIn.map(location).join("; ")
|
|
1579
|
+
})) });
|
|
1580
|
+
}
|
|
1581
|
+
function buildInput() {
|
|
1582
|
+
const target = snapshot.sectionId == null && snapshot.variant === "all" ? { kind: "document" } : {
|
|
1583
|
+
kind: "headerFooterSlots",
|
|
1584
|
+
slots: scopeSlots(sections, snapshot.sectionId, snapshot.variant)
|
|
1585
|
+
};
|
|
1586
|
+
if (snapshot.draft.kind === "none") return {
|
|
1587
|
+
target,
|
|
1588
|
+
action: "remove",
|
|
1589
|
+
watermarkIds: snapshot.selectedIds
|
|
1590
|
+
};
|
|
1591
|
+
const watermark = toWatermarkInput(snapshot.draft);
|
|
1592
|
+
if (snapshot.selectedIds.length) return {
|
|
1593
|
+
target,
|
|
1594
|
+
action: "replace",
|
|
1595
|
+
watermarkIds: snapshot.selectedIds,
|
|
1596
|
+
watermark
|
|
1597
|
+
};
|
|
1598
|
+
if ("source" in watermark) throw new Error("Select the existing picture watermark in this scope, or choose a new picture.");
|
|
1599
|
+
return {
|
|
1600
|
+
target,
|
|
1601
|
+
action: "insert",
|
|
1602
|
+
watermark
|
|
1603
|
+
};
|
|
1604
|
+
}
|
|
1605
|
+
function rejectReceipt(result) {
|
|
1606
|
+
if (result.success) return false;
|
|
1607
|
+
const stale = result.failure?.code === "REVISION_MISMATCH";
|
|
1608
|
+
publish({
|
|
1609
|
+
stale,
|
|
1610
|
+
phase: "editing",
|
|
1611
|
+
canApply: false,
|
|
1612
|
+
error: stale ? STALE_MESSAGE : result.failure?.message ?? "The watermark could not be updated."
|
|
1613
|
+
});
|
|
1614
|
+
return true;
|
|
1615
|
+
}
|
|
1616
|
+
async function prepare(token) {
|
|
1617
|
+
try {
|
|
1618
|
+
const error = getWatermarkDraftError(snapshot.draft);
|
|
1619
|
+
if (error) {
|
|
1620
|
+
publish({
|
|
1621
|
+
phase: "editing",
|
|
1622
|
+
error,
|
|
1623
|
+
canApply: false,
|
|
1624
|
+
preview: null
|
|
1625
|
+
});
|
|
1626
|
+
return;
|
|
1627
|
+
}
|
|
1628
|
+
const input = snapshot.draft.kind === "none" && !snapshot.selectedIds.length ? null : buildInput();
|
|
1629
|
+
const preview = snapshot.draft.kind === "none" ? null : await editor.host.watermarkPreview({
|
|
1630
|
+
watermark: toWatermarkInput(snapshot.draft),
|
|
1631
|
+
sectionId: snapshot.sectionId ?? sections[0]?.address.sectionId,
|
|
1632
|
+
expectedRevision: revision
|
|
1633
|
+
});
|
|
1634
|
+
if (!current(token)) return;
|
|
1635
|
+
if (!input || !snapshot.dirty || !editable()) {
|
|
1636
|
+
publish({
|
|
1637
|
+
phase: "editing",
|
|
1638
|
+
preview,
|
|
1639
|
+
canApply: false,
|
|
1640
|
+
error: null
|
|
1641
|
+
});
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
const receipt = await editor.doc.watermarks.apply(input, {
|
|
1645
|
+
expectedRevision: revision,
|
|
1646
|
+
dryRun: true
|
|
1647
|
+
});
|
|
1648
|
+
if (!current(token)) return;
|
|
1649
|
+
if (!receipt.success) {
|
|
1650
|
+
rejectReceipt(receipt);
|
|
1651
|
+
return;
|
|
1652
|
+
}
|
|
1653
|
+
preparedInput = input;
|
|
1654
|
+
const affected = receipt.affectedSlots.map(location);
|
|
1655
|
+
publish({
|
|
1656
|
+
phase: "editing",
|
|
1657
|
+
preview,
|
|
1658
|
+
error: null,
|
|
1659
|
+
canApply: affected.length > 0 && !snapshot.stale && editable(),
|
|
1660
|
+
impact: affected.length ? `Changes: ${affected.length > 3 ? `${affected.length} page locations` : affected.join("; ")}. Other locations stay as they are.` : "No matching watermark will change.",
|
|
1661
|
+
impactDetails: affected.length > 3 ? affected : []
|
|
1662
|
+
});
|
|
1663
|
+
} catch (error) {
|
|
1664
|
+
if (current(token)) publish({
|
|
1665
|
+
phase: "editing",
|
|
1666
|
+
error: failureMessage(error),
|
|
1667
|
+
canApply: false,
|
|
1668
|
+
preview: null
|
|
1669
|
+
});
|
|
1670
|
+
}
|
|
1671
|
+
}
|
|
1672
|
+
function schedulePreview() {
|
|
1673
|
+
const token = invalidate();
|
|
1674
|
+
publish({
|
|
1675
|
+
phase: "previewing",
|
|
1676
|
+
canApply: false,
|
|
1677
|
+
error: null,
|
|
1678
|
+
impact: "",
|
|
1679
|
+
impactDetails: [],
|
|
1680
|
+
preview: null
|
|
1681
|
+
});
|
|
1682
|
+
timer = setTimeout(() => {
|
|
1683
|
+
prepare(token);
|
|
1684
|
+
}, 120);
|
|
1685
|
+
}
|
|
1686
|
+
const model = {
|
|
1687
|
+
getSnapshot: () => snapshot,
|
|
1688
|
+
subscribe(listener) {
|
|
1689
|
+
listeners.add(listener);
|
|
1690
|
+
listener(snapshot);
|
|
1691
|
+
return () => {
|
|
1692
|
+
listeners.delete(listener);
|
|
1693
|
+
};
|
|
1694
|
+
},
|
|
1695
|
+
async reload() {
|
|
1696
|
+
const token = invalidate();
|
|
1697
|
+
publish({
|
|
1698
|
+
phase: "loading",
|
|
1699
|
+
canApply: false,
|
|
1700
|
+
stale: false,
|
|
1701
|
+
error: null,
|
|
1702
|
+
impactDetails: [],
|
|
1703
|
+
preview: null
|
|
1704
|
+
});
|
|
1705
|
+
try {
|
|
1706
|
+
const [marks, sectionList] = await Promise.all([editor.doc.watermarks.list(), editor.doc.sections.list()]);
|
|
1707
|
+
if (!current(token)) return;
|
|
1708
|
+
if (marks.items.length !== marks.total || sectionList.items.length !== sectionList.total) throw new Error("The complete watermark scope could not be loaded.");
|
|
1709
|
+
if (sectionList.evaluatedRevision && sectionList.evaluatedRevision !== marks.evaluatedRevision) throw new Error(STALE_MESSAGE);
|
|
1710
|
+
catalog = marks.items;
|
|
1711
|
+
sections = sectionList.items;
|
|
1712
|
+
revision = marks.evaluatedRevision;
|
|
1713
|
+
const available = scopedItems();
|
|
1714
|
+
const selected = available.length === 1 ? available[0] : void 0;
|
|
1715
|
+
const draft = createWatermarkDraft(selected);
|
|
1716
|
+
originalDraft = JSON.stringify(draft);
|
|
1717
|
+
publish({
|
|
1718
|
+
draft,
|
|
1719
|
+
dirty: false,
|
|
1720
|
+
selectedIds: selected ? [selected.watermarkId] : [],
|
|
1721
|
+
sections: sections.map((item) => ({
|
|
1722
|
+
id: item.address.sectionId,
|
|
1723
|
+
label: `Section ${item.index + 1}`
|
|
1724
|
+
})),
|
|
1725
|
+
readonlyReason: editable() ? null : options.getMode() === "suggesting" ? "Watermarks cannot be changed in Suggesting mode." : "This document is read-only.",
|
|
1726
|
+
impact: available.length > 1 ? "Select the watermark copies you want to edit, or add a new watermark." : ""
|
|
1727
|
+
});
|
|
1728
|
+
publishCatalog();
|
|
1729
|
+
await prepare(token);
|
|
1730
|
+
} catch (error) {
|
|
1731
|
+
if (current(token)) publish({
|
|
1732
|
+
phase: "editing",
|
|
1733
|
+
error: failureMessage(error),
|
|
1734
|
+
canApply: false
|
|
1735
|
+
});
|
|
1736
|
+
}
|
|
1737
|
+
},
|
|
1738
|
+
patchDraft(patch) {
|
|
1739
|
+
if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying" || !editable()) return;
|
|
1740
|
+
const draft = patchWatermarkDraft(snapshot.draft, patch);
|
|
1741
|
+
publish({
|
|
1742
|
+
draft,
|
|
1743
|
+
dirty: JSON.stringify(draft) !== originalDraft
|
|
1744
|
+
});
|
|
1745
|
+
schedulePreview();
|
|
1746
|
+
},
|
|
1747
|
+
setScope(sectionId, variant) {
|
|
1748
|
+
if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying") return;
|
|
1749
|
+
if (sectionId != null && !sections.some((item) => item.address.sectionId === sectionId)) return;
|
|
1750
|
+
publish({
|
|
1751
|
+
sectionId,
|
|
1752
|
+
variant
|
|
1753
|
+
});
|
|
1754
|
+
publishCatalog();
|
|
1755
|
+
const available = scopedItems();
|
|
1756
|
+
const visible = new Set(available.map((item) => item.watermarkId));
|
|
1757
|
+
let selectedIds = snapshot.selectedIds.filter((id) => visible.has(id));
|
|
1758
|
+
if (snapshot.dirty && snapshot.draft.kind === "none" && !selectedIds.length && available.length === 1) selectedIds = [available[0].watermarkId];
|
|
1759
|
+
publish({ selectedIds });
|
|
1760
|
+
if (!snapshot.dirty) model.selectWatermarks(available.length === 1 ? [available[0].watermarkId] : []);
|
|
1761
|
+
else schedulePreview();
|
|
1762
|
+
},
|
|
1763
|
+
selectWatermarks(ids) {
|
|
1764
|
+
if (!alive || snapshot.phase === "loading" || snapshot.phase === "applying") return;
|
|
1765
|
+
const available = scopedItems();
|
|
1766
|
+
const selectedIds = [...new Set(ids)].filter((id) => available.some((item) => item.watermarkId === id));
|
|
1767
|
+
const draft = createWatermarkDraft(available.find((item) => item.watermarkId === selectedIds[0]));
|
|
1768
|
+
originalDraft = JSON.stringify(draft);
|
|
1769
|
+
publish({
|
|
1770
|
+
selectedIds,
|
|
1771
|
+
draft,
|
|
1772
|
+
dirty: false
|
|
1773
|
+
});
|
|
1774
|
+
schedulePreview();
|
|
1775
|
+
},
|
|
1776
|
+
async apply() {
|
|
1777
|
+
if (!alive || !snapshot.canApply || !preparedInput || !editable() || options.getEditor() !== editor) return;
|
|
1778
|
+
const input = preparedInput;
|
|
1779
|
+
const token = invalidate();
|
|
1780
|
+
publish({
|
|
1781
|
+
phase: "applying",
|
|
1782
|
+
canApply: false,
|
|
1783
|
+
error: null
|
|
1784
|
+
});
|
|
1785
|
+
options.announce?.("Applying watermark changes. Closing the dialog will not cancel them.");
|
|
1786
|
+
try {
|
|
1787
|
+
const receipt = await editor.doc.watermarks.apply(input, { expectedRevision: revision });
|
|
1788
|
+
if (!current(token)) {
|
|
1789
|
+
options.announce?.(receipt.success ? "Watermark updated." : "The watermark could not be updated.");
|
|
1790
|
+
return;
|
|
1791
|
+
}
|
|
1792
|
+
if (rejectReceipt(receipt)) return;
|
|
1793
|
+
options.announce?.(input.action === "remove" ? "Watermark removed." : "Watermark updated.");
|
|
1794
|
+
onSuccess();
|
|
1795
|
+
} catch (error) {
|
|
1796
|
+
if (current(token)) publish({
|
|
1797
|
+
phase: "editing",
|
|
1798
|
+
error: failureMessage(error),
|
|
1799
|
+
canApply: false
|
|
1800
|
+
});
|
|
1801
|
+
else options.announce?.(failureMessage(error));
|
|
1802
|
+
}
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
const stopEvents = editor.host?.events?.subscribe((event) => {
|
|
1806
|
+
if (!alive || snapshot.phase === "applying") return;
|
|
1807
|
+
if (event.type === "collaboration:document-replaced") {
|
|
1808
|
+
invalidate();
|
|
1809
|
+
publish({
|
|
1810
|
+
phase: "editing",
|
|
1811
|
+
stale: true,
|
|
1812
|
+
canApply: false,
|
|
1813
|
+
error: STALE_MESSAGE
|
|
1814
|
+
});
|
|
1815
|
+
return;
|
|
1816
|
+
}
|
|
1817
|
+
if (![
|
|
1818
|
+
"document:mutated",
|
|
1819
|
+
"mutation:committed",
|
|
1820
|
+
"collaboration:remote-changed"
|
|
1821
|
+
].includes(event.type)) return;
|
|
1822
|
+
invalidate();
|
|
1823
|
+
if (snapshot.dirty) publish({
|
|
1824
|
+
phase: "editing",
|
|
1825
|
+
stale: true,
|
|
1826
|
+
canApply: false,
|
|
1827
|
+
error: STALE_MESSAGE
|
|
1828
|
+
});
|
|
1829
|
+
else timer = setTimeout(() => {
|
|
1830
|
+
model.reload();
|
|
1831
|
+
}, 120);
|
|
1832
|
+
});
|
|
1833
|
+
return {
|
|
1834
|
+
model,
|
|
1835
|
+
dispose() {
|
|
1836
|
+
alive = false;
|
|
1837
|
+
invalidate();
|
|
1838
|
+
stopEvents?.();
|
|
1839
|
+
listeners.clear();
|
|
1840
|
+
}
|
|
1841
|
+
};
|
|
1842
|
+
}
|
|
1843
|
+
//#endregion
|
|
537
1844
|
//#region src/public/ui/format-painter-helpers.js
|
|
538
1845
|
/**
|
|
539
1846
|
* Maps SDRunProps field names to InlineRunPatch field names.
|
|
@@ -7591,6 +8898,7 @@ function createSuperDocUI(options) {
|
|
|
7591
8898
|
syncTrackedChangeFocusFromHostReviewTarget(readHostActiveReviewTarget(readHostReviewSource()));
|
|
7592
8899
|
state = computeState("initial");
|
|
7593
8900
|
lastOptimisticInlineSelectionSignature = selectionInlineValueSignature(state.selection);
|
|
8901
|
+
let scheduleActiveSearchRefresh = () => {};
|
|
7594
8902
|
const syncHostEventsSubscription = () => {
|
|
7595
8903
|
const host = getEditor()?.host;
|
|
7596
8904
|
const events = host?.events;
|
|
@@ -7610,6 +8918,7 @@ function createSuperDocUI(options) {
|
|
|
7610
8918
|
const off = next.subscribe((event) => {
|
|
7611
8919
|
const type = event?.type;
|
|
7612
8920
|
const isStandaloneDocumentMutation = type === "document:mutated" && event.hasCommitEvent !== true;
|
|
8921
|
+
if (isStandaloneDocumentMutation || type === "mutation:committed" && mutationCommittedEventChangedDocument(event) || type === "collaboration:remote-changed" && Array.isArray(event.changedStoryIds) && event.changedStoryIds.length > 0) scheduleActiveSearchRefresh();
|
|
7613
8922
|
if ((type === "document:mutated" || type === "mutation:committed" && mutationCommittedEventChangedDocument(event)) && host && !dirtyHosts.has(host)) {
|
|
7614
8923
|
dirtyHosts.add(host);
|
|
7615
8924
|
recompute("document-dirty");
|
|
@@ -11011,6 +12320,12 @@ function createSuperDocUI(options) {
|
|
|
11011
12320
|
* session is the one that says how to close it.
|
|
11012
12321
|
*/
|
|
11013
12322
|
let releaseActiveSearchSession = null;
|
|
12323
|
+
let releaseRefreshShellSearch = null;
|
|
12324
|
+
const cancelRefreshShellSearch = () => {
|
|
12325
|
+
const release = releaseRefreshShellSearch;
|
|
12326
|
+
releaseRefreshShellSearch = null;
|
|
12327
|
+
if (release) safeCall(() => release(), null);
|
|
12328
|
+
};
|
|
11014
12329
|
/** Release whatever session is open, then forget it. */
|
|
11015
12330
|
const releaseSearchSession = () => {
|
|
11016
12331
|
const release = releaseActiveSearchSession;
|
|
@@ -11042,6 +12357,7 @@ function createSuperDocUI(options) {
|
|
|
11042
12357
|
searchRequestGeneration += 1;
|
|
11043
12358
|
pendingFallbackGeneration = null;
|
|
11044
12359
|
shellFallbackOutstanding = false;
|
|
12360
|
+
cancelRefreshShellSearch();
|
|
11045
12361
|
releaseSearchSession();
|
|
11046
12362
|
const available = searchIsAvailable();
|
|
11047
12363
|
searchState = {
|
|
@@ -11223,6 +12539,7 @@ function createSuperDocUI(options) {
|
|
|
11223
12539
|
},
|
|
11224
12540
|
close: () => {
|
|
11225
12541
|
searchRequestGeneration += 1;
|
|
12542
|
+
cancelRefreshShellSearch();
|
|
11226
12543
|
if (releaseActiveSearchSession) releaseSearchSession();
|
|
11227
12544
|
else {
|
|
11228
12545
|
const host = getHostSearch();
|
|
@@ -11246,6 +12563,7 @@ function createSuperDocUI(options) {
|
|
|
11246
12563
|
const includeDeletedText = (options?.includeTrackedDeletions ?? options?.includeDeletedText) === true;
|
|
11247
12564
|
const regex = options?.regex === true;
|
|
11248
12565
|
const generation = ++searchRequestGeneration;
|
|
12566
|
+
cancelRefreshShellSearch();
|
|
11249
12567
|
cancelOutstandingShellFallback();
|
|
11250
12568
|
if (!host || typeof host.setSession !== "function") {
|
|
11251
12569
|
const editSearch = getEditCommandSearch();
|
|
@@ -11434,6 +12752,7 @@ function createSuperDocUI(options) {
|
|
|
11434
12752
|
},
|
|
11435
12753
|
clear: () => {
|
|
11436
12754
|
searchRequestGeneration += 1;
|
|
12755
|
+
cancelRefreshShellSearch();
|
|
11437
12756
|
cancelOutstandingShellFallback();
|
|
11438
12757
|
const host = getHostSearch();
|
|
11439
12758
|
if (host && typeof host.clear === "function") safeCall(() => host.clear(), null);
|
|
@@ -11549,6 +12868,49 @@ function createSuperDocUI(options) {
|
|
|
11549
12868
|
return mapHostReplaceResult(result);
|
|
11550
12869
|
}
|
|
11551
12870
|
};
|
|
12871
|
+
let searchRefreshTimer = null;
|
|
12872
|
+
scheduleActiveSearchRefresh = () => {
|
|
12873
|
+
if (searchRefreshTimer !== null) clearTimeout(searchRefreshTimer);
|
|
12874
|
+
if (!searchState.open || !searchState.query) return;
|
|
12875
|
+
const scheduledGeneration = searchRequestGeneration;
|
|
12876
|
+
searchRefreshTimer = setTimeout(() => {
|
|
12877
|
+
searchRefreshTimer = null;
|
|
12878
|
+
if (disposed || scheduledGeneration !== searchRequestGeneration || !searchState.open || !searchState.query) return;
|
|
12879
|
+
const input = {
|
|
12880
|
+
query: searchState.query,
|
|
12881
|
+
caseSensitive: searchState.caseSensitive,
|
|
12882
|
+
includeDeletedText: searchState.includeDeletedText,
|
|
12883
|
+
regex: searchState.regex
|
|
12884
|
+
};
|
|
12885
|
+
const editSearch = getEditCommandSearch();
|
|
12886
|
+
const host = getHostSearch();
|
|
12887
|
+
if (typeof editSearch?.refresh !== "function" && typeof host?.refresh !== "function") return;
|
|
12888
|
+
const generation = ++searchRequestGeneration;
|
|
12889
|
+
cancelOutstandingShellFallback();
|
|
12890
|
+
if (typeof editSearch?.refresh === "function" && typeof editSearch.query === "function") {
|
|
12891
|
+
const capturedSearch = editSearch;
|
|
12892
|
+
releaseRefreshShellSearch = () => {
|
|
12893
|
+
capturedSearch.query({ query: "" });
|
|
12894
|
+
};
|
|
12895
|
+
}
|
|
12896
|
+
const result = typeof editSearch?.refresh === "function" ? safeCall(() => editSearch.refresh(input), null) : safeCall(() => host.refresh(), null);
|
|
12897
|
+
if (isPromiseLike(result)) {
|
|
12898
|
+
pendingFallbackGeneration = generation;
|
|
12899
|
+
Promise.resolve(result).then((resolved) => {
|
|
12900
|
+
if (generation !== searchRequestGeneration || disposed) return;
|
|
12901
|
+
pendingFallbackGeneration = null;
|
|
12902
|
+
applyHostSearchResult(resolved, readEditCommandCanReplace(), readEditCommandCanReplaceAll());
|
|
12903
|
+
}, () => {
|
|
12904
|
+
if (generation !== searchRequestGeneration || disposed) return;
|
|
12905
|
+
pendingFallbackGeneration = null;
|
|
12906
|
+
setSearchState({
|
|
12907
|
+
available: false,
|
|
12908
|
+
reason: SUPERDOC_UI_REASONS.searchUnavailable
|
|
12909
|
+
});
|
|
12910
|
+
});
|
|
12911
|
+
} else if (result !== null) applyHostSearchResult(result);
|
|
12912
|
+
}, 120);
|
|
12913
|
+
};
|
|
11552
12914
|
const stylesSub = sliceHandle((s) => s.styles);
|
|
11553
12915
|
const stylesSnap = snapshotHandle(stylesSub);
|
|
11554
12916
|
const styles = {
|
|
@@ -11563,6 +12925,15 @@ function createSuperDocUI(options) {
|
|
|
11563
12925
|
getQuickGallery: () => stylesSub.get().quickGallery,
|
|
11564
12926
|
getActiveParagraphStyle: () => computeActiveParagraphStyle(state.selection, getStyleCatalog().cache).style
|
|
11565
12927
|
};
|
|
12928
|
+
const watermark = createWatermarkController({
|
|
12929
|
+
getEditor,
|
|
12930
|
+
getMode: readDocumentMode,
|
|
12931
|
+
getFonts: () => fonts.getFamilyOptions(),
|
|
12932
|
+
getContainer: () => superdoc.element ?? null,
|
|
12933
|
+
openSurface: typeof superdoc.openSurface === "function" ? (request) => superdoc.openSurface(request) : null
|
|
12934
|
+
});
|
|
12935
|
+
documentResetHooks.push(watermark.close);
|
|
12936
|
+
documentModeChangeHooks.push(watermark.close);
|
|
11566
12937
|
const createScope = () => {
|
|
11567
12938
|
const scopeUnsubs = [];
|
|
11568
12939
|
return {
|
|
@@ -11584,8 +12955,12 @@ function createSuperDocUI(options) {
|
|
|
11584
12955
|
};
|
|
11585
12956
|
const destroy = () => {
|
|
11586
12957
|
if (disposed) return;
|
|
12958
|
+
watermark.destroy();
|
|
11587
12959
|
clearContentControlHighlight();
|
|
11588
12960
|
disposed = true;
|
|
12961
|
+
if (searchRefreshTimer !== null) clearTimeout(searchRefreshTimer);
|
|
12962
|
+
searchRefreshTimer = null;
|
|
12963
|
+
cancelRefreshShellSearch();
|
|
11589
12964
|
releaseSharedUiTrackedChangesCatalog(uiTrackedChangesCatalogHost, uiTrackedChangesCatalogState);
|
|
11590
12965
|
if (foregroundAsyncRetryTimer) {
|
|
11591
12966
|
clearTimeout(foregroundAsyncRetryTimer);
|
|
@@ -11666,6 +13041,7 @@ function createSuperDocUI(options) {
|
|
|
11666
13041
|
tables,
|
|
11667
13042
|
search,
|
|
11668
13043
|
contextMenu,
|
|
13044
|
+
watermark,
|
|
11669
13045
|
styles,
|
|
11670
13046
|
formatPainter: {
|
|
11671
13047
|
setPointerSelecting(flag) {
|
|
@@ -11878,4 +13254,81 @@ function commandIsActive(descriptor, selection) {
|
|
|
11878
13254
|
return descriptor.activeMark ? selection.activeMarks.includes(descriptor.activeMark) : false;
|
|
11879
13255
|
}
|
|
11880
13256
|
//#endregion
|
|
11881
|
-
|
|
13257
|
+
Object.defineProperty(exports, "BUILT_IN_COMMAND_IDS", {
|
|
13258
|
+
enumerable: true,
|
|
13259
|
+
get: function() {
|
|
13260
|
+
return BUILT_IN_COMMAND_IDS;
|
|
13261
|
+
}
|
|
13262
|
+
});
|
|
13263
|
+
Object.defineProperty(exports, "DOM_CLASS_NAMES", {
|
|
13264
|
+
enumerable: true,
|
|
13265
|
+
get: function() {
|
|
13266
|
+
return DOM_CLASS_NAMES;
|
|
13267
|
+
}
|
|
13268
|
+
});
|
|
13269
|
+
Object.defineProperty(exports, "applyV2CommentInvalidationFromMutation", {
|
|
13270
|
+
enumerable: true,
|
|
13271
|
+
get: function() {
|
|
13272
|
+
return applyV2CommentInvalidationFromMutation;
|
|
13273
|
+
}
|
|
13274
|
+
});
|
|
13275
|
+
Object.defineProperty(exports, "closeInteractionHistory", {
|
|
13276
|
+
enumerable: true,
|
|
13277
|
+
get: function() {
|
|
13278
|
+
return closeInteractionHistory;
|
|
13279
|
+
}
|
|
13280
|
+
});
|
|
13281
|
+
Object.defineProperty(exports, "createImageFilePicker", {
|
|
13282
|
+
enumerable: true,
|
|
13283
|
+
get: function() {
|
|
13284
|
+
return createImageFilePicker;
|
|
13285
|
+
}
|
|
13286
|
+
});
|
|
13287
|
+
Object.defineProperty(exports, "createInteractionHistory", {
|
|
13288
|
+
enumerable: true,
|
|
13289
|
+
get: function() {
|
|
13290
|
+
return createInteractionHistory;
|
|
13291
|
+
}
|
|
13292
|
+
});
|
|
13293
|
+
Object.defineProperty(exports, "createSuperDocUI", {
|
|
13294
|
+
enumerable: true,
|
|
13295
|
+
get: function() {
|
|
13296
|
+
return createSuperDocUI;
|
|
13297
|
+
}
|
|
13298
|
+
});
|
|
13299
|
+
Object.defineProperty(exports, "executeFirstPartyCommandAsync", {
|
|
13300
|
+
enumerable: true,
|
|
13301
|
+
get: function() {
|
|
13302
|
+
return executeFirstPartyCommandAsync;
|
|
13303
|
+
}
|
|
13304
|
+
});
|
|
13305
|
+
Object.defineProperty(exports, "getV2TrackedChangeMutationImpact", {
|
|
13306
|
+
enumerable: true,
|
|
13307
|
+
get: function() {
|
|
13308
|
+
return getV2TrackedChangeMutationImpact;
|
|
13309
|
+
}
|
|
13310
|
+
});
|
|
13311
|
+
Object.defineProperty(exports, "recordInteraction", {
|
|
13312
|
+
enumerable: true,
|
|
13313
|
+
get: function() {
|
|
13314
|
+
return recordInteraction;
|
|
13315
|
+
}
|
|
13316
|
+
});
|
|
13317
|
+
Object.defineProperty(exports, "registerFirstPartyCommandMutation", {
|
|
13318
|
+
enumerable: true,
|
|
13319
|
+
get: function() {
|
|
13320
|
+
return registerFirstPartyCommandMutation;
|
|
13321
|
+
}
|
|
13322
|
+
});
|
|
13323
|
+
Object.defineProperty(exports, "resolveImageSrc", {
|
|
13324
|
+
enumerable: true,
|
|
13325
|
+
get: function() {
|
|
13326
|
+
return resolveImageSrc;
|
|
13327
|
+
}
|
|
13328
|
+
});
|
|
13329
|
+
Object.defineProperty(exports, "shallowEqual", {
|
|
13330
|
+
enumerable: true,
|
|
13331
|
+
get: function() {
|
|
13332
|
+
return shallowEqual;
|
|
13333
|
+
}
|
|
13334
|
+
});
|