helper.js 2.4 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697
  1. (function() {
  2. const WS_URL = 'ws://' + window.location.host;
  3. let ws = null;
  4. let eventQueue = [];
  5. function connect() {
  6. ws = new WebSocket(WS_URL);
  7. ws.onopen = () => {
  8. // Send any queued events
  9. eventQueue.forEach(e => ws.send(JSON.stringify(e)));
  10. eventQueue = [];
  11. };
  12. ws.onmessage = (msg) => {
  13. const data = JSON.parse(msg.data);
  14. if (data.type === 'reload') {
  15. window.location.reload();
  16. }
  17. };
  18. ws.onclose = () => {
  19. // Reconnect after 1 second
  20. setTimeout(connect, 1000);
  21. };
  22. }
  23. function send(event) {
  24. event.timestamp = Date.now();
  25. if (ws && ws.readyState === WebSocket.OPEN) {
  26. ws.send(JSON.stringify(event));
  27. } else {
  28. eventQueue.push(event);
  29. }
  30. }
  31. // Auto-capture clicks on interactive elements
  32. document.addEventListener('click', (e) => {
  33. const target = e.target.closest('button, a, [data-choice], [role="button"], input[type="submit"]');
  34. if (!target) return;
  35. // Don't capture regular link navigation
  36. if (target.tagName === 'A' && !target.dataset.choice) return;
  37. e.preventDefault();
  38. send({
  39. type: 'click',
  40. text: target.textContent.trim(),
  41. choice: target.dataset.choice || null,
  42. id: target.id || null,
  43. className: target.className || null
  44. });
  45. });
  46. // Auto-capture form submissions
  47. document.addEventListener('submit', (e) => {
  48. e.preventDefault();
  49. const form = e.target;
  50. const formData = new FormData(form);
  51. const data = {};
  52. formData.forEach((value, key) => { data[key] = value; });
  53. send({
  54. type: 'submit',
  55. formId: form.id || null,
  56. formName: form.name || null,
  57. data: data
  58. });
  59. });
  60. // Auto-capture input changes (debounced)
  61. let inputTimeout = null;
  62. document.addEventListener('input', (e) => {
  63. const target = e.target;
  64. if (!target.matches('input, textarea, select')) return;
  65. clearTimeout(inputTimeout);
  66. inputTimeout = setTimeout(() => {
  67. send({
  68. type: 'input',
  69. name: target.name || null,
  70. id: target.id || null,
  71. value: target.value,
  72. inputType: target.type || target.tagName.toLowerCase()
  73. });
  74. }, 500); // 500ms debounce
  75. });
  76. // Expose for explicit use if needed
  77. window.brainstorm = {
  78. send: send,
  79. choice: (value, metadata = {}) => send({ type: 'choice', value, ...metadata })
  80. };
  81. connect();
  82. })();