overtype 2.3.10 → 2.4.0
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/README.md +103 -11
- package/dist/overtype-webcomponent.esm.js +454 -96
- package/dist/overtype-webcomponent.esm.js.map +3 -3
- package/dist/overtype-webcomponent.js +454 -96
- package/dist/overtype-webcomponent.js.map +3 -3
- package/dist/overtype-webcomponent.min.js +57 -56
- package/dist/overtype.cjs +454 -96
- package/dist/overtype.cjs.map +3 -3
- package/dist/overtype.d.ts +12 -0
- package/dist/overtype.esm.js +454 -96
- package/dist/overtype.esm.js.map +3 -3
- package/dist/overtype.js +454 -96
- package/dist/overtype.js.map +3 -3
- package/dist/overtype.min.js +53 -52
- package/package.json +3 -3
- package/src/link-tooltip.js +18 -2
- package/src/overtype.d.ts +12 -0
- package/src/overtype.js +196 -70
- package/src/shortcuts.js +12 -0
- package/src/toolbar-buttons.js +10 -0
- package/src/toolbar.js +308 -49
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* OverType v2.
|
|
2
|
+
* OverType v2.4.0
|
|
3
3
|
* A lightweight markdown editor library with perfect WYSIWYG alignment
|
|
4
4
|
* @license MIT
|
|
5
5
|
* @author David Miranda
|
|
@@ -777,6 +777,16 @@ var OverTypeEditor = (() => {
|
|
|
777
777
|
const modKey = isMac ? event.metaKey : event.ctrlKey;
|
|
778
778
|
if (!modKey)
|
|
779
779
|
return false;
|
|
780
|
+
if (event.key === "]") {
|
|
781
|
+
event.preventDefault();
|
|
782
|
+
this.editor.indentSelection();
|
|
783
|
+
return true;
|
|
784
|
+
}
|
|
785
|
+
if (event.key === "[") {
|
|
786
|
+
event.preventDefault();
|
|
787
|
+
this.editor.outdentSelection();
|
|
788
|
+
return true;
|
|
789
|
+
}
|
|
780
790
|
let actionId = null;
|
|
781
791
|
switch (event.key.toLowerCase()) {
|
|
782
792
|
case "b":
|
|
@@ -2889,6 +2899,10 @@ ${blockSuffix}` : suffix;
|
|
|
2889
2899
|
this.editor = editor;
|
|
2890
2900
|
this.container = null;
|
|
2891
2901
|
this.buttons = {};
|
|
2902
|
+
this.currentItemIndex = 0;
|
|
2903
|
+
this.handleDocumentClick = null;
|
|
2904
|
+
this.activeDropdown = null;
|
|
2905
|
+
this.activeDropdownButton = null;
|
|
2892
2906
|
this.toolbarButtons = options.toolbarButtons || [];
|
|
2893
2907
|
}
|
|
2894
2908
|
/**
|
|
@@ -2897,8 +2911,10 @@ ${blockSuffix}` : suffix;
|
|
|
2897
2911
|
create() {
|
|
2898
2912
|
this.container = document.createElement("div");
|
|
2899
2913
|
this.container.className = "overtype-toolbar";
|
|
2914
|
+
this.container.id = this.getInstanceElementId("toolbar");
|
|
2900
2915
|
this.container.setAttribute("role", "toolbar");
|
|
2901
2916
|
this.container.setAttribute("aria-label", "Formatting toolbar");
|
|
2917
|
+
this.container.setAttribute("aria-controls", this.editor.textarea.id);
|
|
2902
2918
|
this.toolbarButtons.forEach((buttonConfig) => {
|
|
2903
2919
|
if (buttonConfig.name === "separator") {
|
|
2904
2920
|
const separator = this.createSeparator();
|
|
@@ -2909,8 +2925,116 @@ ${blockSuffix}` : suffix;
|
|
|
2909
2925
|
this.container.appendChild(button);
|
|
2910
2926
|
}
|
|
2911
2927
|
});
|
|
2928
|
+
this.setupRovingTabIndex();
|
|
2929
|
+
this.updateButtonStates();
|
|
2912
2930
|
this.editor.container.insertBefore(this.container, this.editor.wrapper);
|
|
2913
2931
|
}
|
|
2932
|
+
/**
|
|
2933
|
+
* Build a stable id from the owning OverType instance
|
|
2934
|
+
*/
|
|
2935
|
+
getInstanceElementId(name) {
|
|
2936
|
+
return `overtype-${this.editor.instanceId}-${name}`;
|
|
2937
|
+
}
|
|
2938
|
+
/**
|
|
2939
|
+
* Configure toolbar focus management per the ARIA toolbar pattern
|
|
2940
|
+
*/
|
|
2941
|
+
setupRovingTabIndex() {
|
|
2942
|
+
const toolbarItems = this.getToolbarItems();
|
|
2943
|
+
if (toolbarItems.length === 0) {
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
this.currentItemIndex = this.getValidItemIndex(this.currentItemIndex);
|
|
2947
|
+
this.updateTabIndexes();
|
|
2948
|
+
this.container.addEventListener("keydown", (e) => {
|
|
2949
|
+
this.onToolbarKeydown(e);
|
|
2950
|
+
});
|
|
2951
|
+
this.container.addEventListener("focusin", (e) => {
|
|
2952
|
+
this.onToolbarFocusin(e);
|
|
2953
|
+
});
|
|
2954
|
+
}
|
|
2955
|
+
/**
|
|
2956
|
+
* Get toolbar buttons in DOM order for keyboard navigation
|
|
2957
|
+
*/
|
|
2958
|
+
getToolbarItems() {
|
|
2959
|
+
if (!this.container) {
|
|
2960
|
+
return [];
|
|
2961
|
+
}
|
|
2962
|
+
return Array.from(this.container.querySelectorAll(".overtype-toolbar-button"));
|
|
2963
|
+
}
|
|
2964
|
+
/**
|
|
2965
|
+
* Handle keyboard navigation within the toolbar
|
|
2966
|
+
*/
|
|
2967
|
+
onToolbarKeydown(e) {
|
|
2968
|
+
const toolbarItems = this.getToolbarItems();
|
|
2969
|
+
if (!toolbarItems.includes(e.target)) {
|
|
2970
|
+
return;
|
|
2971
|
+
}
|
|
2972
|
+
switch (e.key) {
|
|
2973
|
+
case "ArrowRight":
|
|
2974
|
+
e.preventDefault();
|
|
2975
|
+
this.focusItem(this.currentItemIndex + 1);
|
|
2976
|
+
break;
|
|
2977
|
+
case "ArrowLeft":
|
|
2978
|
+
e.preventDefault();
|
|
2979
|
+
this.focusItem(this.currentItemIndex - 1);
|
|
2980
|
+
break;
|
|
2981
|
+
case "Home":
|
|
2982
|
+
e.preventDefault();
|
|
2983
|
+
this.focusItem(0);
|
|
2984
|
+
break;
|
|
2985
|
+
case "End":
|
|
2986
|
+
e.preventDefault();
|
|
2987
|
+
this.focusItem(toolbarItems.length - 1);
|
|
2988
|
+
break;
|
|
2989
|
+
}
|
|
2990
|
+
}
|
|
2991
|
+
/**
|
|
2992
|
+
* Remember the focused toolbar item as the toolbar tab stop
|
|
2993
|
+
*/
|
|
2994
|
+
onToolbarFocusin(e) {
|
|
2995
|
+
const focusedItemIndex = this.getToolbarItems().indexOf(e.target);
|
|
2996
|
+
if (focusedItemIndex === -1) {
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
this.currentItemIndex = focusedItemIndex;
|
|
3000
|
+
this.updateTabIndexes();
|
|
3001
|
+
}
|
|
3002
|
+
/**
|
|
3003
|
+
* Move focus to a toolbar item and make it the only tab stop
|
|
3004
|
+
*/
|
|
3005
|
+
focusItem(index) {
|
|
3006
|
+
const toolbarItems = this.getToolbarItems();
|
|
3007
|
+
if (toolbarItems.length === 0) {
|
|
3008
|
+
return;
|
|
3009
|
+
}
|
|
3010
|
+
this.currentItemIndex = this.getValidItemIndex(index, toolbarItems);
|
|
3011
|
+
this.updateTabIndexes();
|
|
3012
|
+
toolbarItems[this.currentItemIndex].focus();
|
|
3013
|
+
}
|
|
3014
|
+
/**
|
|
3015
|
+
* Normalize toolbar item indexes with wrapping
|
|
3016
|
+
*/
|
|
3017
|
+
getValidItemIndex(index, toolbarItems = this.getToolbarItems()) {
|
|
3018
|
+
const itemCount = toolbarItems.length;
|
|
3019
|
+
if (itemCount === 0) {
|
|
3020
|
+
return 0;
|
|
3021
|
+
}
|
|
3022
|
+
if (index < 0) {
|
|
3023
|
+
return itemCount - 1;
|
|
3024
|
+
}
|
|
3025
|
+
if (index >= itemCount) {
|
|
3026
|
+
return 0;
|
|
3027
|
+
}
|
|
3028
|
+
return index;
|
|
3029
|
+
}
|
|
3030
|
+
/**
|
|
3031
|
+
* Keep exactly one toolbar item in the page tab sequence
|
|
3032
|
+
*/
|
|
3033
|
+
updateTabIndexes() {
|
|
3034
|
+
this.getToolbarItems().forEach((item, index) => {
|
|
3035
|
+
item.tabIndex = index === this.currentItemIndex ? 0 : -1;
|
|
3036
|
+
});
|
|
3037
|
+
}
|
|
2914
3038
|
/**
|
|
2915
3039
|
* Create a toolbar separator
|
|
2916
3040
|
*/
|
|
@@ -2934,10 +3058,22 @@ ${blockSuffix}` : suffix;
|
|
|
2934
3058
|
if (buttonConfig.name === "viewMode") {
|
|
2935
3059
|
button.classList.add("has-dropdown");
|
|
2936
3060
|
button.dataset.dropdown = "true";
|
|
2937
|
-
button.
|
|
3061
|
+
button.setAttribute("aria-haspopup", "menu");
|
|
3062
|
+
button.setAttribute("aria-expanded", "false");
|
|
3063
|
+
button._clickHandler = (e) => {
|
|
2938
3064
|
e.preventDefault();
|
|
2939
3065
|
this.toggleViewModeDropdown(button);
|
|
2940
|
-
}
|
|
3066
|
+
};
|
|
3067
|
+
button._keydownHandler = (e) => {
|
|
3068
|
+
if (!["ArrowDown", "ArrowUp", "Enter", " "].includes(e.key)) {
|
|
3069
|
+
return;
|
|
3070
|
+
}
|
|
3071
|
+
e.preventDefault();
|
|
3072
|
+
const placement = e.key === "ArrowUp" ? "last" : "current";
|
|
3073
|
+
this.openViewModeDropdown(button, placement);
|
|
3074
|
+
};
|
|
3075
|
+
button.addEventListener("click", button._clickHandler);
|
|
3076
|
+
button.addEventListener("keydown", button._keydownHandler);
|
|
2941
3077
|
return button;
|
|
2942
3078
|
}
|
|
2943
3079
|
button._clickHandler = (e) => {
|
|
@@ -2992,12 +3128,17 @@ ${blockSuffix}` : suffix;
|
|
|
2992
3128
|
* Not exposed to users - viewMode button behavior is fixed
|
|
2993
3129
|
*/
|
|
2994
3130
|
toggleViewModeDropdown(button) {
|
|
2995
|
-
|
|
2996
|
-
|
|
2997
|
-
existingDropdown.remove();
|
|
2998
|
-
button.classList.remove("dropdown-active");
|
|
3131
|
+
if (this.activeDropdown) {
|
|
3132
|
+
this.closeViewModeDropdown(button);
|
|
2999
3133
|
return;
|
|
3000
3134
|
}
|
|
3135
|
+
this.openViewModeDropdown(button);
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* Open the view mode dropdown
|
|
3139
|
+
*/
|
|
3140
|
+
openViewModeDropdown(button, focusPlacement = null) {
|
|
3141
|
+
this.closeViewModeDropdown(button);
|
|
3001
3142
|
button.classList.add("dropdown-active");
|
|
3002
3143
|
const dropdown = this.createViewModeDropdown(button);
|
|
3003
3144
|
const rect = button.getBoundingClientRect();
|
|
@@ -3005,16 +3146,42 @@ ${blockSuffix}` : suffix;
|
|
|
3005
3146
|
dropdown.style.top = `${rect.bottom + 5}px`;
|
|
3006
3147
|
dropdown.style.left = `${rect.left}px`;
|
|
3007
3148
|
document.body.appendChild(dropdown);
|
|
3149
|
+
this.activeDropdown = dropdown;
|
|
3150
|
+
this.activeDropdownButton = button;
|
|
3151
|
+
button.setAttribute("aria-controls", dropdown.id);
|
|
3152
|
+
button.setAttribute("aria-expanded", "true");
|
|
3008
3153
|
this.handleDocumentClick = (e) => {
|
|
3009
3154
|
if (!dropdown.contains(e.target) && !button.contains(e.target)) {
|
|
3010
|
-
|
|
3011
|
-
button.classList.remove("dropdown-active");
|
|
3012
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
3155
|
+
this.closeViewModeDropdown(button);
|
|
3013
3156
|
}
|
|
3014
3157
|
};
|
|
3015
3158
|
setTimeout(() => {
|
|
3016
3159
|
document.addEventListener("click", this.handleDocumentClick);
|
|
3017
3160
|
}, 0);
|
|
3161
|
+
if (focusPlacement) {
|
|
3162
|
+
this.focusViewModeMenuItem(dropdown, focusPlacement);
|
|
3163
|
+
}
|
|
3164
|
+
}
|
|
3165
|
+
/**
|
|
3166
|
+
* Close the view mode dropdown
|
|
3167
|
+
*/
|
|
3168
|
+
closeViewModeDropdown(button = this.activeDropdownButton, returnFocus = false) {
|
|
3169
|
+
if (this.activeDropdown) {
|
|
3170
|
+
this.activeDropdown.remove();
|
|
3171
|
+
this.activeDropdown = null;
|
|
3172
|
+
}
|
|
3173
|
+
if (button) {
|
|
3174
|
+
button.classList.remove("dropdown-active");
|
|
3175
|
+
button.setAttribute("aria-expanded", "false");
|
|
3176
|
+
}
|
|
3177
|
+
if (this.handleDocumentClick) {
|
|
3178
|
+
document.removeEventListener("click", this.handleDocumentClick);
|
|
3179
|
+
this.handleDocumentClick = null;
|
|
3180
|
+
}
|
|
3181
|
+
this.activeDropdownButton = null;
|
|
3182
|
+
if (returnFocus && button) {
|
|
3183
|
+
button.focus();
|
|
3184
|
+
}
|
|
3018
3185
|
}
|
|
3019
3186
|
/**
|
|
3020
3187
|
* Create view mode dropdown menu (internal implementation)
|
|
@@ -3022,6 +3189,12 @@ ${blockSuffix}` : suffix;
|
|
|
3022
3189
|
createViewModeDropdown(button) {
|
|
3023
3190
|
const dropdown = document.createElement("div");
|
|
3024
3191
|
dropdown.className = "overtype-dropdown-menu";
|
|
3192
|
+
dropdown.id = this.getInstanceElementId("toolbar-view-mode-menu");
|
|
3193
|
+
dropdown.setAttribute("role", "menu");
|
|
3194
|
+
dropdown.setAttribute("aria-label", "View mode");
|
|
3195
|
+
dropdown.addEventListener("keydown", (e) => {
|
|
3196
|
+
this.onViewModeMenuKeydown(e, button);
|
|
3197
|
+
});
|
|
3025
3198
|
const items = [
|
|
3026
3199
|
{ id: "normal", label: "Normal Edit", icon: "\u2713" },
|
|
3027
3200
|
{ id: "plain", label: "Plain Textarea", icon: "\u2713" },
|
|
@@ -3032,12 +3205,15 @@ ${blockSuffix}` : suffix;
|
|
|
3032
3205
|
const menuItem = document.createElement("button");
|
|
3033
3206
|
menuItem.className = "overtype-dropdown-item";
|
|
3034
3207
|
menuItem.type = "button";
|
|
3208
|
+
menuItem.tabIndex = -1;
|
|
3209
|
+
menuItem.setAttribute("role", "menuitemradio");
|
|
3210
|
+
menuItem.setAttribute("aria-checked", String(item.id === currentMode));
|
|
3035
3211
|
menuItem.textContent = item.label;
|
|
3036
3212
|
if (item.id === currentMode) {
|
|
3037
3213
|
menuItem.classList.add("active");
|
|
3038
|
-
menuItem.setAttribute("aria-current", "true");
|
|
3039
3214
|
const checkmark = document.createElement("span");
|
|
3040
3215
|
checkmark.className = "overtype-dropdown-icon";
|
|
3216
|
+
checkmark.setAttribute("aria-hidden", "true");
|
|
3041
3217
|
checkmark.textContent = item.icon;
|
|
3042
3218
|
menuItem.prepend(checkmark);
|
|
3043
3219
|
}
|
|
@@ -3055,14 +3231,77 @@ ${blockSuffix}` : suffix;
|
|
|
3055
3231
|
this.editor.showNormalEditMode();
|
|
3056
3232
|
break;
|
|
3057
3233
|
}
|
|
3058
|
-
|
|
3059
|
-
button.classList.remove("dropdown-active");
|
|
3060
|
-
document.removeEventListener("click", this.handleDocumentClick);
|
|
3234
|
+
this.closeViewModeDropdown(button, true);
|
|
3061
3235
|
});
|
|
3062
3236
|
dropdown.appendChild(menuItem);
|
|
3063
3237
|
});
|
|
3064
3238
|
return dropdown;
|
|
3065
3239
|
}
|
|
3240
|
+
/**
|
|
3241
|
+
* Handle keyboard navigation inside the view mode menu
|
|
3242
|
+
*/
|
|
3243
|
+
onViewModeMenuKeydown(e, button) {
|
|
3244
|
+
const menuItems = this.getViewModeMenuItems();
|
|
3245
|
+
const currentIndex = menuItems.indexOf(e.target);
|
|
3246
|
+
if (currentIndex === -1) {
|
|
3247
|
+
return;
|
|
3248
|
+
}
|
|
3249
|
+
switch (e.key) {
|
|
3250
|
+
case "ArrowDown":
|
|
3251
|
+
e.preventDefault();
|
|
3252
|
+
this.focusViewModeMenuItem(this.activeDropdown, currentIndex + 1);
|
|
3253
|
+
break;
|
|
3254
|
+
case "ArrowUp":
|
|
3255
|
+
e.preventDefault();
|
|
3256
|
+
this.focusViewModeMenuItem(this.activeDropdown, currentIndex - 1);
|
|
3257
|
+
break;
|
|
3258
|
+
case "Home":
|
|
3259
|
+
e.preventDefault();
|
|
3260
|
+
this.focusViewModeMenuItem(this.activeDropdown, "first");
|
|
3261
|
+
break;
|
|
3262
|
+
case "End":
|
|
3263
|
+
e.preventDefault();
|
|
3264
|
+
this.focusViewModeMenuItem(this.activeDropdown, "last");
|
|
3265
|
+
break;
|
|
3266
|
+
case "Escape":
|
|
3267
|
+
e.preventDefault();
|
|
3268
|
+
this.closeViewModeDropdown(button, true);
|
|
3269
|
+
break;
|
|
3270
|
+
}
|
|
3271
|
+
}
|
|
3272
|
+
/**
|
|
3273
|
+
* Focus a view mode menu item by index or placement
|
|
3274
|
+
*/
|
|
3275
|
+
focusViewModeMenuItem(dropdown, placement) {
|
|
3276
|
+
const menuItems = this.getViewModeMenuItems(dropdown);
|
|
3277
|
+
if (menuItems.length === 0) {
|
|
3278
|
+
return;
|
|
3279
|
+
}
|
|
3280
|
+
let index = placement;
|
|
3281
|
+
if (placement === "first") {
|
|
3282
|
+
index = 0;
|
|
3283
|
+
} else if (placement === "last") {
|
|
3284
|
+
index = menuItems.length - 1;
|
|
3285
|
+
} else if (placement === "current") {
|
|
3286
|
+
index = menuItems.findIndex((item) => item.getAttribute("aria-checked") === "true");
|
|
3287
|
+
}
|
|
3288
|
+
if (index < 0) {
|
|
3289
|
+
index = menuItems.length - 1;
|
|
3290
|
+
}
|
|
3291
|
+
if (index >= menuItems.length) {
|
|
3292
|
+
index = 0;
|
|
3293
|
+
}
|
|
3294
|
+
menuItems[index].focus();
|
|
3295
|
+
}
|
|
3296
|
+
/**
|
|
3297
|
+
* Get the current view mode menu items
|
|
3298
|
+
*/
|
|
3299
|
+
getViewModeMenuItems(dropdown = this.activeDropdown) {
|
|
3300
|
+
if (!dropdown) {
|
|
3301
|
+
return [];
|
|
3302
|
+
}
|
|
3303
|
+
return Array.from(dropdown.querySelectorAll('[role="menuitemradio"]'));
|
|
3304
|
+
}
|
|
3066
3305
|
/**
|
|
3067
3306
|
* Update active states of toolbar buttons
|
|
3068
3307
|
*/
|
|
@@ -3076,39 +3315,14 @@ ${blockSuffix}` : suffix;
|
|
|
3076
3315
|
Object.entries(this.buttons).forEach(([name, button]) => {
|
|
3077
3316
|
if (name === "viewMode")
|
|
3078
3317
|
return;
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
isActive = activeFormats.includes("bold");
|
|
3083
|
-
break;
|
|
3084
|
-
case "italic":
|
|
3085
|
-
isActive = activeFormats.includes("italic");
|
|
3086
|
-
break;
|
|
3087
|
-
case "code":
|
|
3088
|
-
isActive = false;
|
|
3089
|
-
break;
|
|
3090
|
-
case "bulletList":
|
|
3091
|
-
isActive = activeFormats.includes("bullet-list");
|
|
3092
|
-
break;
|
|
3093
|
-
case "orderedList":
|
|
3094
|
-
isActive = activeFormats.includes("numbered-list");
|
|
3095
|
-
break;
|
|
3096
|
-
case "taskList":
|
|
3097
|
-
isActive = activeFormats.includes("task-list");
|
|
3098
|
-
break;
|
|
3099
|
-
case "quote":
|
|
3100
|
-
isActive = activeFormats.includes("quote");
|
|
3101
|
-
break;
|
|
3102
|
-
case "h1":
|
|
3103
|
-
isActive = activeFormats.includes("header");
|
|
3104
|
-
break;
|
|
3105
|
-
case "h2":
|
|
3106
|
-
isActive = activeFormats.includes("header-2");
|
|
3107
|
-
break;
|
|
3108
|
-
case "h3":
|
|
3109
|
-
isActive = activeFormats.includes("header-3");
|
|
3110
|
-
break;
|
|
3318
|
+
const buttonConfig = this.toolbarButtons.find((buttonConfig2) => buttonConfig2.name === name);
|
|
3319
|
+
if (!(buttonConfig == null ? void 0 : buttonConfig.isActive)) {
|
|
3320
|
+
return;
|
|
3111
3321
|
}
|
|
3322
|
+
const isActive = Boolean(buttonConfig.isActive({
|
|
3323
|
+
editor: this.editor,
|
|
3324
|
+
activeFormats
|
|
3325
|
+
}));
|
|
3112
3326
|
button.classList.toggle("active", isActive);
|
|
3113
3327
|
button.setAttribute("aria-pressed", isActive.toString());
|
|
3114
3328
|
});
|
|
@@ -3130,14 +3344,21 @@ ${blockSuffix}` : suffix;
|
|
|
3130
3344
|
*/
|
|
3131
3345
|
destroy() {
|
|
3132
3346
|
if (this.container) {
|
|
3133
|
-
if (this.
|
|
3347
|
+
if (this.activeDropdown) {
|
|
3348
|
+
this.closeViewModeDropdown();
|
|
3349
|
+
} else if (this.handleDocumentClick) {
|
|
3134
3350
|
document.removeEventListener("click", this.handleDocumentClick);
|
|
3351
|
+
this.handleDocumentClick = null;
|
|
3135
3352
|
}
|
|
3136
3353
|
Object.values(this.buttons).forEach((button) => {
|
|
3137
3354
|
if (button._clickHandler) {
|
|
3138
3355
|
button.removeEventListener("click", button._clickHandler);
|
|
3139
3356
|
delete button._clickHandler;
|
|
3140
3357
|
}
|
|
3358
|
+
if (button._keydownHandler) {
|
|
3359
|
+
button.removeEventListener("keydown", button._keydownHandler);
|
|
3360
|
+
delete button._keydownHandler;
|
|
3361
|
+
}
|
|
3141
3362
|
});
|
|
3142
3363
|
this.container.remove();
|
|
3143
3364
|
this.container = null;
|
|
@@ -4404,7 +4625,10 @@ ${blockSuffix}` : suffix;
|
|
|
4404
4625
|
e.preventDefault();
|
|
4405
4626
|
e.stopPropagation();
|
|
4406
4627
|
if (this.currentLink) {
|
|
4407
|
-
|
|
4628
|
+
const safeUrl = MarkdownParser.sanitizeUrl(this.currentLink.url);
|
|
4629
|
+
if (safeUrl !== "#") {
|
|
4630
|
+
window.open(safeUrl, "_blank");
|
|
4631
|
+
}
|
|
4408
4632
|
this.hide();
|
|
4409
4633
|
}
|
|
4410
4634
|
});
|
|
@@ -4432,7 +4656,7 @@ ${blockSuffix}` : suffix;
|
|
|
4432
4656
|
if (position >= start && position <= end) {
|
|
4433
4657
|
return {
|
|
4434
4658
|
text: match[1],
|
|
4435
|
-
url: match[2],
|
|
4659
|
+
url: this.transformUrl(match[2]),
|
|
4436
4660
|
index: linkIndex,
|
|
4437
4661
|
start,
|
|
4438
4662
|
end
|
|
@@ -4442,6 +4666,18 @@ ${blockSuffix}` : suffix;
|
|
|
4442
4666
|
}
|
|
4443
4667
|
return null;
|
|
4444
4668
|
}
|
|
4669
|
+
transformUrl(url) {
|
|
4670
|
+
const transform = this.editor.options.transformLinkUrl;
|
|
4671
|
+
if (typeof transform !== "function")
|
|
4672
|
+
return url;
|
|
4673
|
+
try {
|
|
4674
|
+
const result = transform(url);
|
|
4675
|
+
return typeof result === "string" ? result : url;
|
|
4676
|
+
} catch (e) {
|
|
4677
|
+
console.warn("transformLinkUrl threw:", e);
|
|
4678
|
+
return url;
|
|
4679
|
+
}
|
|
4680
|
+
}
|
|
4445
4681
|
async show(linkInfo) {
|
|
4446
4682
|
this.currentLink = linkInfo;
|
|
4447
4683
|
this.cancelHide();
|
|
@@ -4593,6 +4829,7 @@ ${blockSuffix}` : suffix;
|
|
|
4593
4829
|
actionId: "toggleBold",
|
|
4594
4830
|
icon: boldIcon,
|
|
4595
4831
|
title: "Bold (Ctrl+B)",
|
|
4832
|
+
isActive: ({ activeFormats }) => activeFormats.includes("bold"),
|
|
4596
4833
|
action: ({ editor }) => {
|
|
4597
4834
|
toggleBold(editor.textarea);
|
|
4598
4835
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4603,6 +4840,7 @@ ${blockSuffix}` : suffix;
|
|
|
4603
4840
|
actionId: "toggleItalic",
|
|
4604
4841
|
icon: italicIcon,
|
|
4605
4842
|
title: "Italic (Ctrl+I)",
|
|
4843
|
+
isActive: ({ activeFormats }) => activeFormats.includes("italic"),
|
|
4606
4844
|
action: ({ editor }) => {
|
|
4607
4845
|
toggleItalic(editor.textarea);
|
|
4608
4846
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4613,6 +4851,7 @@ ${blockSuffix}` : suffix;
|
|
|
4613
4851
|
actionId: "toggleCode",
|
|
4614
4852
|
icon: codeIcon,
|
|
4615
4853
|
title: "Inline Code",
|
|
4854
|
+
isActive: () => false,
|
|
4616
4855
|
action: ({ editor }) => {
|
|
4617
4856
|
toggleCode(editor.textarea);
|
|
4618
4857
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4637,6 +4876,7 @@ ${blockSuffix}` : suffix;
|
|
|
4637
4876
|
actionId: "toggleH1",
|
|
4638
4877
|
icon: h1Icon,
|
|
4639
4878
|
title: "Heading 1",
|
|
4879
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header"),
|
|
4640
4880
|
action: ({ editor }) => {
|
|
4641
4881
|
toggleH1(editor.textarea);
|
|
4642
4882
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4647,6 +4887,7 @@ ${blockSuffix}` : suffix;
|
|
|
4647
4887
|
actionId: "toggleH2",
|
|
4648
4888
|
icon: h2Icon,
|
|
4649
4889
|
title: "Heading 2",
|
|
4890
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header-2"),
|
|
4650
4891
|
action: ({ editor }) => {
|
|
4651
4892
|
toggleH2(editor.textarea);
|
|
4652
4893
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4657,6 +4898,7 @@ ${blockSuffix}` : suffix;
|
|
|
4657
4898
|
actionId: "toggleH3",
|
|
4658
4899
|
icon: h3Icon,
|
|
4659
4900
|
title: "Heading 3",
|
|
4901
|
+
isActive: ({ activeFormats }) => activeFormats.includes("header-3"),
|
|
4660
4902
|
action: ({ editor }) => {
|
|
4661
4903
|
toggleH3(editor.textarea);
|
|
4662
4904
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4667,6 +4909,7 @@ ${blockSuffix}` : suffix;
|
|
|
4667
4909
|
actionId: "toggleBulletList",
|
|
4668
4910
|
icon: bulletListIcon,
|
|
4669
4911
|
title: "Bullet List",
|
|
4912
|
+
isActive: ({ activeFormats }) => activeFormats.includes("bullet-list"),
|
|
4670
4913
|
action: ({ editor }) => {
|
|
4671
4914
|
toggleBulletList(editor.textarea);
|
|
4672
4915
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4677,6 +4920,7 @@ ${blockSuffix}` : suffix;
|
|
|
4677
4920
|
actionId: "toggleNumberedList",
|
|
4678
4921
|
icon: orderedListIcon,
|
|
4679
4922
|
title: "Numbered List",
|
|
4923
|
+
isActive: ({ activeFormats }) => activeFormats.includes("numbered-list"),
|
|
4680
4924
|
action: ({ editor }) => {
|
|
4681
4925
|
toggleNumberedList(editor.textarea);
|
|
4682
4926
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4687,6 +4931,7 @@ ${blockSuffix}` : suffix;
|
|
|
4687
4931
|
actionId: "toggleTaskList",
|
|
4688
4932
|
icon: taskListIcon,
|
|
4689
4933
|
title: "Task List",
|
|
4934
|
+
isActive: ({ activeFormats }) => activeFormats.includes("task-list"),
|
|
4690
4935
|
action: ({ editor }) => {
|
|
4691
4936
|
if (toggleTaskList) {
|
|
4692
4937
|
toggleTaskList(editor.textarea);
|
|
@@ -4699,6 +4944,7 @@ ${blockSuffix}` : suffix;
|
|
|
4699
4944
|
actionId: "toggleQuote",
|
|
4700
4945
|
icon: quoteIcon,
|
|
4701
4946
|
title: "Quote",
|
|
4947
|
+
isActive: ({ activeFormats }) => activeFormats.includes("quote"),
|
|
4702
4948
|
action: ({ editor }) => {
|
|
4703
4949
|
toggleQuote(editor.textarea);
|
|
4704
4950
|
editor.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
@@ -4760,6 +5006,17 @@ ${blockSuffix}` : suffix;
|
|
|
4760
5006
|
];
|
|
4761
5007
|
|
|
4762
5008
|
// src/overtype.js
|
|
5009
|
+
var _isSafariCache;
|
|
5010
|
+
function isSafariBrowser() {
|
|
5011
|
+
if (_isSafariCache !== void 0)
|
|
5012
|
+
return _isSafariCache;
|
|
5013
|
+
_isSafariCache = false;
|
|
5014
|
+
if (typeof navigator !== "undefined") {
|
|
5015
|
+
const ua = navigator.userAgent || "";
|
|
5016
|
+
_isSafariCache = /^((?!chrome|android|crios|fxios|edg|opr).)*safari/i.test(ua) || /iPad|iPhone|iPod/.test(ua) || navigator.platform === "MacIntel" && navigator.maxTouchPoints > 1 && /Safari/.test(ua);
|
|
5017
|
+
}
|
|
5018
|
+
return _isSafariCache;
|
|
5019
|
+
}
|
|
4763
5020
|
function buildActionsMap(buttons) {
|
|
4764
5021
|
const map = {};
|
|
4765
5022
|
(buttons || []).forEach((btn) => {
|
|
@@ -4834,6 +5091,8 @@ ${blockSuffix}` : suffix;
|
|
|
4834
5091
|
this.options = this._mergeOptions(options);
|
|
4835
5092
|
this.instanceId = ++_OverType.instanceCount;
|
|
4836
5093
|
this.initialized = false;
|
|
5094
|
+
this._isSafari = isSafariBrowser();
|
|
5095
|
+
this._safariReflowRaf = null;
|
|
4837
5096
|
_OverType.injectStyles();
|
|
4838
5097
|
_OverType.initGlobalListeners();
|
|
4839
5098
|
const container = element.querySelector(".overtype-container");
|
|
@@ -4908,8 +5167,10 @@ ${blockSuffix}` : suffix;
|
|
|
4908
5167
|
// Enable smart list continuation
|
|
4909
5168
|
codeHighlighter: null,
|
|
4910
5169
|
// Per-instance code highlighter
|
|
4911
|
-
spellcheck: false
|
|
5170
|
+
spellcheck: false,
|
|
4912
5171
|
// Browser spellcheck (disabled by default)
|
|
5172
|
+
transformLinkUrl: null
|
|
5173
|
+
// Transform URLs shown/opened in the link tooltip
|
|
4913
5174
|
};
|
|
4914
5175
|
const { theme, colors, ...cleanOptions } = options;
|
|
4915
5176
|
return {
|
|
@@ -4962,6 +5223,8 @@ ${blockSuffix}` : suffix;
|
|
|
4962
5223
|
this.wrapper._instance = this;
|
|
4963
5224
|
this._applyInstanceCSSVars();
|
|
4964
5225
|
this._configureTextarea();
|
|
5226
|
+
this._ensureTextareaId();
|
|
5227
|
+
this._syncPreviewInteractivity();
|
|
4965
5228
|
this._applyOptions();
|
|
4966
5229
|
}
|
|
4967
5230
|
/**
|
|
@@ -5025,6 +5288,7 @@ ${blockSuffix}` : suffix;
|
|
|
5025
5288
|
}
|
|
5026
5289
|
});
|
|
5027
5290
|
}
|
|
5291
|
+
this._ensureTextareaId();
|
|
5028
5292
|
this.preview = document.createElement("div");
|
|
5029
5293
|
this.preview.className = "overtype-preview";
|
|
5030
5294
|
this.preview.setAttribute("aria-hidden", "true");
|
|
@@ -5048,6 +5312,7 @@ ${blockSuffix}` : suffix;
|
|
|
5048
5312
|
} else {
|
|
5049
5313
|
this.container.classList.remove("overtype-auto-resize");
|
|
5050
5314
|
}
|
|
5315
|
+
this._syncPreviewInteractivity();
|
|
5051
5316
|
}
|
|
5052
5317
|
/**
|
|
5053
5318
|
* Configure textarea attributes
|
|
@@ -5062,6 +5327,31 @@ ${blockSuffix}` : suffix;
|
|
|
5062
5327
|
this.textarea.setAttribute("data-gramm_editor", "false");
|
|
5063
5328
|
this.textarea.setAttribute("data-enable-grammarly", "false");
|
|
5064
5329
|
}
|
|
5330
|
+
/**
|
|
5331
|
+
* Ensure the textarea can be referenced by aria-controls
|
|
5332
|
+
* @private
|
|
5333
|
+
*/
|
|
5334
|
+
_ensureTextareaId() {
|
|
5335
|
+
if (!this.textarea.id) {
|
|
5336
|
+
this.textarea.id = `overtype-${this.instanceId}-input`;
|
|
5337
|
+
}
|
|
5338
|
+
}
|
|
5339
|
+
/**
|
|
5340
|
+
* Keep rendered preview content out of keyboard navigation until Preview mode.
|
|
5341
|
+
* @private
|
|
5342
|
+
*/
|
|
5343
|
+
_syncPreviewInteractivity() {
|
|
5344
|
+
if (!this.preview || !this.container)
|
|
5345
|
+
return;
|
|
5346
|
+
const isPreviewMode = this.container.dataset.mode === "preview";
|
|
5347
|
+
this.preview.inert = !isPreviewMode;
|
|
5348
|
+
this.preview.toggleAttribute("inert", !isPreviewMode);
|
|
5349
|
+
if (isPreviewMode) {
|
|
5350
|
+
this.preview.removeAttribute("aria-hidden");
|
|
5351
|
+
return;
|
|
5352
|
+
}
|
|
5353
|
+
this.preview.setAttribute("aria-hidden", "true");
|
|
5354
|
+
}
|
|
5065
5355
|
/**
|
|
5066
5356
|
* Create and setup toolbar
|
|
5067
5357
|
* @private
|
|
@@ -5400,6 +5690,29 @@ ${blockSuffix}` : suffix;
|
|
|
5400
5690
|
handleInput(event) {
|
|
5401
5691
|
this.updatePreview();
|
|
5402
5692
|
this._notifyChange();
|
|
5693
|
+
this._scheduleSafariReflow();
|
|
5694
|
+
}
|
|
5695
|
+
/**
|
|
5696
|
+
* Force Safari to re-shape stale textarea text after an edit.
|
|
5697
|
+
* Safari can leave a textarea's glyph layout cached after incremental edits,
|
|
5698
|
+
* desyncing the caret/wrap from the styled preview overlay. Toggling
|
|
5699
|
+
* letter-spacing (with !important to beat the stylesheet rule) and reading
|
|
5700
|
+
* offsetHeight forces a synchronous re-shape. Safari-only, coalesced to one
|
|
5701
|
+
* run per animation frame.
|
|
5702
|
+
* @private
|
|
5703
|
+
*/
|
|
5704
|
+
_scheduleSafariReflow() {
|
|
5705
|
+
if (!this._isSafari || this._safariReflowRaf)
|
|
5706
|
+
return;
|
|
5707
|
+
this._safariReflowRaf = requestAnimationFrame(() => {
|
|
5708
|
+
this._safariReflowRaf = null;
|
|
5709
|
+
const ta = this.textarea;
|
|
5710
|
+
if (!ta)
|
|
5711
|
+
return;
|
|
5712
|
+
ta.style.setProperty("letter-spacing", "-0.001px", "important");
|
|
5713
|
+
void ta.offsetHeight;
|
|
5714
|
+
ta.style.removeProperty("letter-spacing");
|
|
5715
|
+
});
|
|
5403
5716
|
}
|
|
5404
5717
|
/**
|
|
5405
5718
|
* Handle focus events
|
|
@@ -5427,49 +5740,11 @@ ${blockSuffix}` : suffix;
|
|
|
5427
5740
|
if (event.key === "Tab") {
|
|
5428
5741
|
const start = this.textarea.selectionStart;
|
|
5429
5742
|
const end = this.textarea.selectionEnd;
|
|
5430
|
-
|
|
5431
|
-
|
|
5743
|
+
if (start !== end && this._canEditTextarea()) {
|
|
5744
|
+
event.preventDefault();
|
|
5745
|
+
event.shiftKey ? this.outdentSelection() : this.indentSelection();
|
|
5432
5746
|
return;
|
|
5433
5747
|
}
|
|
5434
|
-
event.preventDefault();
|
|
5435
|
-
if (start !== end && event.shiftKey) {
|
|
5436
|
-
const before = value.substring(0, start);
|
|
5437
|
-
const selection = value.substring(start, end);
|
|
5438
|
-
const after = value.substring(end);
|
|
5439
|
-
const lines = selection.split("\n");
|
|
5440
|
-
const outdented = lines.map((line) => line.replace(/^ /, "")).join("\n");
|
|
5441
|
-
if (document.execCommand) {
|
|
5442
|
-
this.textarea.setSelectionRange(start, end);
|
|
5443
|
-
document.execCommand("insertText", false, outdented);
|
|
5444
|
-
} else {
|
|
5445
|
-
this.textarea.value = before + outdented + after;
|
|
5446
|
-
this.textarea.selectionStart = start;
|
|
5447
|
-
this.textarea.selectionEnd = start + outdented.length;
|
|
5448
|
-
}
|
|
5449
|
-
} else if (start !== end) {
|
|
5450
|
-
const before = value.substring(0, start);
|
|
5451
|
-
const selection = value.substring(start, end);
|
|
5452
|
-
const after = value.substring(end);
|
|
5453
|
-
const lines = selection.split("\n");
|
|
5454
|
-
const indented = lines.map((line) => " " + line).join("\n");
|
|
5455
|
-
if (document.execCommand) {
|
|
5456
|
-
this.textarea.setSelectionRange(start, end);
|
|
5457
|
-
document.execCommand("insertText", false, indented);
|
|
5458
|
-
} else {
|
|
5459
|
-
this.textarea.value = before + indented + after;
|
|
5460
|
-
this.textarea.selectionStart = start;
|
|
5461
|
-
this.textarea.selectionEnd = start + indented.length;
|
|
5462
|
-
}
|
|
5463
|
-
} else {
|
|
5464
|
-
if (document.execCommand) {
|
|
5465
|
-
document.execCommand("insertText", false, " ");
|
|
5466
|
-
} else {
|
|
5467
|
-
this.textarea.value = value.substring(0, start) + " " + value.substring(end);
|
|
5468
|
-
this.textarea.selectionStart = this.textarea.selectionEnd = start + 2;
|
|
5469
|
-
}
|
|
5470
|
-
}
|
|
5471
|
-
this.textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5472
|
-
return;
|
|
5473
5748
|
}
|
|
5474
5749
|
if (event.key === "Enter" && !event.shiftKey && !event.metaKey && !event.ctrlKey && this.options.smartLists) {
|
|
5475
5750
|
if (this.handleSmartListContinuation()) {
|
|
@@ -5606,6 +5881,7 @@ ${blockSuffix}` : suffix;
|
|
|
5606
5881
|
}
|
|
5607
5882
|
if (didChange) {
|
|
5608
5883
|
this._notifyChange();
|
|
5884
|
+
this._scheduleSafariReflow();
|
|
5609
5885
|
}
|
|
5610
5886
|
}
|
|
5611
5887
|
/**
|
|
@@ -5666,6 +5942,63 @@ ${blockSuffix}` : suffix;
|
|
|
5666
5942
|
getPreviewHTML() {
|
|
5667
5943
|
return this.preview.innerHTML;
|
|
5668
5944
|
}
|
|
5945
|
+
/**
|
|
5946
|
+
* Indent the current line or selected lines by two spaces.
|
|
5947
|
+
*/
|
|
5948
|
+
indentSelection() {
|
|
5949
|
+
this._replaceSelectedLines((line) => ` ${line}`);
|
|
5950
|
+
}
|
|
5951
|
+
/**
|
|
5952
|
+
* Outdent the current line or selected lines by up to two spaces or one tab.
|
|
5953
|
+
*/
|
|
5954
|
+
outdentSelection() {
|
|
5955
|
+
this._replaceSelectedLines((line) => line.replace(/^( {1,2}|\t)/, ""));
|
|
5956
|
+
}
|
|
5957
|
+
/**
|
|
5958
|
+
* Replace full lines touched by the current selection.
|
|
5959
|
+
* @private
|
|
5960
|
+
*/
|
|
5961
|
+
_replaceSelectedLines(transformLine) {
|
|
5962
|
+
if (!this._canEditTextarea())
|
|
5963
|
+
return false;
|
|
5964
|
+
const textarea = this.textarea;
|
|
5965
|
+
const { selectionStart, selectionEnd, value } = textarea;
|
|
5966
|
+
const lineStart = value.lastIndexOf("\n", selectionStart - 1) + 1;
|
|
5967
|
+
const effectiveEnd = this._effectiveSelectionEnd(value, selectionStart, selectionEnd);
|
|
5968
|
+
const lineEndOffset = value.indexOf("\n", effectiveEnd);
|
|
5969
|
+
const lineEnd = lineEndOffset === -1 ? value.length : lineEndOffset;
|
|
5970
|
+
const selectedLines = value.slice(lineStart, lineEnd);
|
|
5971
|
+
const replacement = selectedLines.split("\n").map(transformLine).join("\n");
|
|
5972
|
+
if (replacement === selectedLines)
|
|
5973
|
+
return false;
|
|
5974
|
+
textarea.setSelectionRange(lineStart, lineEnd);
|
|
5975
|
+
let inserted = false;
|
|
5976
|
+
try {
|
|
5977
|
+
inserted = document.execCommand("insertText", false, replacement);
|
|
5978
|
+
} catch (_) {
|
|
5979
|
+
}
|
|
5980
|
+
if (!inserted) {
|
|
5981
|
+
textarea.setRangeText(replacement, lineStart, lineEnd, "preserve");
|
|
5982
|
+
}
|
|
5983
|
+
textarea.setSelectionRange(lineStart, lineStart + replacement.length);
|
|
5984
|
+
textarea.dispatchEvent(new Event("input", { bubbles: true }));
|
|
5985
|
+
return true;
|
|
5986
|
+
}
|
|
5987
|
+
/**
|
|
5988
|
+
* @private
|
|
5989
|
+
*/
|
|
5990
|
+
_effectiveSelectionEnd(value, selectionStart, selectionEnd) {
|
|
5991
|
+
if (selectionEnd > selectionStart && value[selectionEnd - 1] === "\n") {
|
|
5992
|
+
return selectionEnd - 1;
|
|
5993
|
+
}
|
|
5994
|
+
return selectionEnd;
|
|
5995
|
+
}
|
|
5996
|
+
/**
|
|
5997
|
+
* @private
|
|
5998
|
+
*/
|
|
5999
|
+
_canEditTextarea() {
|
|
6000
|
+
return this.textarea && !this.textarea.disabled && !this.textarea.readOnly;
|
|
6001
|
+
}
|
|
5669
6002
|
/**
|
|
5670
6003
|
* Get clean HTML without any OverType-specific markup
|
|
5671
6004
|
* Useful for exporting to other formats or storage
|
|
@@ -5889,6 +6222,7 @@ ${blockSuffix}` : suffix;
|
|
|
5889
6222
|
*/
|
|
5890
6223
|
showNormalEditMode() {
|
|
5891
6224
|
this.container.dataset.mode = "normal";
|
|
6225
|
+
this._syncPreviewInteractivity();
|
|
5892
6226
|
this.updatePreview();
|
|
5893
6227
|
this._updateAutoHeight();
|
|
5894
6228
|
requestAnimationFrame(() => {
|
|
@@ -5903,6 +6237,7 @@ ${blockSuffix}` : suffix;
|
|
|
5903
6237
|
*/
|
|
5904
6238
|
showPlainTextarea() {
|
|
5905
6239
|
this.container.dataset.mode = "plain";
|
|
6240
|
+
this._syncPreviewInteractivity();
|
|
5906
6241
|
this._updateAutoHeight();
|
|
5907
6242
|
if (this.toolbar) {
|
|
5908
6243
|
const toggleBtn = this.container.querySelector('[data-action="toggle-plain"]');
|
|
@@ -5919,6 +6254,7 @@ ${blockSuffix}` : suffix;
|
|
|
5919
6254
|
*/
|
|
5920
6255
|
showPreviewMode() {
|
|
5921
6256
|
this.container.dataset.mode = "preview";
|
|
6257
|
+
this._syncPreviewInteractivity();
|
|
5922
6258
|
this.updatePreview();
|
|
5923
6259
|
this._updateAutoHeight();
|
|
5924
6260
|
return this;
|
|
@@ -5937,6 +6273,10 @@ ${blockSuffix}` : suffix;
|
|
|
5937
6273
|
if (this.shortcuts) {
|
|
5938
6274
|
this.shortcuts.destroy();
|
|
5939
6275
|
}
|
|
6276
|
+
if (this._safariReflowRaf) {
|
|
6277
|
+
cancelAnimationFrame(this._safariReflowRaf);
|
|
6278
|
+
this._safariReflowRaf = null;
|
|
6279
|
+
}
|
|
5940
6280
|
if (this.wrapper) {
|
|
5941
6281
|
const content = this.getValue();
|
|
5942
6282
|
this.wrapper.remove();
|
|
@@ -5968,11 +6308,16 @@ ${blockSuffix}` : suffix;
|
|
|
5968
6308
|
return elements.map((el) => {
|
|
5969
6309
|
const options = { ...defaults };
|
|
5970
6310
|
for (const attr of el.attributes) {
|
|
5971
|
-
if (attr.name.startsWith("data-ot-"))
|
|
5972
|
-
|
|
5973
|
-
|
|
5974
|
-
|
|
6311
|
+
if (!attr.name.startsWith("data-ot-"))
|
|
6312
|
+
continue;
|
|
6313
|
+
const kebab = attr.name.slice(8);
|
|
6314
|
+
if (kebab.startsWith("textarea-") && kebab !== "textarea-props") {
|
|
6315
|
+
const propKey = kebab.slice(9).replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
6316
|
+
options.textareaProps = { ...options.textareaProps || {}, [propKey]: _OverType._parseDataValue(attr.value) };
|
|
6317
|
+
continue;
|
|
5975
6318
|
}
|
|
6319
|
+
const key = kebab.replace(/-([a-z])/g, (_, c) => c.toUpperCase());
|
|
6320
|
+
options[key] = _OverType._parseDataValue(attr.value);
|
|
5976
6321
|
}
|
|
5977
6322
|
return new _OverType(el, options)[0];
|
|
5978
6323
|
});
|
|
@@ -6017,6 +6362,14 @@ ${blockSuffix}` : suffix;
|
|
|
6017
6362
|
return null;
|
|
6018
6363
|
if (value !== "" && !isNaN(Number(value)))
|
|
6019
6364
|
return Number(value);
|
|
6365
|
+
const trimmed = value.trim();
|
|
6366
|
+
if (trimmed[0] === "{" || trimmed[0] === "[") {
|
|
6367
|
+
try {
|
|
6368
|
+
return JSON.parse(trimmed);
|
|
6369
|
+
} catch (e) {
|
|
6370
|
+
return value;
|
|
6371
|
+
}
|
|
6372
|
+
}
|
|
6020
6373
|
return value;
|
|
6021
6374
|
}
|
|
6022
6375
|
/**
|
|
@@ -6195,8 +6548,13 @@ ${blockSuffix}` : suffix;
|
|
|
6195
6548
|
* Initialize global event listeners
|
|
6196
6549
|
*/
|
|
6197
6550
|
static initGlobalListeners() {
|
|
6198
|
-
|
|
6551
|
+
const globalScope = typeof window !== "undefined" ? window : globalThis;
|
|
6552
|
+
const globalListenersKey = "__overtypeGlobalListenersInitialized";
|
|
6553
|
+
if (_OverType.globalListenersInitialized || globalScope[globalListenersKey]) {
|
|
6554
|
+
_OverType.globalListenersInitialized = true;
|
|
6199
6555
|
return;
|
|
6556
|
+
}
|
|
6557
|
+
globalScope[globalListenersKey] = true;
|
|
6200
6558
|
document.addEventListener("input", (e) => {
|
|
6201
6559
|
if (e.target && e.target.classList && e.target.classList.contains("overtype-input")) {
|
|
6202
6560
|
const wrapper = e.target.closest(".overtype-wrapper");
|