@weave-apps/sdk 0.10.0 → 0.12.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/dist/WeaveDOMAPI.d.ts +66 -0
- package/dist/WeaveDOMAPI.d.ts.map +1 -1
- package/dist/WeaveDOMAPI.js +51 -0
- package/dist/apis/api-mono/services/interfaces/WorkflowsTriggersWorkflowCompanyIdPostPost.d.ts +224 -0
- package/dist/apis/api-mono/services/interfaces/WorkflowsTriggersWorkflowCompanyIdPostPost.d.ts.map +1 -0
- package/dist/apis/api-mono/services/interfaces/WorkflowsTriggersWorkflowCompanyIdPostPost.js +66 -0
- package/dist/app-sdk/src/WeaveAPIClient.d.ts +373 -0
- package/dist/app-sdk/src/WeaveAPIClient.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveAPIClient.js +361 -0
- package/dist/app-sdk/src/WeaveAppInstanceAPI.d.ts +237 -0
- package/dist/app-sdk/src/WeaveAppInstanceAPI.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveAppInstanceAPI.js +395 -0
- package/dist/app-sdk/src/WeaveBackgroundAPI.d.ts +81 -0
- package/dist/app-sdk/src/WeaveBackgroundAPI.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveBackgroundAPI.js +165 -0
- package/dist/app-sdk/src/WeaveBaseApp.d.ts +318 -0
- package/dist/app-sdk/src/WeaveBaseApp.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveBaseApp.js +434 -0
- package/dist/app-sdk/src/WeaveCronAPI.d.ts +68 -0
- package/dist/app-sdk/src/WeaveCronAPI.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveCronAPI.js +172 -0
- package/dist/app-sdk/src/WeaveDOMAPI.d.ts +593 -0
- package/dist/app-sdk/src/WeaveDOMAPI.d.ts.map +1 -0
- package/dist/app-sdk/src/WeaveDOMAPI.js +774 -0
- package/dist/app-sdk/src/global.d.ts +25 -0
- package/dist/app-sdk/src/global.d.ts.map +1 -0
- package/dist/app-sdk/src/global.js +23 -0
- package/dist/app-sdk/src/index.d.ts +14 -0
- package/dist/app-sdk/src/index.d.ts.map +1 -0
- package/dist/app-sdk/src/index.js +14 -0
- package/package.json +3 -3
- package/templates/WEAVE_SPEC.md +459 -2
|
@@ -0,0 +1,774 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Weave DOM API
|
|
3
|
+
*
|
|
4
|
+
* Client-side API for iframe apps to interact with the parent page DOM
|
|
5
|
+
* through the secure DOM Bridge in the content script.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* DOM operation types (must match content script)
|
|
9
|
+
*/
|
|
10
|
+
var DOMOperation;
|
|
11
|
+
(function (DOMOperation) {
|
|
12
|
+
// Read operations
|
|
13
|
+
DOMOperation["QUERY"] = "QUERY";
|
|
14
|
+
DOMOperation["QUERY_ALL"] = "QUERY_ALL";
|
|
15
|
+
DOMOperation["GET_TEXT"] = "GET_TEXT";
|
|
16
|
+
DOMOperation["GET_ATTRIBUTE"] = "GET_ATTRIBUTE";
|
|
17
|
+
DOMOperation["GET_VALUE"] = "GET_VALUE";
|
|
18
|
+
DOMOperation["IS_CHECKED"] = "IS_CHECKED";
|
|
19
|
+
DOMOperation["HAS_CLASS"] = "HAS_CLASS";
|
|
20
|
+
DOMOperation["GET_PAGE_URL"] = "GET_PAGE_URL";
|
|
21
|
+
// Write operations
|
|
22
|
+
DOMOperation["SET_TEXT"] = "SET_TEXT";
|
|
23
|
+
DOMOperation["SET_ATTRIBUTE"] = "SET_ATTRIBUTE";
|
|
24
|
+
DOMOperation["SET_VALUE"] = "SET_VALUE";
|
|
25
|
+
DOMOperation["ADD_CLASS"] = "ADD_CLASS";
|
|
26
|
+
DOMOperation["REMOVE_CLASS"] = "REMOVE_CLASS";
|
|
27
|
+
DOMOperation["TOGGLE_CLASS"] = "TOGGLE_CLASS";
|
|
28
|
+
DOMOperation["SET_STYLE"] = "SET_STYLE";
|
|
29
|
+
// DOM manipulation
|
|
30
|
+
DOMOperation["INSERT_HTML"] = "INSERT_HTML";
|
|
31
|
+
DOMOperation["REMOVE_ELEMENT"] = "REMOVE_ELEMENT";
|
|
32
|
+
// Element injection with event listeners
|
|
33
|
+
DOMOperation["INJECT_ELEMENT"] = "INJECT_ELEMENT";
|
|
34
|
+
DOMOperation["REMOVE_INJECTED_ELEMENT"] = "REMOVE_INJECTED_ELEMENT";
|
|
35
|
+
// Form operations
|
|
36
|
+
DOMOperation["GET_FORM_DATA"] = "GET_FORM_DATA";
|
|
37
|
+
DOMOperation["START_FORM_CLICK_LISTENER"] = "START_FORM_CLICK_LISTENER";
|
|
38
|
+
DOMOperation["STOP_FORM_CLICK_LISTENER"] = "STOP_FORM_CLICK_LISTENER";
|
|
39
|
+
DOMOperation["SET_FORM_FIELD_VALUE"] = "SET_FORM_FIELD_VALUE";
|
|
40
|
+
// Element click listener operations
|
|
41
|
+
DOMOperation["START_ELEMENT_CLICK_LISTENER"] = "START_ELEMENT_CLICK_LISTENER";
|
|
42
|
+
DOMOperation["STOP_ELEMENT_CLICK_LISTENER"] = "STOP_ELEMENT_CLICK_LISTENER";
|
|
43
|
+
// Element hover listener operations
|
|
44
|
+
DOMOperation["START_ELEMENT_HOVER_LISTENER"] = "START_ELEMENT_HOVER_LISTENER";
|
|
45
|
+
DOMOperation["STOP_ELEMENT_HOVER_LISTENER"] = "STOP_ELEMENT_HOVER_LISTENER";
|
|
46
|
+
// Click operation
|
|
47
|
+
DOMOperation["CLICK_ELEMENT"] = "CLICK_ELEMENT";
|
|
48
|
+
// Element watching operations
|
|
49
|
+
DOMOperation["WATCH_ELEMENT"] = "WATCH_ELEMENT";
|
|
50
|
+
DOMOperation["UNWATCH_ELEMENT"] = "UNWATCH_ELEMENT";
|
|
51
|
+
// Navigation operations
|
|
52
|
+
DOMOperation["RELOAD_PAGE"] = "RELOAD_PAGE";
|
|
53
|
+
// Scroll operations
|
|
54
|
+
DOMOperation["SCROLL_INTO_VIEW"] = "SCROLL_INTO_VIEW";
|
|
55
|
+
// Dialog operations
|
|
56
|
+
DOMOperation["SHOW_ALERT"] = "SHOW_ALERT";
|
|
57
|
+
DOMOperation["SHOW_CONFIRM"] = "SHOW_CONFIRM";
|
|
58
|
+
})(DOMOperation || (DOMOperation = {}));
|
|
59
|
+
/**
|
|
60
|
+
* Weave DOM API
|
|
61
|
+
* Provides methods for iframe apps to interact with parent page DOM
|
|
62
|
+
*/
|
|
63
|
+
export class WeaveDOMAPI {
|
|
64
|
+
constructor() {
|
|
65
|
+
this.pendingRequests = new Map();
|
|
66
|
+
this.messageListener = null;
|
|
67
|
+
this.requestCounter = 0;
|
|
68
|
+
this.timeout = 5000; // 5 second timeout
|
|
69
|
+
this.formClickCallback = null;
|
|
70
|
+
this.workflowSavedCallback = null;
|
|
71
|
+
this.triggerSavedCallback = null;
|
|
72
|
+
this.elementClickCallbacks = new Map();
|
|
73
|
+
this.elementSelectorClickCallbacks = new Map();
|
|
74
|
+
this.elementSelectorHoverCallbacks = new Map();
|
|
75
|
+
this.elementChangeCallbacks = new Map();
|
|
76
|
+
this.elementIdCounter = 0;
|
|
77
|
+
this.watcherIdCounter = 0;
|
|
78
|
+
this.initialize();
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Initialize the API and start listening for responses
|
|
82
|
+
*/
|
|
83
|
+
initialize() {
|
|
84
|
+
this.messageListener = (event) => {
|
|
85
|
+
this.handleResponse(event);
|
|
86
|
+
};
|
|
87
|
+
window.addEventListener('message', this.messageListener);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Cleanup
|
|
91
|
+
*/
|
|
92
|
+
destroy() {
|
|
93
|
+
if (this.messageListener) {
|
|
94
|
+
window.removeEventListener('message', this.messageListener);
|
|
95
|
+
this.messageListener = null;
|
|
96
|
+
}
|
|
97
|
+
this.pendingRequests.clear();
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Handle response from content script
|
|
101
|
+
*/
|
|
102
|
+
handleResponse(event) {
|
|
103
|
+
const data = event.data;
|
|
104
|
+
// Only accept messages from parent (content script)
|
|
105
|
+
if (event.source !== window.parent) {
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// Handle form click events
|
|
109
|
+
if (data?.type === 'WEAVE_FORM_CLICKED') {
|
|
110
|
+
if (this.formClickCallback) {
|
|
111
|
+
this.formClickCallback({
|
|
112
|
+
formData: data.formData,
|
|
113
|
+
clickedElement: data.clickedElement,
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
// Handle workflow saved events
|
|
119
|
+
if (data?.type === 'WORKFLOW_SAVED') {
|
|
120
|
+
if (this.workflowSavedCallback) {
|
|
121
|
+
this.workflowSavedCallback(data.payload);
|
|
122
|
+
}
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
// Handle trigger saved events
|
|
126
|
+
if (data?.type === 'TRIGGER_SAVED') {
|
|
127
|
+
if (this.triggerSavedCallback) {
|
|
128
|
+
this.triggerSavedCallback(data.payload);
|
|
129
|
+
}
|
|
130
|
+
return;
|
|
131
|
+
}
|
|
132
|
+
// Handle element click events (for injected elements)
|
|
133
|
+
if (data?.type === 'WEAVE_ELEMENT_CLICKED') {
|
|
134
|
+
const callback = this.elementClickCallbacks.get(data.elementId);
|
|
135
|
+
if (callback) {
|
|
136
|
+
callback({
|
|
137
|
+
elementId: data.elementId,
|
|
138
|
+
event: data.event,
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
// Handle element selector click events (for element click listeners)
|
|
144
|
+
if (data?.type === 'WEAVE_ELEMENT_SELECTOR_CLICKED') {
|
|
145
|
+
const callback = this.elementSelectorClickCallbacks.get(data.listenerId);
|
|
146
|
+
if (callback) {
|
|
147
|
+
callback({
|
|
148
|
+
element: data.element,
|
|
149
|
+
event: data.event,
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
return;
|
|
153
|
+
}
|
|
154
|
+
// Handle element selector hover events (for element hover listeners)
|
|
155
|
+
if (data?.type === 'WEAVE_ELEMENT_SELECTOR_HOVERED') {
|
|
156
|
+
const callback = this.elementSelectorHoverCallbacks.get(data.listenerId);
|
|
157
|
+
if (callback) {
|
|
158
|
+
callback({
|
|
159
|
+
element: data.element,
|
|
160
|
+
event: data.event,
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
// Handle element change events (for element watchers)
|
|
166
|
+
if (data?.type === 'WEAVE_ELEMENT_CHANGED') {
|
|
167
|
+
const callback = this.elementChangeCallbacks.get(data.watcherId);
|
|
168
|
+
if (callback) {
|
|
169
|
+
callback({
|
|
170
|
+
changeType: data.changeType,
|
|
171
|
+
element: data.element,
|
|
172
|
+
attributeName: data.attributeName,
|
|
173
|
+
attributeValue: data.attributeValue,
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
178
|
+
// Handle normal DOM operation responses
|
|
179
|
+
if (data?.type !== 'WEAVE_DOM_RESPONSE') {
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const response = data;
|
|
183
|
+
const pending = this.pendingRequests.get(response.id);
|
|
184
|
+
if (!pending) {
|
|
185
|
+
return;
|
|
186
|
+
}
|
|
187
|
+
this.pendingRequests.delete(response.id);
|
|
188
|
+
if (response.success) {
|
|
189
|
+
pending.resolve(response.data);
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
pending.reject(new Error(response.error || 'Unknown error'));
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* Send request to content script
|
|
197
|
+
*/
|
|
198
|
+
sendRequest(operation, payload) {
|
|
199
|
+
return new Promise((resolve, reject) => {
|
|
200
|
+
const id = `dom-request-${++this.requestCounter}`;
|
|
201
|
+
const request = {
|
|
202
|
+
type: 'WEAVE_DOM_REQUEST',
|
|
203
|
+
id,
|
|
204
|
+
operation,
|
|
205
|
+
payload,
|
|
206
|
+
};
|
|
207
|
+
// Store pending request
|
|
208
|
+
this.pendingRequests.set(id, { resolve, reject });
|
|
209
|
+
// Set timeout
|
|
210
|
+
const timeoutId = setTimeout(() => {
|
|
211
|
+
this.pendingRequests.delete(id);
|
|
212
|
+
reject(new Error(`Request timeout: ${operation}`));
|
|
213
|
+
}, this.timeout);
|
|
214
|
+
// Clear timeout on resolve/reject
|
|
215
|
+
const originalResolve = resolve;
|
|
216
|
+
const originalReject = reject;
|
|
217
|
+
this.pendingRequests.set(id, {
|
|
218
|
+
resolve: (value) => {
|
|
219
|
+
clearTimeout(timeoutId);
|
|
220
|
+
originalResolve(value);
|
|
221
|
+
},
|
|
222
|
+
reject: (error) => {
|
|
223
|
+
clearTimeout(timeoutId);
|
|
224
|
+
originalReject(error);
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
// Send to parent window (content script will intercept)
|
|
228
|
+
window.parent.postMessage(request, '*');
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
// ============================================================================
|
|
232
|
+
// Read Operations
|
|
233
|
+
// ============================================================================
|
|
234
|
+
/**
|
|
235
|
+
* Query a single element from parent page
|
|
236
|
+
*/
|
|
237
|
+
async query(selector) {
|
|
238
|
+
return this.sendRequest(DOMOperation.QUERY, { selector });
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Query all matching elements from parent page
|
|
242
|
+
*/
|
|
243
|
+
async queryAll(selector) {
|
|
244
|
+
return this.sendRequest(DOMOperation.QUERY_ALL, { selector });
|
|
245
|
+
}
|
|
246
|
+
/**
|
|
247
|
+
* Get text content of an element
|
|
248
|
+
*/
|
|
249
|
+
async getText(selector) {
|
|
250
|
+
return this.sendRequest(DOMOperation.GET_TEXT, { selector });
|
|
251
|
+
}
|
|
252
|
+
/**
|
|
253
|
+
* Get attribute value of an element
|
|
254
|
+
*/
|
|
255
|
+
async getAttribute(selector, attribute) {
|
|
256
|
+
return this.sendRequest(DOMOperation.GET_ATTRIBUTE, {
|
|
257
|
+
selector,
|
|
258
|
+
attribute
|
|
259
|
+
});
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Get value of an input element
|
|
263
|
+
*/
|
|
264
|
+
async getValue(selector) {
|
|
265
|
+
return this.sendRequest(DOMOperation.GET_VALUE, { selector });
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* Check if a checkbox or radio button is checked
|
|
269
|
+
* @param selector - CSS selector for the checkbox/radio element
|
|
270
|
+
* @returns Promise with true if checked, false otherwise
|
|
271
|
+
*
|
|
272
|
+
* @example
|
|
273
|
+
* ```typescript
|
|
274
|
+
* const isChecked = await weaveDOM.isChecked('#my-checkbox');
|
|
275
|
+
* if (isChecked) {
|
|
276
|
+
* console.log('Checkbox is checked');
|
|
277
|
+
* }
|
|
278
|
+
* ```
|
|
279
|
+
*/
|
|
280
|
+
async isChecked(selector) {
|
|
281
|
+
return this.sendRequest(DOMOperation.IS_CHECKED, { selector });
|
|
282
|
+
}
|
|
283
|
+
/**
|
|
284
|
+
* Check if element has a class
|
|
285
|
+
*/
|
|
286
|
+
async hasClass(selector, className) {
|
|
287
|
+
return this.sendRequest(DOMOperation.HAS_CLASS, {
|
|
288
|
+
selector,
|
|
289
|
+
className
|
|
290
|
+
});
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Get the current page URL
|
|
294
|
+
* Returns the parent page URL (not the iframe URL)
|
|
295
|
+
* @returns Promise with the current page URL
|
|
296
|
+
*/
|
|
297
|
+
async getPageUrl() {
|
|
298
|
+
return this.sendRequest(DOMOperation.GET_PAGE_URL, {});
|
|
299
|
+
}
|
|
300
|
+
/**
|
|
301
|
+
* Reload the current page
|
|
302
|
+
* Triggers a full page reload of the parent page
|
|
303
|
+
*/
|
|
304
|
+
async reloadPage() {
|
|
305
|
+
return this.sendRequest(DOMOperation.RELOAD_PAGE, {});
|
|
306
|
+
}
|
|
307
|
+
// ============================================================================
|
|
308
|
+
// Write Operations
|
|
309
|
+
// ============================================================================
|
|
310
|
+
/**
|
|
311
|
+
* Set text content of an element
|
|
312
|
+
*/
|
|
313
|
+
async setText(selector, text) {
|
|
314
|
+
return this.sendRequest(DOMOperation.SET_TEXT, { selector, text });
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Set attribute value of an element
|
|
318
|
+
*/
|
|
319
|
+
async setAttribute(selector, attribute, value) {
|
|
320
|
+
return this.sendRequest(DOMOperation.SET_ATTRIBUTE, {
|
|
321
|
+
selector,
|
|
322
|
+
attribute,
|
|
323
|
+
value
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
/**
|
|
327
|
+
* Set value of an input element
|
|
328
|
+
*/
|
|
329
|
+
async setValue(selector, value) {
|
|
330
|
+
return this.sendRequest(DOMOperation.SET_VALUE, { selector, value });
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Add a class to an element
|
|
334
|
+
*/
|
|
335
|
+
async addClass(selector, className) {
|
|
336
|
+
return this.sendRequest(DOMOperation.ADD_CLASS, { selector, className });
|
|
337
|
+
}
|
|
338
|
+
/**
|
|
339
|
+
* Remove a class from an element
|
|
340
|
+
*/
|
|
341
|
+
async removeClass(selector, className) {
|
|
342
|
+
return this.sendRequest(DOMOperation.REMOVE_CLASS, { selector, className });
|
|
343
|
+
}
|
|
344
|
+
/**
|
|
345
|
+
* Toggle a class on an element
|
|
346
|
+
*/
|
|
347
|
+
async toggleClass(selector, className) {
|
|
348
|
+
return this.sendRequest(DOMOperation.TOGGLE_CLASS, { selector, className });
|
|
349
|
+
}
|
|
350
|
+
/**
|
|
351
|
+
* Set a CSS style property on an element
|
|
352
|
+
*/
|
|
353
|
+
async setStyle(selector, property, value) {
|
|
354
|
+
return this.sendRequest(DOMOperation.SET_STYLE, {
|
|
355
|
+
selector,
|
|
356
|
+
property,
|
|
357
|
+
value
|
|
358
|
+
});
|
|
359
|
+
}
|
|
360
|
+
/**
|
|
361
|
+
* Insert HTML relative to an element
|
|
362
|
+
*/
|
|
363
|
+
async insertHTML(selector, position, html) {
|
|
364
|
+
return this.sendRequest(DOMOperation.INSERT_HTML, {
|
|
365
|
+
selector,
|
|
366
|
+
position,
|
|
367
|
+
html
|
|
368
|
+
});
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Remove an element from the DOM
|
|
372
|
+
*/
|
|
373
|
+
async removeElement(selector) {
|
|
374
|
+
return this.sendRequest(DOMOperation.REMOVE_ELEMENT, { selector });
|
|
375
|
+
}
|
|
376
|
+
/**
|
|
377
|
+
* Click an element on the parent page
|
|
378
|
+
*
|
|
379
|
+
* @param selector - CSS selector for the element to click
|
|
380
|
+
* @returns Promise that resolves when the click is complete
|
|
381
|
+
*
|
|
382
|
+
* @example
|
|
383
|
+
* // Click a button
|
|
384
|
+
* await weaveDOM.clickElement('button#submit');
|
|
385
|
+
*
|
|
386
|
+
* // Click a link
|
|
387
|
+
* await weaveDOM.clickElement('a.nav-item[href="/dashboard"]');
|
|
388
|
+
*/
|
|
389
|
+
async clickElement(selector) {
|
|
390
|
+
return this.sendRequest(DOMOperation.CLICK_ELEMENT, { selector });
|
|
391
|
+
}
|
|
392
|
+
// ============================================================================
|
|
393
|
+
// Form Operations
|
|
394
|
+
// ============================================================================
|
|
395
|
+
/**
|
|
396
|
+
* Get form data from a form or an element inside a form
|
|
397
|
+
* @param selector - CSS selector for the form or an element inside the form
|
|
398
|
+
* @returns Promise with complete form data including all fields
|
|
399
|
+
*/
|
|
400
|
+
async getFormData(selector) {
|
|
401
|
+
return this.sendRequest(DOMOperation.GET_FORM_DATA, { selector });
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Start listening for clicks on form elements
|
|
405
|
+
* When a form element is clicked, the callback will be invoked with the form data
|
|
406
|
+
* @param callback - Function to call when a form element is clicked
|
|
407
|
+
*/
|
|
408
|
+
async startFormClickListener(callback) {
|
|
409
|
+
this.formClickCallback = callback;
|
|
410
|
+
return this.sendRequest(DOMOperation.START_FORM_CLICK_LISTENER, {});
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Stop listening for clicks on form elements
|
|
414
|
+
*/
|
|
415
|
+
async stopFormClickListener() {
|
|
416
|
+
this.formClickCallback = null;
|
|
417
|
+
return this.sendRequest(DOMOperation.STOP_FORM_CLICK_LISTENER, {});
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Start listening for clicks on elements matching a CSS selector
|
|
421
|
+
* When an element is clicked, the callback will be invoked with element data
|
|
422
|
+
*
|
|
423
|
+
* @param selector - CSS selector for elements to listen to (e.g., 'div.sortable-item[role="button"]')
|
|
424
|
+
* @param callback - Function to call when a matching element is clicked
|
|
425
|
+
* @param options - Optional configuration
|
|
426
|
+
* @param options.listenerId - Unique ID for this listener (auto-generated if not provided)
|
|
427
|
+
* @returns Promise<string> - The listener ID (for cleanup with stopElementClickListener)
|
|
428
|
+
*
|
|
429
|
+
* @example
|
|
430
|
+
* // Listen to tab buttons
|
|
431
|
+
* const listenerId = await weaveDOM.startElementClickListener(
|
|
432
|
+
* 'div.sortable-item[role="button"]',
|
|
433
|
+
* (data) => {
|
|
434
|
+
* console.log('Tab clicked:', data.element.textContent);
|
|
435
|
+
* console.log('Element:', data.element);
|
|
436
|
+
* }
|
|
437
|
+
* );
|
|
438
|
+
*
|
|
439
|
+
* // Later, stop listening
|
|
440
|
+
* await weaveDOM.stopElementClickListener(listenerId);
|
|
441
|
+
*/
|
|
442
|
+
async startElementClickListener(selector, callback, options) {
|
|
443
|
+
const listenerId = options?.listenerId || `listener-${Date.now()}-${Math.random()}`;
|
|
444
|
+
// Store callback
|
|
445
|
+
this.elementSelectorClickCallbacks.set(listenerId, callback);
|
|
446
|
+
// Send request to content script
|
|
447
|
+
await this.sendRequest(DOMOperation.START_ELEMENT_CLICK_LISTENER, {
|
|
448
|
+
selector,
|
|
449
|
+
listenerId,
|
|
450
|
+
});
|
|
451
|
+
return listenerId;
|
|
452
|
+
}
|
|
453
|
+
/**
|
|
454
|
+
* Stop listening for clicks on elements
|
|
455
|
+
*
|
|
456
|
+
* @param listenerId - The ID of the listener to stop (returned from startElementClickListener)
|
|
457
|
+
*
|
|
458
|
+
* @example
|
|
459
|
+
* const listenerId = await weaveDOM.startElementClickListener('button', callback);
|
|
460
|
+
* // ... later ...
|
|
461
|
+
* await weaveDOM.stopElementClickListener(listenerId);
|
|
462
|
+
*/
|
|
463
|
+
async stopElementClickListener(listenerId) {
|
|
464
|
+
// Remove callback
|
|
465
|
+
this.elementSelectorClickCallbacks.delete(listenerId);
|
|
466
|
+
// Send request to content script
|
|
467
|
+
return this.sendRequest(DOMOperation.STOP_ELEMENT_CLICK_LISTENER, {
|
|
468
|
+
listenerId,
|
|
469
|
+
});
|
|
470
|
+
}
|
|
471
|
+
/**
|
|
472
|
+
* Start listening for hover on elements matching a CSS selector
|
|
473
|
+
* When an element is hovered for the configured delay, the callback will be invoked with element data
|
|
474
|
+
*
|
|
475
|
+
* @param selector - CSS selector for elements to listen to
|
|
476
|
+
* @param callback - Function to call when a matching element is hovered
|
|
477
|
+
* @param options - Optional configuration
|
|
478
|
+
* @param options.listenerId - Unique ID for this listener (auto-generated if not provided)
|
|
479
|
+
* @param options.hoverDelayMs - Delay in milliseconds before hover callback fires (default: 1000)
|
|
480
|
+
* @returns Promise<string> - The listener ID (for cleanup with stopElementHoverListener)
|
|
481
|
+
*/
|
|
482
|
+
async startElementHoverListener(selector, callback, options) {
|
|
483
|
+
const listenerId = options?.listenerId || `hover-listener-${Date.now()}-${Math.random()}`;
|
|
484
|
+
// Store callback
|
|
485
|
+
this.elementSelectorHoverCallbacks.set(listenerId, callback);
|
|
486
|
+
// Send request to content script
|
|
487
|
+
await this.sendRequest(DOMOperation.START_ELEMENT_HOVER_LISTENER, {
|
|
488
|
+
selector,
|
|
489
|
+
listenerId,
|
|
490
|
+
hoverDelayMs: options?.hoverDelayMs,
|
|
491
|
+
});
|
|
492
|
+
return listenerId;
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Stop listening for hover on elements
|
|
496
|
+
*
|
|
497
|
+
* @param listenerId - The ID of the listener to stop (returned from startElementHoverListener)
|
|
498
|
+
*/
|
|
499
|
+
async stopElementHoverListener(listenerId) {
|
|
500
|
+
// Remove callback
|
|
501
|
+
this.elementSelectorHoverCallbacks.delete(listenerId);
|
|
502
|
+
// Send request to content script
|
|
503
|
+
return this.sendRequest(DOMOperation.STOP_ELEMENT_HOVER_LISTENER, {
|
|
504
|
+
listenerId,
|
|
505
|
+
});
|
|
506
|
+
}
|
|
507
|
+
/**
|
|
508
|
+
* Set the value of a form field
|
|
509
|
+
* Handles all input types (text, checkbox, radio, select, textarea, etc.)
|
|
510
|
+
* Automatically triggers validation events
|
|
511
|
+
*
|
|
512
|
+
* @param selector - CSS selector for the form field
|
|
513
|
+
* @param value - Value to set (string for text inputs, boolean for checkboxes, array for multi-selects)
|
|
514
|
+
* @param scrollIntoView - Optional: if true, scrolls element to center of viewport before setting value (default: false)
|
|
515
|
+
*
|
|
516
|
+
* @example
|
|
517
|
+
* // Text input
|
|
518
|
+
* await weaveDOM.setFormFieldValue('input[name="email"]', 'user@example.com');
|
|
519
|
+
*
|
|
520
|
+
* // Checkbox with scroll
|
|
521
|
+
* await weaveDOM.setFormFieldValue('input[name="terms"]', true, true);
|
|
522
|
+
*
|
|
523
|
+
* // Radio button (set to the value of the radio to select)
|
|
524
|
+
* await weaveDOM.setFormFieldValue('input[name="gender"][value="female"]', 'female');
|
|
525
|
+
*
|
|
526
|
+
* // Select
|
|
527
|
+
* await weaveDOM.setFormFieldValue('select[name="country"]', 'US');
|
|
528
|
+
*
|
|
529
|
+
* // Multi-select with scroll to make it visible
|
|
530
|
+
* await weaveDOM.setFormFieldValue('select[name="interests"]', ['sports', 'music'], true);
|
|
531
|
+
*/
|
|
532
|
+
async setFormFieldValue(selector, value, scrollIntoView = false) {
|
|
533
|
+
return this.sendRequest(DOMOperation.SET_FORM_FIELD_VALUE, {
|
|
534
|
+
selector,
|
|
535
|
+
value,
|
|
536
|
+
scrollIntoView
|
|
537
|
+
});
|
|
538
|
+
}
|
|
539
|
+
// ============================================================================
|
|
540
|
+
// Event Listeners
|
|
541
|
+
// ============================================================================
|
|
542
|
+
/**
|
|
543
|
+
* Register a callback for when a workflow is saved
|
|
544
|
+
* @param callback - Function to call when a workflow is saved from the content script
|
|
545
|
+
*/
|
|
546
|
+
onWorkflowSaved(callback) {
|
|
547
|
+
this.workflowSavedCallback = callback;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Remove the workflow saved callback
|
|
551
|
+
*/
|
|
552
|
+
offWorkflowSaved() {
|
|
553
|
+
this.workflowSavedCallback = null;
|
|
554
|
+
}
|
|
555
|
+
/**
|
|
556
|
+
* Register a callback for when a trigger is saved
|
|
557
|
+
* @param callback - Function to call when a trigger is saved from the content script
|
|
558
|
+
*/
|
|
559
|
+
onTriggerSaved(callback) {
|
|
560
|
+
this.triggerSavedCallback = callback;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Remove the trigger saved callback
|
|
564
|
+
*/
|
|
565
|
+
offTriggerSaved() {
|
|
566
|
+
this.triggerSavedCallback = null;
|
|
567
|
+
}
|
|
568
|
+
// ============================================================================
|
|
569
|
+
// Element Injection Operations
|
|
570
|
+
// ============================================================================
|
|
571
|
+
/**
|
|
572
|
+
* Inject an element onto the parent page with optional click event listener
|
|
573
|
+
*
|
|
574
|
+
* @param targetSelector - CSS selector for the element to inject relative to
|
|
575
|
+
* @param position - Position relative to target ('beforebegin', 'afterbegin', 'beforeend', 'afterend')
|
|
576
|
+
* @param html - HTML string to inject (will be sanitized)
|
|
577
|
+
* @param options - Optional configuration
|
|
578
|
+
* @param options.onClick - Callback function to invoke when element is clicked
|
|
579
|
+
* @param options.elementId - Custom element ID (auto-generated if not provided)
|
|
580
|
+
* @returns Promise with the element ID
|
|
581
|
+
*
|
|
582
|
+
* @example
|
|
583
|
+
* // Inject a button with click handler
|
|
584
|
+
* const elementId = await weaveDOM.injectElement(
|
|
585
|
+
* 'body',
|
|
586
|
+
* 'beforeend',
|
|
587
|
+
* '<button class="my-button">Click Me</button>',
|
|
588
|
+
* {
|
|
589
|
+
* onClick: (data) => {
|
|
590
|
+
* console.log('Button clicked!', data);
|
|
591
|
+
* }
|
|
592
|
+
* }
|
|
593
|
+
* );
|
|
594
|
+
*
|
|
595
|
+
* // Later, remove the element
|
|
596
|
+
* await weaveDOM.removeInjectedElement(elementId);
|
|
597
|
+
*/
|
|
598
|
+
async injectElement(targetSelector, position, html, options) {
|
|
599
|
+
// Generate element ID if not provided
|
|
600
|
+
const elementId = options?.elementId || `weave-injected-${++this.elementIdCounter}`;
|
|
601
|
+
// Store click callback if provided
|
|
602
|
+
if (options?.onClick) {
|
|
603
|
+
this.elementClickCallbacks.set(elementId, options.onClick);
|
|
604
|
+
}
|
|
605
|
+
// Send injection request
|
|
606
|
+
const result = await this.sendRequest(DOMOperation.INJECT_ELEMENT, {
|
|
607
|
+
targetSelector,
|
|
608
|
+
position,
|
|
609
|
+
html,
|
|
610
|
+
elementId,
|
|
611
|
+
onClick: !!options?.onClick,
|
|
612
|
+
});
|
|
613
|
+
return result.elementId;
|
|
614
|
+
}
|
|
615
|
+
/**
|
|
616
|
+
* Remove an injected element from the parent page
|
|
617
|
+
*
|
|
618
|
+
* @param elementId - ID of the element to remove (returned from injectElement)
|
|
619
|
+
*
|
|
620
|
+
* @example
|
|
621
|
+
* await weaveDOM.removeInjectedElement('weave-injected-1');
|
|
622
|
+
*/
|
|
623
|
+
async removeInjectedElement(elementId) {
|
|
624
|
+
// Remove click callback if it exists
|
|
625
|
+
this.elementClickCallbacks.delete(elementId);
|
|
626
|
+
// Send removal request
|
|
627
|
+
return this.sendRequest(DOMOperation.REMOVE_INJECTED_ELEMENT, {
|
|
628
|
+
elementId,
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
// ============================================================================
|
|
632
|
+
// Element Watching Operations
|
|
633
|
+
// ============================================================================
|
|
634
|
+
/**
|
|
635
|
+
* Watch an element for changes (attributes, removal, children)
|
|
636
|
+
*
|
|
637
|
+
* Sets up MutationObservers to monitor:
|
|
638
|
+
* - Attribute changes on the element
|
|
639
|
+
* - Element removal from DOM
|
|
640
|
+
* - Child node changes (optional)
|
|
641
|
+
*
|
|
642
|
+
* @param selector - CSS selector for the element to watch
|
|
643
|
+
* @param callback - Function to call when element changes
|
|
644
|
+
* @param options - Optional configuration
|
|
645
|
+
* @param options.watchAttributes - Watch for attribute changes (default: true)
|
|
646
|
+
* @param options.watchChildren - Watch for child node changes (default: false)
|
|
647
|
+
* @param options.attributeFilter - Optional array of specific attributes to watch
|
|
648
|
+
* @returns Promise with the watcher ID (use to stop watching)
|
|
649
|
+
*
|
|
650
|
+
* @example
|
|
651
|
+
* // Watch for attribute changes
|
|
652
|
+
* const watcherId = await weaveDOM.watchElement(
|
|
653
|
+
* '#my-element',
|
|
654
|
+
* (data) => {
|
|
655
|
+
* if (data.changeType === 'attribute') {
|
|
656
|
+
* console.log(`Attribute ${data.attributeName} changed to: ${data.attributeValue}`);
|
|
657
|
+
* } else if (data.changeType === 'removed') {
|
|
658
|
+
* console.log('Element was removed from DOM');
|
|
659
|
+
* }
|
|
660
|
+
* },
|
|
661
|
+
* {
|
|
662
|
+
* watchAttributes: true,
|
|
663
|
+
* attributeFilter: ['class', 'data-status'] // Only watch specific attributes
|
|
664
|
+
* }
|
|
665
|
+
* );
|
|
666
|
+
*
|
|
667
|
+
* // Later, stop watching
|
|
668
|
+
* await weaveDOM.unwatchElement(watcherId);
|
|
669
|
+
*/
|
|
670
|
+
async watchElement(selector, callback, options) {
|
|
671
|
+
// Generate watcher ID
|
|
672
|
+
const watcherId = `weave-watcher-${++this.watcherIdCounter}`;
|
|
673
|
+
// Store callback
|
|
674
|
+
this.elementChangeCallbacks.set(watcherId, callback);
|
|
675
|
+
// Send watch request
|
|
676
|
+
await this.sendRequest(DOMOperation.WATCH_ELEMENT, {
|
|
677
|
+
selector,
|
|
678
|
+
watcherId,
|
|
679
|
+
watchAttributes: options?.watchAttributes,
|
|
680
|
+
watchChildren: options?.watchChildren,
|
|
681
|
+
attributeFilter: options?.attributeFilter,
|
|
682
|
+
});
|
|
683
|
+
return watcherId;
|
|
684
|
+
}
|
|
685
|
+
/**
|
|
686
|
+
* Stop watching an element
|
|
687
|
+
*
|
|
688
|
+
* @param watcherId - ID of the watcher to stop (returned from watchElement)
|
|
689
|
+
*
|
|
690
|
+
* @example
|
|
691
|
+
* await weaveDOM.unwatchElement('weave-watcher-1');
|
|
692
|
+
*/
|
|
693
|
+
async unwatchElement(watcherId) {
|
|
694
|
+
// Remove callback
|
|
695
|
+
this.elementChangeCallbacks.delete(watcherId);
|
|
696
|
+
// Send unwatch request
|
|
697
|
+
return this.sendRequest(DOMOperation.UNWATCH_ELEMENT, {
|
|
698
|
+
watcherId,
|
|
699
|
+
});
|
|
700
|
+
}
|
|
701
|
+
// ============================================================================
|
|
702
|
+
// Scroll Operations
|
|
703
|
+
// ============================================================================
|
|
704
|
+
/**
|
|
705
|
+
* Scroll an element into view on the parent page
|
|
706
|
+
*
|
|
707
|
+
* Abstraction over Element.scrollIntoView(). Accepts either a boolean
|
|
708
|
+
* `alignToTop` parameter or a `ScrollIntoViewOptions` object.
|
|
709
|
+
*
|
|
710
|
+
* @param selector - CSS selector for the element to scroll into view
|
|
711
|
+
* @param arg - Optional. A boolean (alignToTop) or a ScrollIntoViewOptions object.
|
|
712
|
+
* - `true` (default): aligns the element to the top of the scrollable ancestor
|
|
713
|
+
* - `false`: aligns the element to the bottom
|
|
714
|
+
* - `ScrollIntoViewOptions`: e.g. `{ behavior: 'smooth', block: 'center' }`
|
|
715
|
+
*
|
|
716
|
+
* @example
|
|
717
|
+
* // Scroll element to top (default)
|
|
718
|
+
* await weaveDOM.scrollIntoView('#my-element');
|
|
719
|
+
*
|
|
720
|
+
* // Scroll element to bottom
|
|
721
|
+
* await weaveDOM.scrollIntoView('#my-element', false);
|
|
722
|
+
*
|
|
723
|
+
* // Scroll with smooth animation to center
|
|
724
|
+
* await weaveDOM.scrollIntoView('#my-element', { behavior: 'smooth', block: 'center' });
|
|
725
|
+
*/
|
|
726
|
+
async scrollIntoView(selector, arg) {
|
|
727
|
+
const payload = { selector };
|
|
728
|
+
if (typeof arg === 'boolean') {
|
|
729
|
+
payload.alignToTop = arg;
|
|
730
|
+
}
|
|
731
|
+
else if (typeof arg === 'object' && arg !== null) {
|
|
732
|
+
payload.options = arg;
|
|
733
|
+
}
|
|
734
|
+
return this.sendRequest(DOMOperation.SCROLL_INTO_VIEW, payload);
|
|
735
|
+
}
|
|
736
|
+
// ============================================================================
|
|
737
|
+
// Dialog Operations
|
|
738
|
+
// ============================================================================
|
|
739
|
+
/**
|
|
740
|
+
* Show an alert dialog on the parent page
|
|
741
|
+
*
|
|
742
|
+
* This displays a native browser alert dialog with the specified message.
|
|
743
|
+
* The dialog blocks until the user clicks OK.
|
|
744
|
+
*
|
|
745
|
+
* @param message - Message to display in the alert
|
|
746
|
+
*
|
|
747
|
+
* @example
|
|
748
|
+
* await weaveDOM.alert('Please log in to continue.');
|
|
749
|
+
*/
|
|
750
|
+
async alert(message) {
|
|
751
|
+
return this.sendRequest(DOMOperation.SHOW_ALERT, { message });
|
|
752
|
+
}
|
|
753
|
+
/**
|
|
754
|
+
* Show a confirm dialog on the parent page
|
|
755
|
+
*
|
|
756
|
+
* This displays a native browser confirm dialog with the specified message.
|
|
757
|
+
* Returns true if user clicked OK, false if user clicked Cancel.
|
|
758
|
+
*
|
|
759
|
+
* @param message - Message to display in the confirm dialog
|
|
760
|
+
* @returns Promise<boolean> - true if confirmed, false if cancelled
|
|
761
|
+
*
|
|
762
|
+
* @example
|
|
763
|
+
* const confirmed = await weaveDOM.confirm('Are you sure you want to proceed?');
|
|
764
|
+
* if (confirmed) {
|
|
765
|
+
* // User clicked OK
|
|
766
|
+
* } else {
|
|
767
|
+
* // User clicked Cancel
|
|
768
|
+
* }
|
|
769
|
+
*/
|
|
770
|
+
async confirm(message) {
|
|
771
|
+
return this.sendRequest(DOMOperation.SHOW_CONFIRM, { message });
|
|
772
|
+
}
|
|
773
|
+
}
|
|
774
|
+
export default new WeaveDOMAPI();
|