openfox 2.0.39 → 2.0.41

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.
@@ -2,12 +2,13 @@
2
2
  'use strict'
3
3
 
4
4
  window.__foxInspectMode = false
5
- window.__foxSessionId = null
6
- window.__foxSessionTitle = null
7
5
  window.__foxInspectEnabled = true
8
6
  window.__foxSentPending = false
9
7
  window.__foxPopupOpen = false
10
8
  window.__foxHighlightedEl = null
9
+ window.__foxSelectedSessionId = null
10
+ window.__foxSessions = []
11
+ window.__foxSessionsError = false
11
12
 
12
13
  var overlayStyle = document.createElement('style')
13
14
  overlayStyle.textContent = [
@@ -19,18 +20,23 @@
19
20
  '#__fox-toggle.__fox-active{background:#ef4444}',
20
21
  '#__fox-toggle.__fox-active:hover{background:#dc2626}',
21
22
  '.__fox-highlight{outline:2px solid #3b82f6!important;outline-offset:1px!important}',
22
- '#__fox-popup{position:fixed;background:#1e1e1e;color:#e0e0e0;padding:12px;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.5);z-index:2147483647;min-width:300px;max-width:400px;pointer-events:auto;font-family:system-ui,sans-serif}',
23
+ '#__fox-popup{position:fixed;background:#1e1e1e;color:#e0e0e0;padding:12px;border-radius:8px;box-shadow:0 4px 20px rgba(0,0,0,.5);z-index:2147483647;min-width:320px;max-width:420px;pointer-events:auto;font-family:system-ui,sans-serif}',
23
24
  '#__fox-popup .__fox-selector{font-family:monospace;font-size:11px;color:#888;background:#2a2a2a;padding:4px 8px;border-radius:4px;word-break:break-all;margin-bottom:8px;max-height:80px;overflow:auto}',
24
25
  '#__fox-popup .__fox-tag{font-size:12px;color:#aaa;margin-bottom:8px}',
25
26
  '#__fox-popup .__fox-tag span{color:#3b82f6}',
26
27
  '#__fox-popup textarea{width:100%;background:#2a2a2a;color:#e0e0e0;border:1px solid #444;border-radius:4px;padding:6px 8px;font-size:12px;resize:vertical;min-height:60px;box-sizing:border-box;font-family:inherit}',
27
28
  '#__fox-popup textarea:focus{border-color:#3b82f6;outline:none}',
29
+ '#__fox-popup .__fox-session-row{display:flex;align-items:center;gap:6px;margin-bottom:8px;font-size:11px}',
30
+ '#__fox-popup .__fox-session-row label{color:#888;white-space:nowrap}',
31
+ '#__fox-popup .__fox-session-picker{background:#2a2a2a;color:#e0e0e0;border:1px solid #444;border-radius:4px;padding:3px 6px;font-size:11px;font-family:inherit;flex:1;cursor:pointer}',
32
+ '#__fox-popup .__fox-session-picker:focus{border-color:#3b82f6;outline:none}',
33
+ '#__fox-popup .__fox-session-picker.__fox-error{border-color:#ef4444}',
34
+ '#__fox-popup .__fox-session-picker option{background:#1e1e1e;color:#e0e0e0}',
28
35
  '#__fox-popup .__fox-actions{display:flex;justify-content:flex-end;gap:8px;margin-top:8px}',
29
36
  '#__fox-popup button.__fox-send{background:#3b82f6;color:#fff;border:none;padding:6px 14px;border-radius:4px;cursor:pointer;font-size:12px;font-family:inherit}',
30
37
  '#__fox-popup button.__fox-send:hover{background:#2563eb}',
31
38
  '#__fox-popup button.__fox-cancel{background:transparent;color:#888;border:1px solid #444;padding:6px 14px;border-radius:4px;cursor:pointer;font-size:12px;font-family:inherit}',
32
39
  '#__fox-popup button.__fox-cancel:hover{color:#aaa;border-color:#666}',
33
- '#__fox-popup .__fox-hint{font-size:11px;color:#666;margin-top:6px;line-height:1.4}',
34
40
  ].join('\n')
35
41
 
36
42
  var overlay = document.createElement('div')
@@ -83,7 +89,7 @@
83
89
  }
84
90
  var text = (clone.textContent || '').replace(/\s+/g, ' ').trim()
85
91
  return text.slice(0, 500) || null
86
- } catch (e) {
92
+ } catch {
87
93
  return null
88
94
  }
89
95
  }
@@ -124,8 +130,8 @@
124
130
 
125
131
  var left = x + 10
126
132
  var top = y + 10
127
- if (left + 340 > viewportWidth) left = x - 350
128
- if (top + 280 > viewportHeight) top = y - 290
133
+ if (left + 360 > viewportWidth) left = x - 370
134
+ if (top + 320 > viewportHeight) top = y - 330
129
135
  if (left < 8) left = 8
130
136
  if (top < 8) top = 8
131
137
 
@@ -136,6 +142,14 @@
136
142
 
137
143
  var tagDisplay = data.tag + (data.id ? '#' + data.id : data.className ? '.' + data.className.split(' ')[0] : '')
138
144
 
145
+ // Build session options
146
+ var sessionOpts = '<option value="">Select session...</option>'
147
+ for (var i = 0; i < window.__foxSessions.length; i++) {
148
+ var s = window.__foxSessions[i]
149
+ var sel = s.id === window.__foxSelectedSessionId ? ' selected' : ''
150
+ sessionOpts += '<option value="' + s.id + '"' + sel + '>' + (s.title || s.id) + '</option>'
151
+ }
152
+
139
153
  popup.innerHTML =
140
154
  '<div class="__fox-tag">Element: <span>' +
141
155
  tagDisplay +
@@ -143,10 +157,13 @@
143
157
  '<div class="__fox-selector">' +
144
158
  data.xpath +
145
159
  '</div>' +
146
- '<textarea placeholder="What\'s wrong with this element?"></textarea>' +
147
- '<div class="__fox-hint">Sending to: ' +
148
- (window.__foxSessionTitle || window.__foxSessionId || 'none') +
149
- '. To target a different session, close this, navigate to that session in OpenFox, and reopen the inspect window.</div>' +
160
+ '<textarea placeholder="What\'s wrong with this element?" id="__fox-feedback-textarea"></textarea>' +
161
+ '<div class="__fox-session-row">' +
162
+ '<label>Session:</label>' +
163
+ '<select class="__fox-session-picker" id="__fox-popup-session-picker">' +
164
+ sessionOpts +
165
+ '</select>' +
166
+ '</div>' +
150
167
  '<div class="__fox-actions">' +
151
168
  '<button class="__fox-cancel">Cancel</button>' +
152
169
  '<button class="__fox-send">Send to Agent</button>' +
@@ -154,9 +171,18 @@
154
171
 
155
172
  document.body.appendChild(popup)
156
173
 
157
- var textarea = popup.querySelector('textarea')
174
+ var textarea = popup.querySelector('#__fox-feedback-textarea')
175
+ var picker = popup.querySelector('#__fox-popup-session-picker')
158
176
  textarea.focus()
159
177
 
178
+ // Sync picker changes back to global state
179
+ picker.addEventListener('change', function () {
180
+ window.__foxSelectedSessionId = picker.value || null
181
+ try {
182
+ sessionStorage.setItem('__foxSelectedSessionId', picker.value)
183
+ } catch {}
184
+ })
185
+
160
186
  textarea.addEventListener('keydown', function (ke) {
161
187
  if (ke.key === 'Enter' && !ke.shiftKey) {
162
188
  ke.preventDefault()
@@ -175,6 +201,16 @@
175
201
  e.preventDefault()
176
202
  e.stopPropagation()
177
203
  if (window.__foxSentPending) return
204
+
205
+ var sessionId = picker.value
206
+ if (!sessionId) {
207
+ picker.classList.add('__fox-error')
208
+ setTimeout(function () {
209
+ picker.classList.remove('__fox-error')
210
+ }, 2000)
211
+ return
212
+ }
213
+
178
214
  window.__foxSentPending = true
179
215
  setTimeout(function () {
180
216
  window.__foxSentPending = false
@@ -189,7 +225,7 @@
189
225
  method: 'POST',
190
226
  headers: { 'Content-Type': 'application/json' },
191
227
  body: JSON.stringify({
192
- sessionId: window.__foxSessionId,
228
+ sessionId: sessionId,
193
229
  element: data,
194
230
  annotation: annotation,
195
231
  pageUrl: window.location.href,
@@ -255,18 +291,27 @@
255
291
  }
256
292
  })
257
293
 
258
- window.addEventListener('message', function (e) {
259
- if (e.data && e.data.type === 'setFoxSessionId') {
260
- window.__foxSessionId = e.data.sessionId
261
- }
262
- if (e.data && e.data.type === 'setFoxSessionTitle') {
263
- window.__foxSessionTitle = e.data.sessionTitle
264
- }
265
- if (e.data && e.data.type === 'setFoxInspectEnabled') {
266
- window.__foxInspectEnabled = e.data.enabled
267
- overlay.style.display = e.data.enabled ? '' : 'none'
268
- }
269
- })
294
+ function fetchSessions() {
295
+ fetch('/__openfox_sessions')
296
+ .then(function (res) {
297
+ if (!res.ok) throw new Error('Failed to fetch sessions')
298
+ return res.json()
299
+ })
300
+ .then(function (data) {
301
+ window.__foxSessionsError = false
302
+ window.__foxSessions = data.sessions || []
303
+ // Auto-select most recent if none selected
304
+ if (!window.__foxSelectedSessionId && window.__foxSessions.length > 0) {
305
+ window.__foxSelectedSessionId = window.__foxSessions[0].id
306
+ try {
307
+ sessionStorage.setItem('__foxSelectedSessionId', window.__foxSelectedSessionId)
308
+ } catch {}
309
+ }
310
+ })
311
+ .catch(function () {
312
+ window.__foxSessionsError = true
313
+ })
314
+ }
270
315
 
271
316
  function init() {
272
317
  if (window.__foxInspectInit) return
@@ -274,22 +319,24 @@
274
319
  document.head.appendChild(overlayStyle)
275
320
  document.body.appendChild(overlay)
276
321
  toggleBtn = document.getElementById('__fox-toggle')
277
- var widget = document.getElementById('__fox-widget')
278
- widget.addEventListener(
279
- 'mousedown',
280
- function (e) {
281
- e.preventDefault()
282
- e.stopPropagation()
283
- },
284
- true,
285
- )
322
+
323
+ // Restore previously selected session
324
+ try {
325
+ var saved = sessionStorage.getItem('__foxSelectedSessionId')
326
+ if (saved) window.__foxSelectedSessionId = saved
327
+ } catch {}
328
+
286
329
  toggleBtn.addEventListener('click', function (e) {
287
330
  e.preventDefault()
288
331
  e.stopPropagation()
289
332
  if (window.__foxInspectMode) clearHighlights()
290
333
  setInspectMode(!window.__foxInspectMode)
291
334
  })
335
+
292
336
  overlay.style.display = window.__foxInspectEnabled ? '' : 'none'
337
+
338
+ fetchSessions()
339
+ setInterval(fetchSessions, 30000)
293
340
  }
294
341
 
295
342
  if (document.body) {