customer-chat-sdk 1.1.16 → 1.1.17
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/core/IconManager.d.ts +1 -0
- package/dist/core/IconManager.d.ts.map +1 -1
- package/dist/core/IframeManager.d.ts +10 -4
- package/dist/core/IframeManager.d.ts.map +1 -1
- package/dist/customer-sdk.cjs.js +164 -120
- package/dist/customer-sdk.esm.js +164 -120
- package/dist/customer-sdk.min.js +2 -2
- package/package.json +3 -2
package/dist/customer-sdk.esm.js
CHANGED
|
@@ -18,6 +18,7 @@ class IconManager {
|
|
|
18
18
|
this.lastTouchPosition = { x: 0, y: 0 }; // 最后触摸位置
|
|
19
19
|
this.touchStartTime = 0; // 触摸开始时间
|
|
20
20
|
this.clickThreshold = 15; // 点击阈值(像素)
|
|
21
|
+
this.stoppedByIframe = false; // 是否因为 iframe 而停止拖动(用于避免触发磁性吸附)
|
|
21
22
|
// 性能优化:缓存容器信息,避免频繁查询 DOM
|
|
22
23
|
this.cachedContainer = null;
|
|
23
24
|
this.cachedContainerRect = null;
|
|
@@ -80,6 +81,7 @@ class IconManager {
|
|
|
80
81
|
this.iconElement = document.createElement('div');
|
|
81
82
|
this.iconElement.className = 'customer-sdk-icon';
|
|
82
83
|
// 直接设置样式 - 图标容器
|
|
84
|
+
// 关键优化:使用 pointer-events: none 让事件穿透到 iframe,子元素使用 pointer-events: auto 保持可点击
|
|
83
85
|
const defaultStyle = {
|
|
84
86
|
position: 'absolute',
|
|
85
87
|
width: '30px',
|
|
@@ -96,7 +98,8 @@ class IconManager {
|
|
|
96
98
|
transition: 'transform 0.2s ease',
|
|
97
99
|
border: 'none',
|
|
98
100
|
outline: 'none',
|
|
99
|
-
overflow: 'visible' // 允许红点显示在图标外部
|
|
101
|
+
overflow: 'visible', // 允许红点显示在图标外部
|
|
102
|
+
pointerEvents: 'none' // 让事件穿透到 iframe,只有子元素可以接收事件
|
|
100
103
|
};
|
|
101
104
|
// 如果指定了位置,使用left/top;否则使用默认的bottom/right
|
|
102
105
|
if (this.iconPosition) {
|
|
@@ -194,7 +197,8 @@ class IconManager {
|
|
|
194
197
|
height: '100%',
|
|
195
198
|
borderRadius: '50%',
|
|
196
199
|
overflow: 'hidden', // 限制图片溢出圆形边界
|
|
197
|
-
position: 'relative'
|
|
200
|
+
position: 'relative',
|
|
201
|
+
pointerEvents: 'auto' // 子元素启用指针事件,让 icon 可以点击和拖动
|
|
198
202
|
});
|
|
199
203
|
imgContainer.appendChild(iconImg);
|
|
200
204
|
this.iconElement.appendChild(imgContainer);
|
|
@@ -597,8 +601,38 @@ class IconManager {
|
|
|
597
601
|
target.closest('.customer-sdk-overlay'))) {
|
|
598
602
|
return;
|
|
599
603
|
}
|
|
604
|
+
// 关键优化:检查触摸点是否真的在 icon 的圆形区域内
|
|
605
|
+
// 如果不在,让事件穿透到 iframe,不触发拖动
|
|
606
|
+
if (this.iconElement) {
|
|
607
|
+
const iconRect = this.iconElement.getBoundingClientRect();
|
|
608
|
+
const clientX = 'touches' in e ? e.touches[0].clientX : e.clientX;
|
|
609
|
+
const clientY = 'touches' in e ? e.touches[0].clientY : e.clientY;
|
|
610
|
+
// 计算触摸点相对于 icon 中心的位置
|
|
611
|
+
const iconCenterX = iconRect.left + iconRect.width / 2;
|
|
612
|
+
const iconCenterY = iconRect.top + iconRect.height / 2;
|
|
613
|
+
const iconRadius = Math.min(iconRect.width, iconRect.height) / 2;
|
|
614
|
+
const distanceFromCenter = Math.sqrt(Math.pow(clientX - iconCenterX, 2) + Math.pow(clientY - iconCenterY, 2));
|
|
615
|
+
// 如果触摸点在 icon 圆形区域外(留一点边距,比如 10px),不处理拖动
|
|
616
|
+
// 这样可以让 iframe 内的滑动正常工作
|
|
617
|
+
// 但边距不能太大,否则无法拖动
|
|
618
|
+
if (distanceFromCenter > iconRadius + 10) {
|
|
619
|
+
if (this.debug) {
|
|
620
|
+
console.log('[IconManager] Touch point outside icon circle, allowing event to pass through', {
|
|
621
|
+
distance: distanceFromCenter,
|
|
622
|
+
radius: iconRadius,
|
|
623
|
+
touchPoint: { x: clientX, y: clientY },
|
|
624
|
+
iconCenter: { x: iconCenterX, y: iconCenterY }
|
|
625
|
+
});
|
|
626
|
+
}
|
|
627
|
+
return;
|
|
628
|
+
}
|
|
629
|
+
}
|
|
600
630
|
e.preventDefault();
|
|
601
631
|
e.stopPropagation();
|
|
632
|
+
// 拖动开始时,临时启用 pointer-events 确保拖动事件能正常接收
|
|
633
|
+
if (this.iconElement) {
|
|
634
|
+
this.iconElement.style.pointerEvents = 'auto';
|
|
635
|
+
}
|
|
602
636
|
// 重置状态
|
|
603
637
|
this.hasMoved = false;
|
|
604
638
|
this.dragStarted = false;
|
|
@@ -778,29 +812,8 @@ class IconManager {
|
|
|
778
812
|
});
|
|
779
813
|
}
|
|
780
814
|
}
|
|
781
|
-
//
|
|
782
|
-
|
|
783
|
-
if (clientX >= rect.left &&
|
|
784
|
-
clientX <= rect.right &&
|
|
785
|
-
clientY >= rect.top &&
|
|
786
|
-
clientY <= rect.bottom) {
|
|
787
|
-
// 鼠标在 iframe 上,立即停止拖动
|
|
788
|
-
if (this.debug) {
|
|
789
|
-
console.log('[IconManager] Mouse over iframe detected, stopping drag immediately', {
|
|
790
|
-
mousePosition: { x: clientX, y: clientY },
|
|
791
|
-
iframeRect: {
|
|
792
|
-
left: rect.left,
|
|
793
|
-
top: rect.top,
|
|
794
|
-
right: rect.right,
|
|
795
|
-
bottom: rect.bottom
|
|
796
|
-
},
|
|
797
|
-
iframeSrc: element.src || 'no src'
|
|
798
|
-
});
|
|
799
|
-
}
|
|
800
|
-
this.stopDrag();
|
|
801
|
-
return;
|
|
802
|
-
}
|
|
803
|
-
}
|
|
815
|
+
// 移除 iframe 检测停止拖动的逻辑,让拖动可以在 iframe 上顺畅进行
|
|
816
|
+
// 不再因为检测到 iframe 而停止拖动,保持拖动的流畅性
|
|
804
817
|
}
|
|
805
818
|
// 更新最后记录的鼠标位置和时间戳(用于主动检测)
|
|
806
819
|
const now = Date.now();
|
|
@@ -910,19 +923,18 @@ class IconManager {
|
|
|
910
923
|
// 计算新位置
|
|
911
924
|
let newX = clientX - this.dragOffset.x - containerRect.left;
|
|
912
925
|
let newY = clientY - this.dragOffset.y - containerRect.top;
|
|
913
|
-
//
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
}
|
|
926
|
+
// 允许拖动到容器外(允许负值),但限制在合理范围内(避免拖得太远)
|
|
927
|
+
// 允许拖动到容器外,最多隐藏到只剩一小部分可见
|
|
928
|
+
const minX = -iconWidth + 5; // 允许向左拖动,最多隐藏到只剩 5px
|
|
929
|
+
const maxX = container === document.body
|
|
930
|
+
? window.innerWidth - 5 // 允许向右拖动,最多隐藏到只剩 5px
|
|
931
|
+
: containerRect.width + iconWidth - 5; // 允许超出容器,最多隐藏到只剩 5px
|
|
932
|
+
const minY = -iconHeight + 5; // 允许向上拖动,最多隐藏到只剩 5px
|
|
933
|
+
const maxY = container === document.body
|
|
934
|
+
? window.innerHeight - 5 // 允许向下拖动,最多隐藏到只剩 5px
|
|
935
|
+
: containerRect.height + iconHeight - 5; // 允许超出容器,最多隐藏到只剩 5px
|
|
936
|
+
newX = Math.max(minX, Math.min(newX, maxX));
|
|
937
|
+
newY = Math.max(minY, Math.min(newY, maxY));
|
|
926
938
|
// 性能优化:使用 requestAnimationFrame 节流位置更新
|
|
927
939
|
this.pendingPosition.x = newX;
|
|
928
940
|
this.pendingPosition.y = newY;
|
|
@@ -989,6 +1001,8 @@ class IconManager {
|
|
|
989
1001
|
// 恢复样式
|
|
990
1002
|
this.iconElement.style.transition = 'transform 0.2s ease';
|
|
991
1003
|
this.iconElement.style.cursor = 'pointer';
|
|
1004
|
+
// 拖动结束时,恢复 pointer-events: none 让事件穿透到 iframe
|
|
1005
|
+
this.iconElement.style.pointerEvents = 'none';
|
|
992
1006
|
// 检查是否是点击
|
|
993
1007
|
const touchDuration = Date.now() - this.touchStartTime;
|
|
994
1008
|
const isValidClick = !this.hasMoved && touchDuration < 1000 && !this.dragStarted;
|
|
@@ -1005,26 +1019,37 @@ class IconManager {
|
|
|
1005
1019
|
}
|
|
1006
1020
|
// 先保存点击状态,然后重置拖动状态
|
|
1007
1021
|
const wasClick = isValidClick;
|
|
1008
|
-
//
|
|
1009
|
-
|
|
1010
|
-
|
|
1022
|
+
// 保存 stoppedByIframe 状态,用于后续判断是否启动自动吸附
|
|
1023
|
+
const wasStoppedByIframe = this.stoppedByIframe;
|
|
1024
|
+
// 如果是因为 iframe 而停止拖动,不执行磁性吸附和自动吸附
|
|
1025
|
+
// 这样可以避免拖动到 iframe 上时 icon 缩回去
|
|
1026
|
+
if (this.stoppedByIframe) {
|
|
1027
|
+
if (this.debug) {
|
|
1028
|
+
console.log('[IconManager] Drag stopped by iframe, skipping magnetic snap and auto attach');
|
|
1029
|
+
}
|
|
1011
1030
|
}
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
//
|
|
1018
|
-
if (
|
|
1019
|
-
const
|
|
1020
|
-
const
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
|
|
1026
|
-
if (
|
|
1027
|
-
|
|
1031
|
+
else {
|
|
1032
|
+
// 如果真正拖动过,执行磁性吸附
|
|
1033
|
+
if (this.dragStarted && this.magnetic && this.iconElement) {
|
|
1034
|
+
this.magneticSnap();
|
|
1035
|
+
}
|
|
1036
|
+
// 如果真正拖动过,保存当前位置到 iconPosition
|
|
1037
|
+
if (this.dragStarted && this.isDragging && this.iconElement) {
|
|
1038
|
+
const computedStyle = window.getComputedStyle(this.iconElement);
|
|
1039
|
+
const left = computedStyle.left;
|
|
1040
|
+
const top = computedStyle.top;
|
|
1041
|
+
// 如果 left/top 是有效的像素值,保存到 iconPosition
|
|
1042
|
+
if (left !== 'auto' && top !== 'auto') {
|
|
1043
|
+
const leftValue = parseFloat(left);
|
|
1044
|
+
const topValue = parseFloat(top);
|
|
1045
|
+
if (!isNaN(leftValue) && !isNaN(topValue)) {
|
|
1046
|
+
this.iconPosition = {
|
|
1047
|
+
x: leftValue,
|
|
1048
|
+
y: topValue
|
|
1049
|
+
};
|
|
1050
|
+
if (this.debug) {
|
|
1051
|
+
console.log('Icon position saved:', this.iconPosition);
|
|
1052
|
+
}
|
|
1028
1053
|
}
|
|
1029
1054
|
}
|
|
1030
1055
|
}
|
|
@@ -1034,8 +1059,10 @@ class IconManager {
|
|
|
1034
1059
|
this.isDragging = false;
|
|
1035
1060
|
this.dragStarted = false;
|
|
1036
1061
|
this.isStoppingDrag = false; // 重置停止标志
|
|
1062
|
+
this.stoppedByIframe = false; // 重置 iframe 停止标志
|
|
1037
1063
|
// 如果拖动后没有吸附到侧边,启动自动吸附定时器
|
|
1038
|
-
|
|
1064
|
+
// 但如果是因为 iframe 而停止拖动,不启动自动吸附
|
|
1065
|
+
if (!wasStoppedByIframe && !this.isAttachedToSide && this.sideAttach && this.autoAttachDelay > 0) {
|
|
1039
1066
|
this.startAutoAttachTimer();
|
|
1040
1067
|
}
|
|
1041
1068
|
if (wasClick) {
|
|
@@ -1103,30 +1130,8 @@ class IconManager {
|
|
|
1103
1130
|
console.log(`[IconManager] Active detection: Updated iframe cache (${this.cachedIframes.length} iframes)`);
|
|
1104
1131
|
}
|
|
1105
1132
|
}
|
|
1106
|
-
//
|
|
1107
|
-
|
|
1108
|
-
if (clientX >= rect.left &&
|
|
1109
|
-
clientX <= rect.right &&
|
|
1110
|
-
clientY >= rect.top &&
|
|
1111
|
-
clientY <= rect.bottom) {
|
|
1112
|
-
// 鼠标在 iframe 上,立即停止拖动
|
|
1113
|
-
if (this.debug) {
|
|
1114
|
-
console.log('[IconManager] Active detection: Mouse over iframe detected, stopping drag immediately', {
|
|
1115
|
-
mousePosition: { x: clientX, y: clientY },
|
|
1116
|
-
iframeRect: {
|
|
1117
|
-
left: rect.left,
|
|
1118
|
-
top: rect.top,
|
|
1119
|
-
right: rect.right,
|
|
1120
|
-
bottom: rect.bottom
|
|
1121
|
-
},
|
|
1122
|
-
iframeSrc: element.src || 'no src',
|
|
1123
|
-
timeSinceLastMove
|
|
1124
|
-
});
|
|
1125
|
-
}
|
|
1126
|
-
this.stopDrag();
|
|
1127
|
-
return;
|
|
1128
|
-
}
|
|
1129
|
-
}
|
|
1133
|
+
// 移除 iframe 检测停止拖动的逻辑,让拖动可以在 iframe 上顺畅进行
|
|
1134
|
+
// 不再因为检测到 iframe 而停止拖动,保持拖动的流畅性
|
|
1130
1135
|
}
|
|
1131
1136
|
// 继续检测
|
|
1132
1137
|
this.activeDetectionRafId = requestAnimationFrame(checkMousePosition);
|
|
@@ -1479,6 +1484,7 @@ class IconManager {
|
|
|
1479
1484
|
justifyContent: 'center',
|
|
1480
1485
|
zIndex: '1000001',
|
|
1481
1486
|
boxShadow: '0 -1px 4px rgba(0, 0, 0, 0.3), 0 2px 8px rgba(0, 0, 0, 0.15)',
|
|
1487
|
+
pointerEvents: 'auto', // 子元素启用指针事件,让 badge 可以接收事件
|
|
1482
1488
|
...(count === 0 && text === '' && {
|
|
1483
1489
|
width: '12px',
|
|
1484
1490
|
height: '12px',
|
|
@@ -1970,10 +1976,23 @@ class IframeManager {
|
|
|
1970
1976
|
}
|
|
1971
1977
|
// 创建新的消息处理器并保存引用
|
|
1972
1978
|
this.messageHandler = (event) => {
|
|
1973
|
-
//
|
|
1974
|
-
|
|
1975
|
-
|
|
1979
|
+
// 关键:过滤掉自己通过 dispatchEvent 发送的消息,避免无限循环
|
|
1980
|
+
// 自己发送的消息 source 是 window,而 iframe 发送的消息 source 是 iframe.contentWindow
|
|
1981
|
+
if (event.source === window) {
|
|
1982
|
+
if (this.debug) {
|
|
1983
|
+
console.log('[IframeManager] Ignoring self-broadcasted message to prevent infinite loop:', event.data);
|
|
1984
|
+
}
|
|
1985
|
+
return;
|
|
1986
|
+
}
|
|
1987
|
+
// 不验证来源,直接处理所有消息(确保消息能够被接收)
|
|
1988
|
+
if (this.debug) {
|
|
1989
|
+
console.log('[IframeManager] Message received:', {
|
|
1990
|
+
data: event.data,
|
|
1991
|
+
origin: event.origin,
|
|
1992
|
+
source: event.source
|
|
1993
|
+
});
|
|
1976
1994
|
}
|
|
1995
|
+
this.handleIframeMessage(event.data);
|
|
1977
1996
|
};
|
|
1978
1997
|
window.addEventListener('message', this.messageHandler, false);
|
|
1979
1998
|
}
|
|
@@ -1982,7 +2001,7 @@ class IframeManager {
|
|
|
1982
2001
|
*/
|
|
1983
2002
|
handleIframeMessage(data) {
|
|
1984
2003
|
if (this.debug) {
|
|
1985
|
-
console.log('Message from iframe:', data);
|
|
2004
|
+
console.log('[IframeManager] Message from iframe received:', data);
|
|
1986
2005
|
}
|
|
1987
2006
|
// 判断data是字符串还是对象,兼容两种格式
|
|
1988
2007
|
let messageType;
|
|
@@ -1994,10 +2013,13 @@ class IframeManager {
|
|
|
1994
2013
|
}
|
|
1995
2014
|
else {
|
|
1996
2015
|
if (this.debug) {
|
|
1997
|
-
console.log('Unknown message format:', data);
|
|
2016
|
+
console.log('[IframeManager] Unknown message format:', data);
|
|
1998
2017
|
}
|
|
1999
2018
|
return;
|
|
2000
2019
|
}
|
|
2020
|
+
if (this.debug) {
|
|
2021
|
+
console.log('[IframeManager] Parsed message type:', messageType);
|
|
2022
|
+
}
|
|
2001
2023
|
// 根据消息类型处理不同的操作
|
|
2002
2024
|
switch (messageType) {
|
|
2003
2025
|
case 'iframe_ready':
|
|
@@ -2030,11 +2052,22 @@ class IframeManager {
|
|
|
2030
2052
|
}
|
|
2031
2053
|
break;
|
|
2032
2054
|
case 'goto-login':
|
|
2033
|
-
// 登录跳转消息 -
|
|
2055
|
+
// 登录跳转消息 - 广播给调用 SDK 的 Vue 页面
|
|
2056
|
+
if (this.debug) {
|
|
2057
|
+
console.log('Received goto-login message, broadcasting to Vue page');
|
|
2058
|
+
}
|
|
2059
|
+
this.broadcastMessageToPage(data);
|
|
2060
|
+
if (this.config.onMessage) {
|
|
2061
|
+
this.config.onMessage(messageType, data);
|
|
2062
|
+
}
|
|
2063
|
+
break;
|
|
2064
|
+
case 'DCR_DEPOSIT':
|
|
2065
|
+
// 存款跳转消息 - 广播给调用 SDK 的 Vue 页面
|
|
2066
|
+
// payload.path 是动态的,例如: "?depositType=0&walletId=69382"
|
|
2034
2067
|
if (this.debug) {
|
|
2035
|
-
console.log('Received
|
|
2068
|
+
console.log('Received DCR_DEPOSIT message, broadcasting to Vue page:', data);
|
|
2036
2069
|
}
|
|
2037
|
-
this.
|
|
2070
|
+
this.broadcastMessageToPage(data);
|
|
2038
2071
|
if (this.config.onMessage) {
|
|
2039
2072
|
this.config.onMessage(messageType, data);
|
|
2040
2073
|
}
|
|
@@ -2042,11 +2075,11 @@ class IframeManager {
|
|
|
2042
2075
|
default:
|
|
2043
2076
|
// 处理动态消息:gotoActivityDetailById:xxx
|
|
2044
2077
|
if (typeof messageType === 'string' && messageType.startsWith('gotoActivityDetailById:')) {
|
|
2045
|
-
// 活动详情跳转消息 -
|
|
2078
|
+
// 活动详情跳转消息 - 广播给调用 SDK 的 Vue 页面
|
|
2046
2079
|
if (this.debug) {
|
|
2047
|
-
console.log('Received gotoActivityDetailById message,
|
|
2080
|
+
console.log('Received gotoActivityDetailById message, broadcasting to Vue page:', messageType);
|
|
2048
2081
|
}
|
|
2049
|
-
this.
|
|
2082
|
+
this.broadcastMessageToPage(data);
|
|
2050
2083
|
if (this.config.onMessage) {
|
|
2051
2084
|
this.config.onMessage(messageType, data);
|
|
2052
2085
|
}
|
|
@@ -2061,31 +2094,42 @@ class IframeManager {
|
|
|
2061
2094
|
}
|
|
2062
2095
|
}
|
|
2063
2096
|
/**
|
|
2064
|
-
*
|
|
2065
|
-
*
|
|
2097
|
+
* 向调用 SDK 的地方(Vue 页面)广播消息
|
|
2098
|
+
* 通过 window.dispatchEvent 触发事件,让 Vue 页面中的 window.addEventListener('message') 可以收到
|
|
2099
|
+
*
|
|
2100
|
+
* 重要说明:
|
|
2101
|
+
* 1. window.dispatchEvent 创建的事件会在同一窗口内触发所有监听器,无论 origin 是什么,Vue 页面都能收到
|
|
2102
|
+
* 2. MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串(如 'http://localhost:5173')
|
|
2103
|
+
* 3. 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
|
|
2104
|
+
* 4. 如果 Vue 页面需要检查 origin,应该检查 window.location.origin 而不是 '*'
|
|
2066
2105
|
*/
|
|
2067
|
-
|
|
2106
|
+
broadcastMessageToPage(data) {
|
|
2068
2107
|
try {
|
|
2069
|
-
//
|
|
2070
|
-
//
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
// 方式2:使用 dispatchEvent 创建 MessageEvent(在同一窗口内触发所有监听器)
|
|
2075
|
-
// 这样 Vue 页面中的 window.addEventListener('message') 也能收到
|
|
2108
|
+
// 使用 dispatchEvent 创建 MessageEvent,在同一窗口内触发所有监听器
|
|
2109
|
+
// 这样调用 SDK 的 Vue 页面中的 window.addEventListener('message') 也能收到
|
|
2110
|
+
// 注意:MessageEvent 的 origin 属性不能是 '*',必须是有效的 origin 字符串
|
|
2111
|
+
// 我们使用 window.location.origin 来标识消息来源(当前页面的 origin)
|
|
2112
|
+
// Vue 页面可以收到消息,因为 dispatchEvent 会在同一窗口内触发所有监听器
|
|
2076
2113
|
const messageEvent = new MessageEvent('message', {
|
|
2077
2114
|
data: data,
|
|
2078
|
-
origin: window.location.origin,
|
|
2079
|
-
source: window
|
|
2115
|
+
origin: window.location.origin, // 使用当前页面的 origin,不是 '*'(MessageEvent 不支持 '*')
|
|
2116
|
+
source: window,
|
|
2117
|
+
bubbles: true,
|
|
2118
|
+
cancelable: true
|
|
2080
2119
|
});
|
|
2081
2120
|
window.dispatchEvent(messageEvent);
|
|
2082
2121
|
if (this.debug) {
|
|
2083
|
-
console.log('Message
|
|
2122
|
+
console.log('[IframeManager] Message broadcasted to Vue page via window.dispatchEvent:', {
|
|
2123
|
+
data: data,
|
|
2124
|
+
origin: window.location.origin,
|
|
2125
|
+
type: 'message',
|
|
2126
|
+
note: 'origin is window.location.origin, not "*" (MessageEvent does not support "*")'
|
|
2127
|
+
});
|
|
2084
2128
|
}
|
|
2085
2129
|
}
|
|
2086
2130
|
catch (error) {
|
|
2087
2131
|
if (this.debug) {
|
|
2088
|
-
console.error('Failed to
|
|
2132
|
+
console.error('[IframeManager] Failed to broadcast message:', error);
|
|
2089
2133
|
}
|
|
2090
2134
|
}
|
|
2091
2135
|
}
|
|
@@ -2922,20 +2966,20 @@ function copyInputValue(node, cloned) {
|
|
|
2922
2966
|
}
|
|
2923
2967
|
|
|
2924
2968
|
const pseudoClasses = [
|
|
2925
|
-
"
|
|
2926
|
-
"
|
|
2927
|
-
// '
|
|
2969
|
+
"::before",
|
|
2970
|
+
"::after"
|
|
2971
|
+
// '::placeholder', TODO
|
|
2928
2972
|
];
|
|
2929
2973
|
const scrollbarPseudoClasses = [
|
|
2930
|
-
"
|
|
2931
|
-
"
|
|
2932
|
-
// '
|
|
2933
|
-
"
|
|
2934
|
-
"
|
|
2935
|
-
"
|
|
2936
|
-
// '
|
|
2937
|
-
"
|
|
2938
|
-
"
|
|
2974
|
+
"::-webkit-scrollbar",
|
|
2975
|
+
"::-webkit-scrollbar-button",
|
|
2976
|
+
// '::-webkit-scrollbar:horizontal', TODO
|
|
2977
|
+
"::-webkit-scrollbar-thumb",
|
|
2978
|
+
"::-webkit-scrollbar-track",
|
|
2979
|
+
"::-webkit-scrollbar-track-piece",
|
|
2980
|
+
// '::-webkit-scrollbar:vertical', TODO
|
|
2981
|
+
"::-webkit-scrollbar-corner",
|
|
2982
|
+
"::-webkit-resizer"
|
|
2939
2983
|
];
|
|
2940
2984
|
function copyPseudoClass(node, cloned, copyScrollbar, context, addWordToFontFamilies) {
|
|
2941
2985
|
const { ownerWindow, svgStyleElement, svgStyles, currentNodeStyle } = context;
|
|
@@ -2979,7 +3023,7 @@ function copyPseudoClass(node, cloned, copyScrollbar, context, addWordToFontFami
|
|
|
2979
3023
|
allClasses = [];
|
|
2980
3024
|
svgStyles.set(cssText, allClasses);
|
|
2981
3025
|
}
|
|
2982
|
-
allClasses.push(`.${klasses[0]}
|
|
3026
|
+
allClasses.push(`.${klasses[0]}${pseudoClass}`);
|
|
2983
3027
|
}
|
|
2984
3028
|
pseudoClasses.forEach(copyBy);
|
|
2985
3029
|
if (copyScrollbar)
|