agentation-vue 0.2.1 → 0.2.3
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/AgentationVue.vue +416 -529
- package/dist/components/AgentationToolbar.vue +49 -76
- package/dist/components/AnnotationInput.vue +28 -38
- package/dist/components/AnnotationMarker.vue +15 -20
- package/dist/components/ComponentChain.vue +17 -30
- package/dist/components/ElementHighlight.vue +13 -16
- package/dist/components/SettingsPanel.vue +35 -43
- package/dist/components/SettingsPopover.vue +128 -159
- package/dist/components/VaButton.vue +6 -12
- package/dist/components/VaIcon.vue +5 -5
- package/dist/components/VaIconButton.vue +15 -23
- package/dist/components/VaToggle.vue +7 -8
- package/package.json +18 -7
package/dist/AgentationVue.vue
CHANGED
|
@@ -1,292 +1,235 @@
|
|
|
1
|
-
<script setup
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
import
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import {
|
|
19
|
-
import {
|
|
20
|
-
import {
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}>(), {
|
|
38
|
-
copyToClipboard: true,
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const emit = defineEmits<{
|
|
42
|
-
'annotation-add': [annotation: Annotation]
|
|
43
|
-
'annotation-delete': [annotation: Annotation]
|
|
44
|
-
'annotation-update': [annotation: Annotation]
|
|
45
|
-
'annotations-clear': [annotations: Annotation[]]
|
|
46
|
-
'copy': [markdown: string]
|
|
47
|
-
}>()
|
|
48
|
-
|
|
49
|
-
const HISTORY_CHANGE_EVENT = 'va:history-change'
|
|
50
|
-
|
|
51
|
-
interface VaWindow extends Window {
|
|
52
|
-
__vaHistoryPatched?: boolean
|
|
53
|
-
}
|
|
54
|
-
|
|
1
|
+
<script setup>
|
|
2
|
+
import { isVue2 as _isVue2, computed, defineComponent, onBeforeUnmount, onMounted, ref, watch } from "vue-demi";
|
|
3
|
+
import AgentationToolbar from "./components/AgentationToolbar.vue";
|
|
4
|
+
import AnnotationInput from "./components/AnnotationInput.vue";
|
|
5
|
+
import AnnotationMarker from "./components/AnnotationMarker.vue";
|
|
6
|
+
import ElementHighlight from "./components/ElementHighlight.vue";
|
|
7
|
+
import SettingsPopover from "./components/SettingsPopover.vue";
|
|
8
|
+
import { useAnimationPause } from "./composables/useAnimationPause";
|
|
9
|
+
import { useAnnotations } from "./composables/useAnnotations";
|
|
10
|
+
import { useAreaSelect } from "./composables/useAreaSelect";
|
|
11
|
+
import { useElementDetection } from "./composables/useElementDetection";
|
|
12
|
+
import { useInteractionMode } from "./composables/useInteractionMode";
|
|
13
|
+
import { DEFAULT_SHORTCUT_CONFIG, useKeyboardShortcuts } from "./composables/useKeyboardShortcuts";
|
|
14
|
+
import { useMarkerPositions } from "./composables/useMarkerPositions";
|
|
15
|
+
import { useMultiSelect } from "./composables/useMultiSelect";
|
|
16
|
+
import { useOutputFormatter } from "./composables/useOutputFormatter";
|
|
17
|
+
import { useSettings } from "./composables/useSettings";
|
|
18
|
+
import { useTextSelection } from "./composables/useTextSelection";
|
|
19
|
+
import { VA_DATA_ATTR_SELECTOR } from "./constants";
|
|
20
|
+
import { copyToClipboard } from "./utils/clipboard";
|
|
21
|
+
import { isFixed as checkIsFixed, detectVueComponents, getAccessibilityInfo, getComputedStylesSummary, getNearbyElements, getNearbyText, getRelevantComputedStyles } from "./utils/dom-inspector";
|
|
22
|
+
import { createPortalContainer, destroyPortalContainer } from "./utils/portal";
|
|
23
|
+
import { getElementName, getElementPath } from "./utils/selectors";
|
|
24
|
+
import { boundingBoxToStyle } from "./utils/style";
|
|
25
|
+
const props = defineProps({
|
|
26
|
+
outputDetail: { type: String, required: false },
|
|
27
|
+
markerColor: { type: String, required: false },
|
|
28
|
+
copyToClipboard: { type: Boolean, required: false, default: true },
|
|
29
|
+
blockPageInteractions: { type: Boolean, required: false },
|
|
30
|
+
autoHideToolbar: { type: Boolean, required: false },
|
|
31
|
+
pageUrl: { type: String, required: false },
|
|
32
|
+
theme: { type: String, required: false },
|
|
33
|
+
activationKey: { type: String, required: false }
|
|
34
|
+
});
|
|
35
|
+
const emit = defineEmits(["annotation-add", "annotation-delete", "annotation-update", "annotations-clear", "copy"]);
|
|
36
|
+
const HISTORY_CHANGE_EVENT = "va:history-change";
|
|
55
37
|
function getCurrentUrl() {
|
|
56
|
-
return typeof window !==
|
|
38
|
+
return typeof window !== "undefined" ? window.location.href : "";
|
|
57
39
|
}
|
|
58
|
-
|
|
59
40
|
function patchHistoryEvents() {
|
|
60
|
-
const win = window
|
|
41
|
+
const win = window;
|
|
61
42
|
if (win.__vaHistoryPatched)
|
|
62
|
-
return
|
|
63
|
-
win.__vaHistoryPatched = true
|
|
64
|
-
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
const
|
|
87
|
-
const {
|
|
88
|
-
const {
|
|
89
|
-
const
|
|
90
|
-
const
|
|
91
|
-
const
|
|
92
|
-
const
|
|
93
|
-
const
|
|
94
|
-
const
|
|
95
|
-
const
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
const
|
|
99
|
-
const
|
|
100
|
-
const
|
|
101
|
-
const
|
|
102
|
-
|
|
103
|
-
const
|
|
104
|
-
const editingAnnotation = ref<Annotation | null>(null)
|
|
105
|
-
const settingsOpen = ref(false)
|
|
106
|
-
const settingsAnchorEl = ref<HTMLElement | null>(null)
|
|
107
|
-
const copyFeedback = ref(false)
|
|
108
|
-
const toolbarDragging = ref(false)
|
|
109
|
-
const DRAG_END_SUPPRESSION_MS = 500
|
|
110
|
-
const SETTINGS_CLOSE_SUPPRESSION_MS = 220
|
|
111
|
-
let suppressInteractionsUntil = 0
|
|
112
|
-
const effectiveBlockPageInteractions = computed(() => props.blockPageInteractions ?? settings.blockPageInteractions)
|
|
43
|
+
return;
|
|
44
|
+
win.__vaHistoryPatched = true;
|
|
45
|
+
const originalPushState = win.history.pushState.bind(win.history);
|
|
46
|
+
const originalReplaceState = win.history.replaceState.bind(win.history);
|
|
47
|
+
win.history.pushState = function(...args) {
|
|
48
|
+
originalPushState(...args);
|
|
49
|
+
win.dispatchEvent(new Event(HISTORY_CHANGE_EVENT));
|
|
50
|
+
};
|
|
51
|
+
win.history.replaceState = function(...args) {
|
|
52
|
+
originalReplaceState(...args);
|
|
53
|
+
win.dispatchEvent(new Event(HISTORY_CHANGE_EVENT));
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
const rootEl = ref(null);
|
|
57
|
+
const overlayEl = ref(null);
|
|
58
|
+
const toolbarRef = ref(null);
|
|
59
|
+
const currentUrl = ref(props.pageUrl || getCurrentUrl());
|
|
60
|
+
const { settings } = useSettings();
|
|
61
|
+
const { mode, transition } = useInteractionMode();
|
|
62
|
+
const { annotations, addAnnotation, removeAnnotation, updateAnnotation, clearAnnotations, setScopeUrl } = useAnnotations(currentUrl.value);
|
|
63
|
+
const { hoveredRect, hoveredName, hoveredComponentChain, onMouseMove, clearHighlight, getElementUnderOverlay, cleanup: cleanupDetection } = useElementDetection(overlayEl, () => settings.showComponentTree);
|
|
64
|
+
const textSelection = useTextSelection(mode);
|
|
65
|
+
const multiSelect = useMultiSelect(mode, transition);
|
|
66
|
+
const areaSelect = useAreaSelect(mode, transition);
|
|
67
|
+
const animPause = useAnimationPause();
|
|
68
|
+
const { recalculatePositions: _recalculatePositions } = useMarkerPositions(annotations);
|
|
69
|
+
const { formatAnnotations } = useOutputFormatter();
|
|
70
|
+
const pendingPosition = ref(null);
|
|
71
|
+
const pendingElementName = ref("");
|
|
72
|
+
const pendingTarget = ref(null);
|
|
73
|
+
const pendingComponentChain = ref();
|
|
74
|
+
const pendingComputedStyles = ref();
|
|
75
|
+
const pendingTextSelection = ref(null);
|
|
76
|
+
const editingAnnotation = ref(null);
|
|
77
|
+
const settingsOpen = ref(false);
|
|
78
|
+
const settingsAnchorEl = ref(null);
|
|
79
|
+
const copyFeedback = ref(false);
|
|
80
|
+
const toolbarDragging = ref(false);
|
|
81
|
+
const DRAG_END_SUPPRESSION_MS = 500;
|
|
82
|
+
const SETTINGS_CLOSE_SUPPRESSION_MS = 220;
|
|
83
|
+
let suppressInteractionsUntil = 0;
|
|
84
|
+
const effectiveBlockPageInteractions = computed(() => props.blockPageInteractions ?? settings.blockPageInteractions);
|
|
113
85
|
const rootStyle = computed(() => {
|
|
114
|
-
const hex = settings.markerColor
|
|
86
|
+
const hex = settings.markerColor;
|
|
115
87
|
if (!hex)
|
|
116
|
-
return
|
|
117
|
-
const r = Number.parseInt(hex.slice(1, 3), 16)
|
|
118
|
-
const g = Number.parseInt(hex.slice(3, 5), 16)
|
|
119
|
-
const b = Number.parseInt(hex.slice(5, 7), 16)
|
|
88
|
+
return void 0;
|
|
89
|
+
const r = Number.parseInt(hex.slice(1, 3), 16);
|
|
90
|
+
const g = Number.parseInt(hex.slice(3, 5), 16);
|
|
91
|
+
const b = Number.parseInt(hex.slice(5, 7), 16);
|
|
120
92
|
return {
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
}
|
|
124
|
-
})
|
|
125
|
-
const resolvedUrl = computed(() => currentUrl.value)
|
|
93
|
+
"--va-accent": hex,
|
|
94
|
+
"--va-accent-rgb": `${r}, ${g}, ${b}`
|
|
95
|
+
};
|
|
96
|
+
});
|
|
97
|
+
const resolvedUrl = computed(() => currentUrl.value);
|
|
126
98
|
const pendingMarkerX = computed(() => {
|
|
127
99
|
if (!pendingPosition.value)
|
|
128
|
-
return 0
|
|
129
|
-
return
|
|
130
|
-
})
|
|
100
|
+
return 0;
|
|
101
|
+
return pendingPosition.value.x / window.innerWidth * 100;
|
|
102
|
+
});
|
|
131
103
|
const pendingMarkerY = computed(() => {
|
|
132
104
|
if (!pendingPosition.value)
|
|
133
|
-
return 0
|
|
134
|
-
return pendingPosition.value.y + (window.scrollY || document.documentElement.scrollTop)
|
|
135
|
-
})
|
|
136
|
-
const pendingIsSelection = computed(() => (
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
&& (multiSelect.selectedElements.value.length > 0 || !!areaSelect.areaRect.value)
|
|
140
|
-
))
|
|
141
|
-
|
|
142
|
-
// Portal setup (Vue 2.7 compat)
|
|
143
|
-
let portalContainer: HTMLElement | null = null
|
|
144
|
-
const isVue2 = _isVue2
|
|
145
|
-
|
|
105
|
+
return 0;
|
|
106
|
+
return pendingPosition.value.y + (window.scrollY || document.documentElement.scrollTop);
|
|
107
|
+
});
|
|
108
|
+
const pendingIsSelection = computed(() => mode.value === "input-open" && !editingAnnotation.value && (multiSelect.selectedElements.value.length > 0 || !!areaSelect.areaRect.value));
|
|
109
|
+
let portalContainer = null;
|
|
110
|
+
const isVue2 = _isVue2;
|
|
146
111
|
const PassThrough = defineComponent({
|
|
147
112
|
render() {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const portalWrapper = isVue2 ? PassThrough : 'Teleport'
|
|
155
|
-
const portalProps = isVue2 ? {} : { to: 'body' }
|
|
156
|
-
|
|
113
|
+
const slot = this.$slots.default;
|
|
114
|
+
return (typeof slot === "function" ? slot() : slot?.[0]) || null;
|
|
115
|
+
}
|
|
116
|
+
});
|
|
117
|
+
const portalWrapper = isVue2 ? PassThrough : "Teleport";
|
|
118
|
+
const portalProps = isVue2 ? {} : { to: "body" };
|
|
157
119
|
onMounted(() => {
|
|
158
120
|
if (isVue2 && rootEl.value) {
|
|
159
|
-
portalContainer = createPortalContainer()
|
|
160
|
-
portalContainer.appendChild(rootEl.value)
|
|
121
|
+
portalContainer = createPortalContainer();
|
|
122
|
+
portalContainer.appendChild(rootEl.value);
|
|
161
123
|
}
|
|
162
|
-
})
|
|
163
|
-
|
|
124
|
+
});
|
|
164
125
|
onBeforeUnmount(() => {
|
|
165
|
-
animPause.cleanup()
|
|
166
|
-
cleanupDetection()
|
|
126
|
+
animPause.cleanup();
|
|
127
|
+
cleanupDetection();
|
|
167
128
|
if (portalContainer) {
|
|
168
|
-
destroyPortalContainer(portalContainer)
|
|
129
|
+
destroyPortalContainer(portalContainer);
|
|
169
130
|
}
|
|
170
|
-
})
|
|
171
|
-
|
|
172
|
-
// Apply prop overrides to settings
|
|
131
|
+
});
|
|
173
132
|
watch(() => props.outputDetail, (v) => {
|
|
174
133
|
if (v)
|
|
175
|
-
settings.outputDetail = v
|
|
176
|
-
}, { immediate: true })
|
|
134
|
+
settings.outputDetail = v;
|
|
135
|
+
}, { immediate: true });
|
|
177
136
|
watch(() => props.markerColor, (v) => {
|
|
178
137
|
if (v)
|
|
179
|
-
settings.markerColor = v
|
|
180
|
-
}, { immediate: true })
|
|
138
|
+
settings.markerColor = v;
|
|
139
|
+
}, { immediate: true });
|
|
181
140
|
watch(() => props.theme, (v) => {
|
|
182
141
|
if (v)
|
|
183
|
-
settings.theme = v
|
|
184
|
-
}, { immediate: true })
|
|
142
|
+
settings.theme = v;
|
|
143
|
+
}, { immediate: true });
|
|
185
144
|
watch(() => props.blockPageInteractions, (v) => {
|
|
186
145
|
if (v)
|
|
187
|
-
settings.blockPageInteractions = v
|
|
188
|
-
}, { immediate: true })
|
|
146
|
+
settings.blockPageInteractions = v;
|
|
147
|
+
}, { immediate: true });
|
|
189
148
|
watch(() => props.autoHideToolbar, (v) => {
|
|
190
149
|
if (v)
|
|
191
|
-
settings.autoHideToolbar = v
|
|
192
|
-
}, { immediate: true })
|
|
150
|
+
settings.autoHideToolbar = v;
|
|
151
|
+
}, { immediate: true });
|
|
193
152
|
watch(() => props.pageUrl, (url) => {
|
|
194
|
-
syncUrlScope(url || getCurrentUrl())
|
|
195
|
-
}, { immediate: true })
|
|
153
|
+
syncUrlScope(url || getCurrentUrl());
|
|
154
|
+
}, { immediate: true });
|
|
196
155
|
watch(() => props.activationKey, (v) => {
|
|
197
|
-
if (v !==
|
|
198
|
-
settings.activationKey = v
|
|
199
|
-
}, { immediate: true })
|
|
200
|
-
|
|
201
|
-
// Event handlers
|
|
156
|
+
if (v !== void 0)
|
|
157
|
+
settings.activationKey = v;
|
|
158
|
+
}, { immediate: true });
|
|
202
159
|
function onActivate() {
|
|
203
|
-
transition(
|
|
160
|
+
transition("inspect");
|
|
204
161
|
}
|
|
205
|
-
|
|
206
162
|
function onDeactivate() {
|
|
207
|
-
transition(
|
|
208
|
-
clearHighlight()
|
|
209
|
-
closeSettings(false)
|
|
163
|
+
transition("idle");
|
|
164
|
+
clearHighlight();
|
|
165
|
+
closeSettings(false);
|
|
210
166
|
}
|
|
211
|
-
|
|
212
|
-
function onOverlayMouseMove(e: MouseEvent) {
|
|
167
|
+
function onOverlayMouseMove(e) {
|
|
213
168
|
if (isInteractionLocked())
|
|
214
|
-
return
|
|
215
|
-
if (mode.value ===
|
|
216
|
-
onMouseMove(e)
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
else if (mode.value === 'area-selecting') {
|
|
222
|
-
areaSelect.onMouseMove(e)
|
|
169
|
+
return;
|
|
170
|
+
if (mode.value === "inspect") {
|
|
171
|
+
onMouseMove(e);
|
|
172
|
+
} else if (mode.value === "multi-selecting") {
|
|
173
|
+
multiSelect.onMouseMove(e);
|
|
174
|
+
} else if (mode.value === "area-selecting") {
|
|
175
|
+
areaSelect.onMouseMove(e);
|
|
223
176
|
}
|
|
224
177
|
}
|
|
225
|
-
|
|
226
|
-
function onOverlayMouseDown(e: MouseEvent) {
|
|
178
|
+
function onOverlayMouseDown(e) {
|
|
227
179
|
if (isInteractionLocked())
|
|
228
|
-
return
|
|
180
|
+
return;
|
|
229
181
|
if (multiSelect.onMouseDown(e))
|
|
230
|
-
return
|
|
231
|
-
areaSelect.onMouseDown(e)
|
|
182
|
+
return;
|
|
183
|
+
areaSelect.onMouseDown(e);
|
|
232
184
|
}
|
|
233
|
-
|
|
234
|
-
function onOverlayMouseUp(e: MouseEvent) {
|
|
185
|
+
function onOverlayMouseUp(e) {
|
|
235
186
|
if (isInteractionLocked())
|
|
236
|
-
return
|
|
237
|
-
if (mode.value ===
|
|
238
|
-
multiSelect.onMouseUp()
|
|
187
|
+
return;
|
|
188
|
+
if (mode.value === "multi-selecting") {
|
|
189
|
+
multiSelect.onMouseUp();
|
|
239
190
|
if (multiSelect.selectedElements.value.length > 0) {
|
|
240
|
-
const elements = multiSelect.selectedElements.value
|
|
241
|
-
const rect = multiSelect.selectionRect.value
|
|
242
|
-
pendingPosition.value = rect
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
else {
|
|
252
|
-
multiSelect.reset()
|
|
253
|
-
transition('inspect')
|
|
191
|
+
const elements = multiSelect.selectedElements.value;
|
|
192
|
+
const rect = multiSelect.selectionRect.value;
|
|
193
|
+
pendingPosition.value = rect ? { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 } : { x: e.clientX, y: e.clientY };
|
|
194
|
+
pendingElementName.value = `${elements.length} elements selected`;
|
|
195
|
+
pendingComponentChain.value = void 0;
|
|
196
|
+
pendingComputedStyles.value = void 0;
|
|
197
|
+
pendingTarget.value = null;
|
|
198
|
+
transition("input-open");
|
|
199
|
+
} else {
|
|
200
|
+
multiSelect.reset();
|
|
201
|
+
transition("inspect");
|
|
254
202
|
}
|
|
255
|
-
return
|
|
203
|
+
return;
|
|
256
204
|
}
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
areaSelect.
|
|
260
|
-
const rect = areaSelect.areaRect.value
|
|
205
|
+
if (mode.value === "area-selecting") {
|
|
206
|
+
areaSelect.onMouseUp();
|
|
207
|
+
const rect = areaSelect.areaRect.value;
|
|
261
208
|
if (rect && rect.width > 10 && rect.height > 10) {
|
|
262
|
-
pendingPosition.value = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 }
|
|
263
|
-
pendingElementName.value =
|
|
264
|
-
pendingComponentChain.value =
|
|
265
|
-
pendingComputedStyles.value =
|
|
266
|
-
pendingTarget.value = null
|
|
267
|
-
transition(
|
|
209
|
+
pendingPosition.value = { x: rect.x + rect.width / 2, y: rect.y + rect.height / 2 };
|
|
210
|
+
pendingElementName.value = "Area selection";
|
|
211
|
+
pendingComponentChain.value = void 0;
|
|
212
|
+
pendingComputedStyles.value = void 0;
|
|
213
|
+
pendingTarget.value = null;
|
|
214
|
+
transition("input-open");
|
|
215
|
+
} else {
|
|
216
|
+
areaSelect.reset();
|
|
217
|
+
transition("inspect");
|
|
268
218
|
}
|
|
269
|
-
|
|
270
|
-
areaSelect.reset()
|
|
271
|
-
transition('inspect')
|
|
272
|
-
}
|
|
273
|
-
return
|
|
219
|
+
return;
|
|
274
220
|
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
// Check for text selection first
|
|
280
|
-
const textResult = textSelection.checkTextSelection(e)
|
|
221
|
+
if (mode.value !== "inspect")
|
|
222
|
+
return;
|
|
223
|
+
const textResult = textSelection.checkTextSelection(e);
|
|
281
224
|
if (textResult) {
|
|
282
225
|
pendingPosition.value = {
|
|
283
226
|
x: textResult.rect.left + textResult.rect.width / 2,
|
|
284
|
-
y: textResult.rect.bottom
|
|
285
|
-
}
|
|
286
|
-
pendingElementName.value = `"${textResult.selectedText.slice(0, 30)}"
|
|
287
|
-
pendingComponentChain.value = getVueComponents(textResult.anchorElement)
|
|
288
|
-
pendingComputedStyles.value = getRelevantComputedStyles(textResult.anchorElement)
|
|
289
|
-
pendingTarget.value = textResult.anchorElement
|
|
227
|
+
y: textResult.rect.bottom
|
|
228
|
+
};
|
|
229
|
+
pendingElementName.value = `"${textResult.selectedText.slice(0, 30)}"`;
|
|
230
|
+
pendingComponentChain.value = getVueComponents(textResult.anchorElement);
|
|
231
|
+
pendingComputedStyles.value = getRelevantComputedStyles(textResult.anchorElement);
|
|
232
|
+
pendingTarget.value = textResult.anchorElement;
|
|
290
233
|
pendingTextSelection.value = {
|
|
291
234
|
text: textResult.selectedText,
|
|
292
235
|
element: textResult.anchorElement,
|
|
@@ -294,192 +237,163 @@ function onOverlayMouseUp(e: MouseEvent) {
|
|
|
294
237
|
x: textResult.rect.x,
|
|
295
238
|
y: textResult.rect.y,
|
|
296
239
|
width: textResult.rect.width,
|
|
297
|
-
height: textResult.rect.height
|
|
298
|
-
}
|
|
299
|
-
}
|
|
300
|
-
transition(
|
|
301
|
-
return
|
|
240
|
+
height: textResult.rect.height
|
|
241
|
+
}
|
|
242
|
+
};
|
|
243
|
+
transition("input-open");
|
|
244
|
+
return;
|
|
302
245
|
}
|
|
303
|
-
|
|
304
|
-
// Normal click annotation
|
|
305
|
-
const el = getElementUnderOverlay(e)
|
|
246
|
+
const el = getElementUnderOverlay(e);
|
|
306
247
|
if (!el || el.closest(VA_DATA_ATTR_SELECTOR))
|
|
307
|
-
return
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
function onOverlayWheel(_e: WheelEvent) {
|
|
248
|
+
return;
|
|
249
|
+
pendingPosition.value = { x: e.clientX, y: e.clientY };
|
|
250
|
+
pendingElementName.value = getElementName(el);
|
|
251
|
+
pendingComponentChain.value = settings.showComponentTree ? detectVueComponents(el) : void 0;
|
|
252
|
+
pendingComputedStyles.value = getRelevantComputedStyles(el);
|
|
253
|
+
pendingTarget.value = el;
|
|
254
|
+
pendingTextSelection.value = null;
|
|
255
|
+
transition("input-open");
|
|
256
|
+
}
|
|
257
|
+
function onOverlayWheel(_e) {
|
|
319
258
|
if (isInteractionLocked())
|
|
320
|
-
return
|
|
321
|
-
const overlay = overlayEl.value
|
|
259
|
+
return;
|
|
260
|
+
const overlay = overlayEl.value;
|
|
322
261
|
if (!overlay)
|
|
323
|
-
return
|
|
324
|
-
const previousPointerEvents = overlay.style.pointerEvents
|
|
325
|
-
overlay.style.pointerEvents =
|
|
262
|
+
return;
|
|
263
|
+
const previousPointerEvents = overlay.style.pointerEvents;
|
|
264
|
+
overlay.style.pointerEvents = "none";
|
|
326
265
|
requestAnimationFrame(() => {
|
|
327
266
|
if (overlay)
|
|
328
|
-
overlay.style.pointerEvents = previousPointerEvents
|
|
329
|
-
})
|
|
267
|
+
overlay.style.pointerEvents = previousPointerEvents;
|
|
268
|
+
});
|
|
330
269
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
const overlay = overlayEl.value
|
|
270
|
+
function getElementAtPointThroughOverlay(x, y) {
|
|
271
|
+
const overlay = overlayEl.value;
|
|
334
272
|
if (!overlay)
|
|
335
|
-
return document.elementFromPoint(x, y)
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
return el
|
|
273
|
+
return document.elementFromPoint(x, y);
|
|
274
|
+
const previousPointerEvents = overlay.style.pointerEvents;
|
|
275
|
+
overlay.style.pointerEvents = "none";
|
|
276
|
+
const el = document.elementFromPoint(x, y);
|
|
277
|
+
overlay.style.pointerEvents = previousPointerEvents;
|
|
278
|
+
return el;
|
|
342
279
|
}
|
|
343
|
-
|
|
344
280
|
function shouldUseDocumentFallbackEvents() {
|
|
345
|
-
return mode.value ===
|
|
281
|
+
return mode.value === "inspect" && !effectiveBlockPageInteractions.value && !isInteractionLocked();
|
|
346
282
|
}
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
suppressInteractionsUntil = Math.max(suppressInteractionsUntil, Date.now() + durationMs)
|
|
283
|
+
function lockInteractionsTemporarily(durationMs) {
|
|
284
|
+
suppressInteractionsUntil = Math.max(suppressInteractionsUntil, Date.now() + durationMs);
|
|
350
285
|
}
|
|
351
|
-
|
|
352
286
|
function isInteractionLocked() {
|
|
353
|
-
return settingsOpen.value || toolbarDragging.value || Date.now() < suppressInteractionsUntil
|
|
287
|
+
return settingsOpen.value || toolbarDragging.value || Date.now() < suppressInteractionsUntil;
|
|
354
288
|
}
|
|
355
|
-
|
|
356
289
|
function closeSettings(lockInteractions = true) {
|
|
357
290
|
if (!settingsOpen.value)
|
|
358
|
-
return
|
|
359
|
-
settingsOpen.value = false
|
|
291
|
+
return;
|
|
292
|
+
settingsOpen.value = false;
|
|
360
293
|
if (lockInteractions)
|
|
361
|
-
lockInteractionsTemporarily(SETTINGS_CLOSE_SUPPRESSION_MS)
|
|
294
|
+
lockInteractionsTemporarily(SETTINGS_CLOSE_SUPPRESSION_MS);
|
|
362
295
|
}
|
|
363
|
-
|
|
364
|
-
function syncUrlScope(nextUrl: string) {
|
|
296
|
+
function syncUrlScope(nextUrl) {
|
|
365
297
|
if (!nextUrl || currentUrl.value === nextUrl)
|
|
366
|
-
return
|
|
367
|
-
currentUrl.value = nextUrl
|
|
368
|
-
setScopeUrl(nextUrl)
|
|
298
|
+
return;
|
|
299
|
+
currentUrl.value = nextUrl;
|
|
300
|
+
setScopeUrl(nextUrl);
|
|
369
301
|
}
|
|
370
|
-
|
|
371
302
|
function syncUrlScopeFromWindow() {
|
|
372
303
|
if (props.pageUrl)
|
|
373
|
-
return
|
|
374
|
-
syncUrlScope(getCurrentUrl())
|
|
304
|
+
return;
|
|
305
|
+
syncUrlScope(getCurrentUrl());
|
|
375
306
|
}
|
|
376
|
-
|
|
377
307
|
function onToolbarDragStart() {
|
|
378
|
-
toolbarDragging.value = true
|
|
308
|
+
toolbarDragging.value = true;
|
|
379
309
|
}
|
|
380
|
-
|
|
381
310
|
function onToolbarDragEnd() {
|
|
382
|
-
toolbarDragging.value = false
|
|
383
|
-
|
|
384
|
-
lockInteractionsTemporarily(DRAG_END_SUPPRESSION_MS)
|
|
311
|
+
toolbarDragging.value = false;
|
|
312
|
+
lockInteractionsTemporarily(DRAG_END_SUPPRESSION_MS);
|
|
385
313
|
}
|
|
386
|
-
|
|
387
|
-
function onDocumentMouseMove(e: MouseEvent) {
|
|
314
|
+
function onDocumentMouseMove(e) {
|
|
388
315
|
if (!shouldUseDocumentFallbackEvents())
|
|
389
|
-
return
|
|
390
|
-
onOverlayMouseMove(e)
|
|
316
|
+
return;
|
|
317
|
+
onOverlayMouseMove(e);
|
|
391
318
|
}
|
|
392
|
-
|
|
393
|
-
function onDocumentMouseDown(e: MouseEvent) {
|
|
319
|
+
function onDocumentMouseDown(e) {
|
|
394
320
|
if (!shouldUseDocumentFallbackEvents())
|
|
395
|
-
return
|
|
396
|
-
onOverlayMouseDown(e)
|
|
321
|
+
return;
|
|
322
|
+
onOverlayMouseDown(e);
|
|
397
323
|
}
|
|
398
|
-
|
|
399
|
-
function onDocumentMouseUp(e: MouseEvent) {
|
|
324
|
+
function onDocumentMouseUp(e) {
|
|
400
325
|
if (!shouldUseDocumentFallbackEvents())
|
|
401
|
-
return
|
|
402
|
-
onOverlayMouseUp(e)
|
|
326
|
+
return;
|
|
327
|
+
onOverlayMouseUp(e);
|
|
403
328
|
}
|
|
404
|
-
|
|
405
|
-
function onDocumentWheel(e: WheelEvent) {
|
|
329
|
+
function onDocumentWheel(e) {
|
|
406
330
|
if (!shouldUseDocumentFallbackEvents())
|
|
407
|
-
return
|
|
408
|
-
onOverlayWheel(e)
|
|
331
|
+
return;
|
|
332
|
+
onOverlayWheel(e);
|
|
409
333
|
}
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
const target = e.target as Element
|
|
334
|
+
function onDocumentClick(e) {
|
|
335
|
+
if (mode.value === "idle")
|
|
336
|
+
return;
|
|
337
|
+
const target = e.target;
|
|
415
338
|
if (!target || target.closest(VA_DATA_ATTR_SELECTOR))
|
|
416
|
-
return
|
|
417
|
-
e.preventDefault()
|
|
418
|
-
e.stopPropagation()
|
|
339
|
+
return;
|
|
340
|
+
e.preventDefault();
|
|
341
|
+
e.stopPropagation();
|
|
419
342
|
}
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
return settings.showComponentTree
|
|
423
|
-
? detectVueComponents(el, settings.outputDetail === 'forensic')
|
|
424
|
-
: undefined
|
|
343
|
+
function getVueComponents(el) {
|
|
344
|
+
return settings.showComponentTree ? detectVueComponents(el, settings.outputDetail === "forensic") : void 0;
|
|
425
345
|
}
|
|
426
|
-
|
|
427
346
|
function resetPendingState() {
|
|
428
|
-
pendingPosition.value = null
|
|
429
|
-
pendingTarget.value = null
|
|
430
|
-
pendingComponentChain.value =
|
|
431
|
-
pendingComputedStyles.value =
|
|
432
|
-
pendingTextSelection.value = null
|
|
433
|
-
editingAnnotation.value = null
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
function onInputAdd(comment: string) {
|
|
347
|
+
pendingPosition.value = null;
|
|
348
|
+
pendingTarget.value = null;
|
|
349
|
+
pendingComponentChain.value = void 0;
|
|
350
|
+
pendingComputedStyles.value = void 0;
|
|
351
|
+
pendingTextSelection.value = null;
|
|
352
|
+
editingAnnotation.value = null;
|
|
353
|
+
}
|
|
354
|
+
function onInputAdd(comment) {
|
|
437
355
|
if (editingAnnotation.value) {
|
|
438
|
-
onInputSave(comment)
|
|
439
|
-
return
|
|
356
|
+
onInputSave(comment);
|
|
357
|
+
return;
|
|
440
358
|
}
|
|
441
|
-
|
|
442
|
-
const
|
|
443
|
-
const
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
// Multi-select annotation
|
|
448
|
-
const selected = multiSelect.selectedElements.value
|
|
449
|
-
const elements = selected.map(el => ({
|
|
359
|
+
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
360
|
+
const detail = settings.outputDetail;
|
|
361
|
+
const url = resolvedUrl.value;
|
|
362
|
+
if (mode.value === "input-open" && multiSelect.selectedElements.value.length > 0) {
|
|
363
|
+
const selected = multiSelect.selectedElements.value;
|
|
364
|
+
const elements = selected.map((el) => ({
|
|
450
365
|
element: el.tagName.toLowerCase(),
|
|
451
366
|
elementPath: getElementPath(el),
|
|
452
|
-
cssClasses: Array.from(el.classList).join(
|
|
367
|
+
cssClasses: Array.from(el.classList).join(" "),
|
|
453
368
|
boundingBox: (() => {
|
|
454
|
-
const r = el.getBoundingClientRect()
|
|
455
|
-
return { x: r.x, y: r.y, width: r.width, height: r.height }
|
|
456
|
-
})()
|
|
457
|
-
}))
|
|
458
|
-
const firstElement = selected[0]
|
|
369
|
+
const r = el.getBoundingClientRect();
|
|
370
|
+
return { x: r.x, y: r.y, width: r.width, height: r.height };
|
|
371
|
+
})()
|
|
372
|
+
}));
|
|
373
|
+
const firstElement = selected[0];
|
|
459
374
|
const selectionBox = elements.reduce(
|
|
460
375
|
(acc, el) => {
|
|
461
|
-
const box = el.boundingBox
|
|
462
|
-
acc.left = Math.min(acc.left, box.x)
|
|
463
|
-
acc.top = Math.min(acc.top, box.y)
|
|
464
|
-
acc.right = Math.max(acc.right, box.x + box.width)
|
|
465
|
-
acc.bottom = Math.max(acc.bottom, box.y + box.height)
|
|
466
|
-
return acc
|
|
376
|
+
const box = el.boundingBox;
|
|
377
|
+
acc.left = Math.min(acc.left, box.x);
|
|
378
|
+
acc.top = Math.min(acc.top, box.y);
|
|
379
|
+
acc.right = Math.max(acc.right, box.x + box.width);
|
|
380
|
+
acc.bottom = Math.max(acc.bottom, box.y + box.height);
|
|
381
|
+
return acc;
|
|
467
382
|
},
|
|
468
|
-
{ left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity }
|
|
469
|
-
)
|
|
383
|
+
{ left: Infinity, top: Infinity, right: -Infinity, bottom: -Infinity }
|
|
384
|
+
);
|
|
470
385
|
const boundingBox = {
|
|
471
386
|
x: selectionBox.left,
|
|
472
387
|
y: selectionBox.top,
|
|
473
388
|
width: selectionBox.right - selectionBox.left,
|
|
474
|
-
height: selectionBox.bottom - selectionBox.top
|
|
475
|
-
}
|
|
476
|
-
|
|
389
|
+
height: selectionBox.bottom - selectionBox.top
|
|
390
|
+
};
|
|
477
391
|
const ann = addAnnotation({
|
|
478
|
-
x: pendingPosition.value
|
|
479
|
-
y: pendingPosition.value
|
|
392
|
+
x: pendingPosition.value.x / window.innerWidth * 100,
|
|
393
|
+
y: pendingPosition.value.y + scrollTop,
|
|
480
394
|
comment,
|
|
481
395
|
url,
|
|
482
|
-
element:
|
|
396
|
+
element: "multi",
|
|
483
397
|
elementPath: `region at (${Math.round(boundingBox.x)}, ${Math.round(boundingBox.y)})`,
|
|
484
398
|
isMultiSelect: true,
|
|
485
399
|
elements,
|
|
@@ -487,26 +401,24 @@ function onInputAdd(comment: string) {
|
|
|
487
401
|
vueComponents: getVueComponents(firstElement),
|
|
488
402
|
nearbyElements: getNearbyElements(firstElement),
|
|
489
403
|
nearbyText: getNearbyText(firstElement),
|
|
490
|
-
cssClasses: detail ===
|
|
491
|
-
fullPath: detail ===
|
|
492
|
-
computedStyles: detail ===
|
|
493
|
-
accessibility: detail ===
|
|
494
|
-
})
|
|
495
|
-
emit(
|
|
496
|
-
multiSelect.reset()
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
const
|
|
501
|
-
const
|
|
502
|
-
const centerY = area.y + area.height / 2
|
|
503
|
-
const centerElement = getElementAtPointThroughOverlay(centerX, centerY) || document.body
|
|
404
|
+
cssClasses: detail === "forensic" ? Array.from(firstElement.classList).join(" ") : void 0,
|
|
405
|
+
fullPath: detail === "forensic" ? getElementPath(firstElement) : void 0,
|
|
406
|
+
computedStyles: detail === "forensic" ? getComputedStylesSummary(firstElement) : void 0,
|
|
407
|
+
accessibility: detail === "forensic" ? getAccessibilityInfo(firstElement) : void 0
|
|
408
|
+
});
|
|
409
|
+
emit("annotation-add", ann);
|
|
410
|
+
multiSelect.reset();
|
|
411
|
+
} else if (mode.value === "input-open" && areaSelect.areaRect.value) {
|
|
412
|
+
const area = { ...areaSelect.areaRect.value };
|
|
413
|
+
const centerX = area.x + area.width / 2;
|
|
414
|
+
const centerY = area.y + area.height / 2;
|
|
415
|
+
const centerElement = getElementAtPointThroughOverlay(centerX, centerY) || document.body;
|
|
504
416
|
const ann = addAnnotation({
|
|
505
417
|
x: centerX / window.innerWidth * 100,
|
|
506
418
|
y: centerY + scrollTop,
|
|
507
419
|
comment,
|
|
508
420
|
url,
|
|
509
|
-
element:
|
|
421
|
+
element: "area",
|
|
510
422
|
elementPath: `region at (${Math.round(area.x)}, ${Math.round(area.y)})`,
|
|
511
423
|
isAreaSelect: true,
|
|
512
424
|
area,
|
|
@@ -514,20 +426,18 @@ function onInputAdd(comment: string) {
|
|
|
514
426
|
vueComponents: getVueComponents(centerElement),
|
|
515
427
|
nearbyElements: getNearbyElements(centerElement),
|
|
516
428
|
nearbyText: getNearbyText(centerElement),
|
|
517
|
-
cssClasses: detail ===
|
|
518
|
-
fullPath: detail ===
|
|
519
|
-
computedStyles: detail ===
|
|
520
|
-
accessibility: detail ===
|
|
521
|
-
})
|
|
522
|
-
emit(
|
|
523
|
-
areaSelect.reset()
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// Text selection annotation
|
|
527
|
-
const { element: el, rect, text } = pendingTextSelection.value
|
|
429
|
+
cssClasses: detail === "forensic" ? Array.from(centerElement.classList).join(" ") : void 0,
|
|
430
|
+
fullPath: detail === "forensic" ? getElementPath(centerElement) : void 0,
|
|
431
|
+
computedStyles: detail === "forensic" ? getComputedStylesSummary(centerElement) : void 0,
|
|
432
|
+
accessibility: detail === "forensic" ? getAccessibilityInfo(centerElement) : void 0
|
|
433
|
+
});
|
|
434
|
+
emit("annotation-add", ann);
|
|
435
|
+
areaSelect.reset();
|
|
436
|
+
} else if (pendingTextSelection.value) {
|
|
437
|
+
const { element: el, rect, text } = pendingTextSelection.value;
|
|
528
438
|
const ann = addAnnotation({
|
|
529
|
-
x: pendingPosition.value
|
|
530
|
-
y: pendingPosition.value
|
|
439
|
+
x: pendingPosition.value.x / window.innerWidth * 100,
|
|
440
|
+
y: pendingPosition.value.y + scrollTop,
|
|
531
441
|
comment,
|
|
532
442
|
url,
|
|
533
443
|
element: el.tagName.toLowerCase(),
|
|
@@ -537,23 +447,20 @@ function onInputAdd(comment: string) {
|
|
|
537
447
|
vueComponents: getVueComponents(el),
|
|
538
448
|
nearbyElements: getNearbyElements(el),
|
|
539
449
|
nearbyText: getNearbyText(el),
|
|
540
|
-
cssClasses: detail ===
|
|
541
|
-
fullPath: detail ===
|
|
542
|
-
computedStyles: detail ===
|
|
543
|
-
accessibility: detail ===
|
|
544
|
-
_targetRef: new WeakRef(el)
|
|
545
|
-
})
|
|
546
|
-
emit(
|
|
547
|
-
}
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
const
|
|
551
|
-
const rect = el.getBoundingClientRect()
|
|
552
|
-
const fixed = checkIsFixed(el)
|
|
553
|
-
|
|
450
|
+
cssClasses: detail === "forensic" ? Array.from(el.classList).join(" ") : void 0,
|
|
451
|
+
fullPath: detail === "forensic" ? getElementPath(el) : void 0,
|
|
452
|
+
computedStyles: detail === "forensic" ? getComputedStylesSummary(el) : void 0,
|
|
453
|
+
accessibility: detail === "forensic" ? getAccessibilityInfo(el) : void 0,
|
|
454
|
+
_targetRef: new WeakRef(el)
|
|
455
|
+
});
|
|
456
|
+
emit("annotation-add", ann);
|
|
457
|
+
} else if (pendingTarget.value) {
|
|
458
|
+
const el = pendingTarget.value;
|
|
459
|
+
const rect = el.getBoundingClientRect();
|
|
460
|
+
const fixed = checkIsFixed(el);
|
|
554
461
|
const ann = addAnnotation({
|
|
555
|
-
x: pendingPosition.value
|
|
556
|
-
y: fixed ? pendingPosition.value
|
|
462
|
+
x: pendingPosition.value.x / window.innerWidth * 100,
|
|
463
|
+
y: fixed ? pendingPosition.value.y : pendingPosition.value.y + scrollTop,
|
|
557
464
|
comment,
|
|
558
465
|
url,
|
|
559
466
|
element: el.tagName.toLowerCase(),
|
|
@@ -564,124 +471,102 @@ function onInputAdd(comment: string) {
|
|
|
564
471
|
nearbyElements: getNearbyElements(el),
|
|
565
472
|
nearbyText: getNearbyText(el),
|
|
566
473
|
boundingBox: { x: rect.x, y: rect.y, width: rect.width, height: rect.height },
|
|
567
|
-
cssClasses: detail ===
|
|
568
|
-
fullPath: detail ===
|
|
569
|
-
computedStyles: detail ===
|
|
570
|
-
accessibility: detail ===
|
|
571
|
-
})
|
|
572
|
-
emit(
|
|
474
|
+
cssClasses: detail === "forensic" ? Array.from(el.classList).join(" ") : void 0,
|
|
475
|
+
fullPath: detail === "forensic" ? getElementPath(el) : void 0,
|
|
476
|
+
computedStyles: detail === "forensic" ? getComputedStylesSummary(el) : void 0,
|
|
477
|
+
accessibility: detail === "forensic" ? getAccessibilityInfo(el) : void 0
|
|
478
|
+
});
|
|
479
|
+
emit("annotation-add", ann);
|
|
573
480
|
}
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
transition('inspect')
|
|
481
|
+
resetPendingState();
|
|
482
|
+
transition("inspect");
|
|
577
483
|
}
|
|
578
|
-
|
|
579
484
|
function onInputCancel() {
|
|
580
|
-
resetPendingState()
|
|
581
|
-
multiSelect.reset()
|
|
582
|
-
areaSelect.reset()
|
|
583
|
-
transition(
|
|
485
|
+
resetPendingState();
|
|
486
|
+
multiSelect.reset();
|
|
487
|
+
areaSelect.reset();
|
|
488
|
+
transition("inspect");
|
|
584
489
|
}
|
|
585
|
-
|
|
586
490
|
async function onCopy() {
|
|
587
|
-
const markdown = formatAnnotations(annotations.value, settings.outputDetail, resolvedUrl.value)
|
|
588
|
-
|
|
491
|
+
const markdown = formatAnnotations(annotations.value, settings.outputDetail, resolvedUrl.value);
|
|
589
492
|
if (props.copyToClipboard !== false) {
|
|
590
|
-
const success = await copyToClipboard(markdown)
|
|
493
|
+
const success = await copyToClipboard(markdown);
|
|
591
494
|
if (!success)
|
|
592
|
-
return
|
|
593
|
-
copyFeedback.value = true
|
|
495
|
+
return;
|
|
496
|
+
copyFeedback.value = true;
|
|
594
497
|
setTimeout(() => {
|
|
595
|
-
copyFeedback.value = false
|
|
596
|
-
},
|
|
498
|
+
copyFeedback.value = false;
|
|
499
|
+
}, 2e3);
|
|
597
500
|
}
|
|
598
|
-
|
|
599
|
-
emit('copy', markdown)
|
|
501
|
+
emit("copy", markdown);
|
|
600
502
|
if (settings.clearAfterCopy) {
|
|
601
|
-
const cleared = clearAnnotations()
|
|
602
|
-
emit(
|
|
503
|
+
const cleared = clearAnnotations();
|
|
504
|
+
emit("annotations-clear", cleared);
|
|
603
505
|
}
|
|
604
506
|
}
|
|
605
|
-
|
|
606
507
|
function onClear() {
|
|
607
|
-
const cleared = clearAnnotations()
|
|
608
|
-
emit(
|
|
508
|
+
const cleared = clearAnnotations();
|
|
509
|
+
emit("annotations-clear", cleared);
|
|
510
|
+
}
|
|
511
|
+
function onMarkerClick(ann) {
|
|
512
|
+
const scrollTop = window.scrollY || document.documentElement.scrollTop;
|
|
513
|
+
const markerX = ann.x / 100 * window.innerWidth;
|
|
514
|
+
const markerY = ann.isFixed ? ann.y : ann.y - scrollTop;
|
|
515
|
+
editingAnnotation.value = ann;
|
|
516
|
+
pendingPosition.value = { x: markerX, y: markerY };
|
|
517
|
+
pendingElementName.value = getElementName(ann._targetRef?.deref() || document.createElement(ann.element));
|
|
518
|
+
pendingComponentChain.value = ann.vueComponents;
|
|
519
|
+
pendingComputedStyles.value = ann.computedStyles ? Object.fromEntries(ann.computedStyles.split("\n").filter(Boolean).map((line) => {
|
|
520
|
+
const idx = line.indexOf(":");
|
|
521
|
+
return idx > -1 ? [line.slice(0, idx).trim(), line.slice(idx + 1).trim()] : [line, ""];
|
|
522
|
+
})) : ann._targetRef?.deref() ? getRelevantComputedStyles(ann._targetRef.deref()) : void 0;
|
|
523
|
+
pendingTextSelection.value = null;
|
|
524
|
+
pendingTarget.value = ann._targetRef?.deref() || null;
|
|
525
|
+
transition("input-open");
|
|
609
526
|
}
|
|
610
|
-
|
|
611
|
-
function onMarkerClick(ann: Annotation) {
|
|
612
|
-
// Open the annotation popup for editing
|
|
613
|
-
const scrollTop = window.scrollY || document.documentElement.scrollTop
|
|
614
|
-
const markerX = (ann.x / 100) * window.innerWidth
|
|
615
|
-
const markerY = ann.isFixed ? ann.y : ann.y - scrollTop
|
|
616
|
-
|
|
617
|
-
editingAnnotation.value = ann
|
|
618
|
-
pendingPosition.value = { x: markerX, y: markerY }
|
|
619
|
-
pendingElementName.value = getElementName(ann._targetRef?.deref() || document.createElement(ann.element))
|
|
620
|
-
pendingComponentChain.value = ann.vueComponents
|
|
621
|
-
pendingComputedStyles.value = ann.computedStyles
|
|
622
|
-
? Object.fromEntries(ann.computedStyles.split('\n').filter(Boolean).map((line) => {
|
|
623
|
-
const idx = line.indexOf(':')
|
|
624
|
-
return idx > -1 ? [line.slice(0, idx).trim(), line.slice(idx + 1).trim()] : [line, '']
|
|
625
|
-
}))
|
|
626
|
-
: ann._targetRef?.deref()
|
|
627
|
-
? getRelevantComputedStyles(ann._targetRef.deref()!)
|
|
628
|
-
: undefined
|
|
629
|
-
pendingTextSelection.value = null
|
|
630
|
-
pendingTarget.value = ann._targetRef?.deref() || null
|
|
631
|
-
transition('input-open')
|
|
632
|
-
}
|
|
633
|
-
|
|
634
527
|
function onInputDelete() {
|
|
635
528
|
if (!editingAnnotation.value)
|
|
636
|
-
return
|
|
637
|
-
const removed = removeAnnotation(editingAnnotation.value.id)
|
|
529
|
+
return;
|
|
530
|
+
const removed = removeAnnotation(editingAnnotation.value.id);
|
|
638
531
|
if (removed)
|
|
639
|
-
emit(
|
|
640
|
-
resetPendingState()
|
|
641
|
-
transition(
|
|
532
|
+
emit("annotation-delete", removed);
|
|
533
|
+
resetPendingState();
|
|
534
|
+
transition("inspect");
|
|
642
535
|
}
|
|
643
|
-
|
|
644
|
-
function onInputSave(comment: string) {
|
|
536
|
+
function onInputSave(comment) {
|
|
645
537
|
if (!editingAnnotation.value)
|
|
646
|
-
return
|
|
647
|
-
const updated = updateAnnotation(editingAnnotation.value.id, { comment })
|
|
538
|
+
return;
|
|
539
|
+
const updated = updateAnnotation(editingAnnotation.value.id, { comment });
|
|
648
540
|
if (updated)
|
|
649
|
-
emit(
|
|
650
|
-
resetPendingState()
|
|
651
|
-
transition(
|
|
541
|
+
emit("annotation-update", updated);
|
|
542
|
+
resetPendingState();
|
|
543
|
+
transition("inspect");
|
|
652
544
|
}
|
|
653
|
-
|
|
654
|
-
|
|
655
|
-
areaSelect.isAreaMode.value = value
|
|
545
|
+
function onToggleArea(value) {
|
|
546
|
+
areaSelect.isAreaMode.value = value;
|
|
656
547
|
}
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
settings.toolbarPlacement = value
|
|
548
|
+
function onToolbarPlacementUpdate(value) {
|
|
549
|
+
settings.toolbarPlacement = value;
|
|
660
550
|
}
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
Object.assign(settings, updates)
|
|
551
|
+
function onSettingsUpdate(updates) {
|
|
552
|
+
Object.assign(settings, updates);
|
|
664
553
|
}
|
|
665
|
-
|
|
666
|
-
function onOpenSettings(anchorEl: HTMLElement | null) {
|
|
554
|
+
function onOpenSettings(anchorEl) {
|
|
667
555
|
if (settingsOpen.value && settingsAnchorEl.value === anchorEl) {
|
|
668
|
-
closeSettings()
|
|
669
|
-
return
|
|
556
|
+
closeSettings();
|
|
557
|
+
return;
|
|
670
558
|
}
|
|
671
|
-
settingsAnchorEl.value = anchorEl
|
|
672
|
-
settingsOpen.value = true
|
|
559
|
+
settingsAnchorEl.value = anchorEl;
|
|
560
|
+
settingsOpen.value = true;
|
|
673
561
|
}
|
|
674
|
-
|
|
675
|
-
// Keyboard shortcut manager
|
|
676
|
-
const shortcutConfig = computed<KeyboardShortcutConfig>(() => ({
|
|
562
|
+
const shortcutConfig = computed(() => ({
|
|
677
563
|
...DEFAULT_SHORTCUT_CONFIG,
|
|
678
564
|
doubleTap: {
|
|
679
565
|
...DEFAULT_SHORTCUT_CONFIG.doubleTap,
|
|
680
|
-
enabled: settings.activationKey !==
|
|
681
|
-
key: settings.activationKey !==
|
|
682
|
-
}
|
|
683
|
-
}))
|
|
684
|
-
|
|
566
|
+
enabled: settings.activationKey !== "none",
|
|
567
|
+
key: settings.activationKey !== "none" ? settings.activationKey : DEFAULT_SHORTCUT_CONFIG.doubleTap.key
|
|
568
|
+
}
|
|
569
|
+
}));
|
|
685
570
|
useKeyboardShortcuts({
|
|
686
571
|
mode,
|
|
687
572
|
settingsOpen,
|
|
@@ -699,44 +584,46 @@ useKeyboardShortcuts({
|
|
|
699
584
|
clear: () => onClear(),
|
|
700
585
|
openSettings: () => onOpenSettings(null),
|
|
701
586
|
inputCancel: () => onInputCancel(),
|
|
702
|
-
closeSettings: () => closeSettings()
|
|
703
|
-
}
|
|
704
|
-
})
|
|
705
|
-
|
|
587
|
+
closeSettings: () => closeSettings()
|
|
588
|
+
}
|
|
589
|
+
});
|
|
706
590
|
onMounted(() => {
|
|
707
|
-
patchHistoryEvents()
|
|
708
|
-
window.addEventListener(HISTORY_CHANGE_EVENT, syncUrlScopeFromWindow)
|
|
709
|
-
window.addEventListener(
|
|
710
|
-
window.addEventListener(
|
|
711
|
-
document.addEventListener(
|
|
712
|
-
document.addEventListener(
|
|
713
|
-
document.addEventListener(
|
|
714
|
-
document.addEventListener(
|
|
715
|
-
document.addEventListener(
|
|
716
|
-
})
|
|
717
|
-
|
|
591
|
+
patchHistoryEvents();
|
|
592
|
+
window.addEventListener(HISTORY_CHANGE_EVENT, syncUrlScopeFromWindow);
|
|
593
|
+
window.addEventListener("popstate", syncUrlScopeFromWindow);
|
|
594
|
+
window.addEventListener("hashchange", syncUrlScopeFromWindow);
|
|
595
|
+
document.addEventListener("mousemove", onDocumentMouseMove, true);
|
|
596
|
+
document.addEventListener("mousedown", onDocumentMouseDown, true);
|
|
597
|
+
document.addEventListener("mouseup", onDocumentMouseUp, true);
|
|
598
|
+
document.addEventListener("wheel", onDocumentWheel, { passive: true, capture: true });
|
|
599
|
+
document.addEventListener("click", onDocumentClick, true);
|
|
600
|
+
});
|
|
718
601
|
onBeforeUnmount(() => {
|
|
719
|
-
window.removeEventListener(HISTORY_CHANGE_EVENT, syncUrlScopeFromWindow)
|
|
720
|
-
window.removeEventListener(
|
|
721
|
-
window.removeEventListener(
|
|
722
|
-
document.removeEventListener(
|
|
723
|
-
document.removeEventListener(
|
|
724
|
-
document.removeEventListener(
|
|
725
|
-
document.removeEventListener(
|
|
726
|
-
document.removeEventListener(
|
|
727
|
-
})
|
|
602
|
+
window.removeEventListener(HISTORY_CHANGE_EVENT, syncUrlScopeFromWindow);
|
|
603
|
+
window.removeEventListener("popstate", syncUrlScopeFromWindow);
|
|
604
|
+
window.removeEventListener("hashchange", syncUrlScopeFromWindow);
|
|
605
|
+
document.removeEventListener("mousemove", onDocumentMouseMove, true);
|
|
606
|
+
document.removeEventListener("mousedown", onDocumentMouseDown, true);
|
|
607
|
+
document.removeEventListener("mouseup", onDocumentMouseUp, true);
|
|
608
|
+
document.removeEventListener("wheel", onDocumentWheel, true);
|
|
609
|
+
document.removeEventListener("click", onDocumentClick, true);
|
|
610
|
+
});
|
|
728
611
|
</script>
|
|
729
612
|
|
|
730
613
|
<template>
|
|
731
614
|
<component :is="portalWrapper" v-bind="portalProps">
|
|
732
|
-
<div ref="rootEl" data-agentation-vue :data-va-theme="settings.theme !== 'auto' ? settings.theme :
|
|
615
|
+
<div ref="rootEl" data-agentation-vue :data-va-theme="settings.theme !== 'auto' ? settings.theme : void 0" :style="rootStyle">
|
|
733
616
|
<!-- Intercept overlay -->
|
|
734
617
|
<div
|
|
735
618
|
v-if="mode !== 'idle'"
|
|
736
619
|
ref="overlayEl"
|
|
737
620
|
class="__va-intercept"
|
|
738
|
-
:class="{
|
|
739
|
-
|
|
621
|
+
:class="{
|
|
622
|
+
'__va-intercept--input-open': mode === 'input-open'
|
|
623
|
+
}"
|
|
624
|
+
:style="mode === 'inspect' && !effectiveBlockPageInteractions ? {
|
|
625
|
+
pointerEvents: 'none'
|
|
626
|
+
} : void 0"
|
|
740
627
|
@mousemove="onOverlayMouseMove"
|
|
741
628
|
@mousedown="onOverlayMouseDown"
|
|
742
629
|
@mouseup="onOverlayMouseUp"
|