{"_id":"@doghouse/matomo-form-analytics-custom-field-tracker","_rev":"5-aca91ae8d61e7596a0ec478c1ae5dbf6","name":"@doghouse/matomo-form-analytics-custom-field-tracker","dist-tags":{"latest":"1.0.4"},"versions":{"1.0.0":{"name":"@doghouse/matomo-form-analytics-custom-field-tracker","version":"1.0.0","keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"author":{"url":"https://doghouse.agency","name":"Lemuel Vellez","email":"lemuel@doghouse.agency"},"license":"MIT","_id":"@doghouse/matomo-form-analytics-custom-field-tracker@1.0.0","maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"dist":{"shasum":"31cb4599846ae00b84b20ab0f78573a96a1bd54f","tarball":"https://registry.npmjs.org/@doghouse/matomo-form-analytics-custom-field-tracker/-/matomo-form-analytics-custom-field-tracker-1.0.0.tgz","fileCount":9,"integrity":"sha512-v9sBQ7o+0kLcPLaYflpF2+jhHl/Fsmv8o7x0IsYhjbMxd/xRcA32kB6b8C0KaRjxIWB7icCRbIDptGAZ2lg5KA==","signatures":[{"sig":"MEQCIDP4445WJVRUl9kCA3bH1HUqpwLJwZCHmkiyO7lxLtwtAiB5MoyQ4akMLioZbTk5Afl/CSVbDIqYEvOAra0e5O4RUw==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":157941},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","company":"Doghouse Agency (https://doghouse.agency)","engines":{"node":">=14.0.0"},"gitHead":"e1dc053cc80e46bf65b4fb6db5610494c6090e23","scripts":{"dev":"rollup -c -w","lint":"eslint src/**/*.js","test":"jest","build":"rollup -c","clean":"rimraf dist","lint:fix":"eslint src/**/*.js --fix","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},"repository":{"url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git","type":"git"},"_npmVersion":"8.19.4","description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","directories":{},"_nodeVersion":"16.20.2","browserslist":["> 1%","last 2 versions","not dead"],"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.52.0","rimraf":"^5.0.5","rollup":"^3.29.4","@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^29.7.0","@rollup/plugin-node-resolve":"^15.2.1"},"_npmOperationalInternal":{"tmp":"tmp/matomo-form-analytics-custom-field-tracker_1.0.0_1761271644831_0.4990065756693012","host":"s3://npm-registry-packages-npm-production"}},"1.0.1":{"name":"@doghouse/matomo-form-analytics-custom-field-tracker","version":"1.0.1","keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"author":{"url":"https://doghouse.agency","name":"Lemuel Vellez","email":"lemuel@doghouse.agency"},"license":"MIT","_id":"@doghouse/matomo-form-analytics-custom-field-tracker@1.0.1","maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"dist":{"shasum":"a85b4bdeeef6bcbafbb46213adc6201f8f4ee01c","tarball":"https://registry.npmjs.org/@doghouse/matomo-form-analytics-custom-field-tracker/-/matomo-form-analytics-custom-field-tracker-1.0.1.tgz","fileCount":9,"integrity":"sha512-1sbu85Ga42/bSE801+I/ZnSZFtpYdVIBltbqCwBZy+Wnc5ayp3LCO5O0715zePfuUn05Cbgf69FeKeAWNDv6Eg==","signatures":[{"sig":"MEUCIG232CAqFPLE64yMSY0q3isToHv1euy6bJ0oe2bvxmROAiEAsjvIPYvEeEK9Q+wKwOHVxE+3CbCEIvCFqpO4dLgzu7I=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":182327},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","company":"Doghouse Agency (https://doghouse.agency)","engines":{"node":">=14.0.0"},"gitHead":"0dca6efce5ba772af28b205f18be5dae721e4f9a","scripts":{"dev":"rollup -c -w","lint":"eslint src/**/*.js","test":"jest","build":"rollup -c","clean":"rimraf dist","lint:fix":"eslint src/**/*.js --fix","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},"repository":{"url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git","type":"git"},"_npmVersion":"8.19.4","description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","directories":{},"_nodeVersion":"16.20.2","browserslist":["> 1%","last 2 versions","not dead"],"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.52.0","rimraf":"^5.0.5","rollup":"^3.29.4","@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^29.7.0","@rollup/plugin-node-resolve":"^15.2.1"},"_npmOperationalInternal":{"tmp":"tmp/matomo-form-analytics-custom-field-tracker_1.0.1_1761303312244_0.5562772662595004","host":"s3://npm-registry-packages-npm-production"}},"1.0.2":{"name":"@doghouse/matomo-form-analytics-custom-field-tracker","version":"1.0.2","keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"author":{"url":"https://doghouse.agency","name":"Lemuel Vellez","email":"lemuel@doghouse.agency"},"license":"MIT","_id":"@doghouse/matomo-form-analytics-custom-field-tracker@1.0.2","maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"dist":{"shasum":"872e8444e88add72136ca3c51fb13d7b9c3b1a40","tarball":"https://registry.npmjs.org/@doghouse/matomo-form-analytics-custom-field-tracker/-/matomo-form-analytics-custom-field-tracker-1.0.2.tgz","fileCount":9,"integrity":"sha512-y6yKmbPd4EC68TgUSyJcW8hHIbpcnyIHu/IU4DCSMLlJfRC4G2ShUiljfac7BH4F3Ve297al3/Ru6M1azkz9Nw==","signatures":[{"sig":"MEUCIQDUup/Deo6mIY+6DFQnq/MGf8e3i2DegW0g9++TvVK3iAIgGDuR5Ubtczd+RP+7kyhZ3VHNSIUsJdIh35QCpmC/S00=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":228640},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","company":"Doghouse Agency (https://doghouse.agency)","engines":{"node":">=14.0.0"},"gitHead":"1d932488ddad1cc416813b72a69609e866be4c45","scripts":{"dev":"rollup -c -w","lint":"eslint src/**/*.js","test":"jest","build":"rollup -c","clean":"rimraf dist","lint:fix":"eslint src/**/*.js --fix","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},"repository":{"url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git","type":"git"},"_npmVersion":"8.19.4","description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","directories":{},"_nodeVersion":"16.20.2","browserslist":["> 1%","last 2 versions","not dead"],"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.52.0","rimraf":"^5.0.5","rollup":"^3.29.4","@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^29.7.0","@rollup/plugin-node-resolve":"^15.2.1"},"_npmOperationalInternal":{"tmp":"tmp/matomo-form-analytics-custom-field-tracker_1.0.2_1763016366045_0.8853359318008966","host":"s3://npm-registry-packages-npm-production"}},"1.0.3":{"name":"@doghouse/matomo-form-analytics-custom-field-tracker","version":"1.0.3","keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"author":{"url":"https://doghouse.agency","name":"Lemuel Vellez","email":"lemuel@doghouse.agency"},"license":"MIT","_id":"@doghouse/matomo-form-analytics-custom-field-tracker@1.0.3","maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"dist":{"shasum":"8cd3c47b07b907e6b15890f7d1b6dd6ddaf34b5d","tarball":"https://registry.npmjs.org/@doghouse/matomo-form-analytics-custom-field-tracker/-/matomo-form-analytics-custom-field-tracker-1.0.3.tgz","fileCount":9,"integrity":"sha512-ulJMeiTcKUW7ELXMwecDr0Td/v5LEKuMgqg9g6laODyfWBsCh2VxHzYfxylmWAtcKpWUBxeb5ISlIgeirTTYUg==","signatures":[{"sig":"MEUCIQC7G2oWBGlbZOMAoEESRy5tsb7ziUCQ2ayoiDmcNeuS5AIgGWh2z2cPBat6BstJzY+v+SmoYcktyrsRpVzr2oTaga0=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":235725},"main":"dist/index.js","types":"dist/index.d.ts","module":"dist/index.esm.js","company":"Doghouse Agency (https://doghouse.agency)","engines":{"node":">=14.0.0"},"gitHead":"5fd762c54c22f3df08b1d6b4a5cc920a77013a1f","scripts":{"dev":"rollup -c -w","lint":"eslint src/**/*.js","test":"jest","build":"rollup -c","clean":"rimraf dist","lint:fix":"eslint src/**/*.js --fix","test:watch":"jest --watch","prepublishOnly":"npm run build"},"_npmUser":{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},"repository":{"url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git","type":"git"},"_npmVersion":"8.19.4","description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","directories":{},"_nodeVersion":"16.20.2","browserslist":["> 1%","last 2 versions","not dead"],"_hasShrinkwrap":false,"devDependencies":{"jest":"^29.7.0","eslint":"^8.52.0","rimraf":"^5.0.5","rollup":"^3.29.4","@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-terser":"^0.4.4","jest-environment-jsdom":"^29.7.0","@rollup/plugin-node-resolve":"^15.2.1"},"_npmOperationalInternal":{"tmp":"tmp/matomo-form-analytics-custom-field-tracker_1.0.3_1763021551881_0.344656587030697","host":"s3://npm-registry-packages-npm-production"}},"1.0.4":{"name":"@doghouse/matomo-form-analytics-custom-field-tracker","version":"1.0.4","description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","main":"dist/index.js","module":"dist/index.esm.js","types":"dist/index.d.ts","scripts":{"build":"rollup -c","dev":"rollup -c -w","test":"jest","test:watch":"jest --watch","lint":"eslint src/**/*.js","lint:fix":"eslint src/**/*.js --fix","prepublishOnly":"npm run build","clean":"rimraf dist"},"keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"author":{"name":"Lemuel Vellez","email":"lemuel@doghouse.agency","url":"https://doghouse.agency"},"company":"Doghouse Agency (https://doghouse.agency)","license":"MIT","repository":{"type":"git","url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git"},"bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","devDependencies":{"@babel/core":"^7.23.0","@babel/preset-env":"^7.23.0","@rollup/plugin-babel":"^6.0.4","@rollup/plugin-node-resolve":"^15.2.1","@rollup/plugin-terser":"^0.4.4","eslint":"^8.52.0","jest":"^29.7.0","jest-environment-jsdom":"^29.7.0","rimraf":"^5.0.5","rollup":"^3.29.4"},"engines":{"node":">=14.0.0"},"browserslist":["> 1%","last 2 versions","not dead"],"gitHead":"1dce55f9bddd144f449305f178350de11bae3fd2","_id":"@doghouse/matomo-form-analytics-custom-field-tracker@1.0.4","_nodeVersion":"16.20.2","_npmVersion":"8.19.4","dist":{"integrity":"sha512-ggFOtQ6PswYIPW66tHhscyq4WGG0rEp8A6Jrg5vSbg35XXONT+A2k9kl1kNU+iCNj8mShpw5kXV8v+sN5uqxvg==","shasum":"a1922fc13c53931f240d7e7431611a06add21dc4","tarball":"https://registry.npmjs.org/@doghouse/matomo-form-analytics-custom-field-tracker/-/matomo-form-analytics-custom-field-tracker-1.0.4.tgz","fileCount":9,"unpackedSize":248074,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEUCIBgaGGyJxd5C+pWAuPZEhi7xVIiSR0JaQwByXggpGE8DAiEA+MdwbtdbBK227Ko9Tv1PV9/1KpuWNHMzuwX7L87LhgM="}]},"_npmUser":{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},"directories":{},"maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/matomo-form-analytics-custom-field-tracker_1.0.4_1763085178437_0.04733246739925723"},"_hasShrinkwrap":false}},"time":{"created":"2025-10-24T02:07:24.724Z","modified":"2025-11-14T01:52:58.878Z","1.0.0":"2025-10-24T02:07:25.023Z","1.0.1":"2025-10-24T10:55:12.438Z","1.0.2":"2025-11-13T06:46:06.246Z","1.0.3":"2025-11-13T08:12:32.080Z","1.0.4":"2025-11-14T01:52:58.626Z"},"bugs":{"url":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues"},"author":{"name":"Lemuel Vellez","email":"lemuel@doghouse.agency","url":"https://doghouse.agency"},"license":"MIT","homepage":"https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker#readme","keywords":["matomo","form-analytics","tracking","custom-fields","wysiwyg","rating","image-selector","form-tracking","analytics"],"repository":{"type":"git","url":"git+https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker.git"},"description":"A modular, object-oriented system for creating custom field trackers that integrate with Matomo FormAnalytics","maintainers":[{"name":"lemuel.vellez","email":"lemuel@doghouse.agency"},{"name":"jez500","email":"mail@jez500.com"},{"name":"cbradshaw","email":"carl@doghouse.agency"},{"name":"thomas.hery","email":"thery@doghouse.agency"}],"readme":"# Matomo Form Analytics Custom Field Tracker\n\n[![npm version](https://badge.fury.io/js/matomo-form-analytics-custom-field-tracker.svg)](https://badge.fury.io/js/matomo-form-analytics-custom-field-tracker)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![GitHub stars](https://img.shields.io/github/stars/DoghouseMedia/matomo-form-analytics-custom-field-tracker.svg)](https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/stargazers)\n[![GitHub issues](https://img.shields.io/github/issues/DoghouseMedia/matomo-form-analytics-custom-field-tracker.svg)](https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues)\n\nA modular, object-oriented npm package for creating custom field trackers that integrate with Matomo FormAnalytics. Built with **inheritance patterns** and **centralized factory design**.\n\n## 🎯 What This Package Does\n\nThis package extends Matomo FormAnalytics to track custom form fields that aren't natively supported, such as:\n- **WYSIWYG editors** (ProseMirror, TinyMCE, etc.)\n- **Star rating systems**\n- **Image selection interfaces**\n- **Custom buttons and interactive elements**\n- **Any custom interactive form elements**\n\n## ✨ Key Features\n\n- 🔧 **Modular Architecture** - Easy to extend with new field types\n- 🎯 **Object-Oriented Design** - Clean inheritance patterns\n- 📊 **Full Matomo Integration** - Compatible with FormAnalytics API\n- 🚀 **Multiple Build Formats** - ESM, CommonJS, and UMD support\n- 📝 **TypeScript Support** - Complete type definitions included\n- 🧪 **Comprehensive Testing** - Jest test suite with coverage\n- 📚 **Well Documented** - Extensive examples and API reference\n- 🐛 **Debug Support** - Built-in debug logging for development\n- 📦 **Sample Implementations** - Reference examples for common field types\n- 🧹 **Automatic Cleanup** - Memory leak prevention with tracked event listeners and timers\n- 🔄 **Dynamic Field Detection** - Automatic support for conditional fields and paginated forms\n\n## 🚀 Installation\n\n```bash\nnpm install @doghouse/matomo-form-analytics-custom-field-tracker\n```\n\n## 📦 Usage\n\n### Creating Custom Fields\n\nTo track custom form fields, you need to create a field class that extends `BaseField`. Here's how:\n\n#### 1. Create Your Custom Field Class\n\nCreate a new file for your custom field (e.g., `MyCustomField.js`):\n\n```javascript\nimport { BaseField } from '@doghouse/matomo-form-analytics-custom-field-tracker';\n\nexport class H2ClickField extends BaseField {\n  static fieldType = 'h2Click';\n  static category = BaseField.BaseField.FieldCategories.SELECTABLE;\n  static selector = '.survey-full__intro[data-name]';\n  \n  constructor(tracker, element, fieldName) {\n    super(tracker, element, fieldName);\n    this.h2Element = this.getInteractiveElement();\n    this.clickCount = 0;\n  }\n  \n  getInteractiveElement() {\n    return this.element.querySelector('h2');\n  }\n  \n  isBlank() {\n    return this.clickCount === 0;\n  }\n  \n  getFieldSize() {\n    return this.clickCount;\n  }\n  \n  setupEventListeners() {\n    if (!this.h2Element) return;\n    \n    this._addTrackedEventListener(this.h2Element, 'click', () => {\n      this.onFocus();\n      this.clickCount++;\n      this.onChange();\n      this._trackTimer(setTimeout(() => this.onBlur(), 100));\n    });\n  }\n}\n```\n\n#### Required Static Properties\n\nEvery custom field **must** define these three static properties:\n\n```javascript\nexport class H2ClickField extends BaseField {\n  static fieldType = 'h2Click';                    // Unique identifier\n  static category = BaseField.FieldCategories.SELECTABLE;  // Field category\n  static selector = '.survey-full__intro[data-name]';       // CSS selector\n  // ... rest of implementation\n}\n```\n\n**Property explanations:**\n- **`static fieldType`** - Unique identifier for your field type (e.g., `'h2Click'`, `'rating'`, `'wysiwyg'`). Used internally to identify and register your field type. Must be unique across all your custom fields.\n- **`static category`** - Field category from `BaseField.FieldCategories` enum (`TEXT`, `SELECTABLE`, or `CHECKABLE`). Tells Matomo how to categorize this field for analytics. Choose from `TEXT` (text input), `SELECTABLE` (dropdowns, ratings), or `CHECKABLE` (checkboxes, image selectors).\n- **`static selector`** - CSS selector to find elements on the page (e.g., `'.survey-full__intro[data-name]'`). CSS selector that finds the DOM elements this field should track. Should target elements with `data-name` attributes for proper field identification.\n\n#### Required Overrides\n\nEvery custom field **must** implement these three abstract methods:\n\n- **`getInteractiveElement()`** - Returns the DOM element that users interact with. This is the actual clickable/typeable element inside your field container. For example, in a WYSIWYG editor, this would be the contenteditable div, not the outer wrapper.\n- **`isBlank()`** - Determines if the field is empty/unused. Returns `true` if the field has no content or user input. Used by Matomo to track completion rates and identify abandoned fields.\n- **`getFieldSize()`** - Returns the field's content size/value. This could be character count for text fields, number of selected items for multi-selects, or rating value for star ratings. Used by Matomo to analyze field complexity and user engagement.\n\n#### Optional Overrides\n\n- **`setupEventListeners()`** - Override this when you need custom event handling beyond the default focus/blur/change events\n\n#### Memory Management & Cleanup\n\nThe BaseField class includes automatic memory leak prevention through tracked event listeners, timers, and MutationObservers:\n\n- **`_addTrackedEventListener(element, event, handler, options)`** - Use this instead of `addEventListener()` to automatically track listeners for cleanup\n- **`_trackTimer(timerId)`** - Use this to wrap `setTimeout()` or `setInterval()` calls for automatic cleanup\n- **`_trackMutationObserver(observer)`** - Use this to track `MutationObserver` instances for automatic cleanup\n- **`_setupTrackedMutationObserver(callback, observeOptions, targetElement)`** - Convenient helper to create, track, and observe with a MutationObserver (handles disconnecting existing observer if called multiple times)\n- **`destroy()`** - Automatically removes all tracked event listeners, clears all timers, and disconnects all MutationObservers\n\n**Example with proper cleanup:**\n```javascript\nsetupEventListeners() {\n  if (!this.h2Element) return;\n  \n  // Use tracked event listener (automatically cleaned up)\n  this._addTrackedEventListener(this.h2Element, 'click', () => {\n    this.onFocus();\n    this.clickCount++;\n    this.onChange();\n    // Use tracked timer (automatically cleaned up)\n    this._trackTimer(setTimeout(() => this.onBlur(), 100));\n  });\n}\n\nsetupMutationObserver() {\n  const container = this.element.querySelector('.container');\n  if (!container) return;\n  \n  // Option 1: Use _setupTrackedMutationObserver helper (recommended for single observer)\n  this._setupTrackedMutationObserver(\n    () => this.checkStateChanges(),\n    {\n      attributes: true,\n      attributeFilter: ['class'],\n      childList: true,\n      subtree: true,\n    },\n    container\n  );\n  \n  // Option 2: Manual setup with _trackMutationObserver (for multiple observers)\n  // const observer = this._trackMutationObserver(new MutationObserver(() => {\n  //   this.checkStateChanges();\n  // }));\n  // observer.observe(container, { attributes: true, childList: true, subtree: true });\n}\n```\n\n**Benefits:**\n- ✅ Automatic cleanup prevents memory leaks\n- ✅ Idempotent (safe to call `destroy()` multiple times)\n- ✅ No orphaned event listeners, timers, or MutationObservers\n- ✅ Consistent cleanup pattern across all field types\n\n#### Debug Logging\n\nWhen implementing custom logic, use conditional debug logging:\n\n```javascript\nsetupEventListeners() {\n  if (!this.h2Element) {\n    this.debug && console.log('H2 element not found');\n    return;\n  }\n  \n  this._addTrackedEventListener(this.h2Element, 'click', () => {\n    this.debug && console.log(`H2 clicked: ${this.fieldName}`);\n    this.onFocus();\n    this.clickCount++;\n    this.onChange();\n    this._trackTimer(setTimeout(() => this.onBlur(), 100));\n  });\n}\n```\n\n**Important:** Always use `this.debug && console.log(...)` for debug output to respect the global debug setting.\n\n#### 2. Initialize the Tracker\n\nAfter creating your custom field classes, initialize the tracker:\n\n```javascript\nimport FormAnalyticsCustomFieldTracker from '@doghouse/matomo-form-analytics-custom-field-tracker';\nimport { H2ClickField } from './SampleCustom/H2ClickField.js';\nimport { RatingField } from './SampleCustom/RatingField.js';\nimport { WysiwygField } from './SampleCustom/WysiwygField.js';\nimport { ImageSelectorField } from './SampleCustom/ImageSelectorField.js';\n\n// Initialize custom field tracking for unsupported field types\nFormAnalyticsCustomFieldTracker.init([\n    { fieldType: 'h2Click', FieldClass: H2ClickField },\n    { fieldType: 'rating', FieldClass: RatingField },\n    { fieldType: 'wysiwyg', FieldClass: WysiwygField },\n    { fieldType: 'imageSelector', FieldClass: ImageSelectorField },\n], true); // Enable debug logging\n```\n\n### Debug Mode\n\nEnable debug logging to see detailed information about field tracking. Debug mode is controlled globally and affects all field instances:\n\n```javascript\n// Enable debug logging\nFormAnalyticsCustomFieldTracker.init(customFields, true);\n\n// Disable debug logging (default)\nFormAnalyticsCustomFieldTracker.init(customFields, false);\n```\n\nWhen debug mode is enabled, you'll see console messages like:\n- `✅ Integrated custom rating field: cmF0aW5nOjIwMjUtMTAtMjBUMDE6MzA6MzUuOTUzWg==`\n- `⚡️ WYSIWYG focus (wysiwyg-field)`\n- `⚡️ RATING changed from 3 to 4 (rating-field)`\n- `⚡️ BUTTON click (button-field)`\n\nDebug output includes:\n- Form detection and processing\n- Field type matching and integration\n- User interactions (focus, blur, change)\n- Error messages and warnings\n\n### Conditional Fields & Paginated Forms\n\nThe tracker automatically supports **conditional fields** and **paginated forms** through dynamic field detection.\n\n#### Conditional Fields\n\n**Conditional fields** are hidden fields that appear dynamically based on another field's value. For example, if a user selects \"Yes\" to a question, additional fields may appear that weren't visible initially.\n\nThe tracker uses a `MutationObserver` to automatically detect when new fields are added to the form and integrates them seamlessly:\n\n```javascript\n// Example: A conditional field appears when user selects an option\n// The tracker automatically detects and starts tracking it\nFormAnalyticsCustomFieldTracker.init([\n    { fieldType: 'rating', FieldClass: RatingField },\n    { fieldType: 'wysiwyg', FieldClass: WysiwygField },\n], true);\n\n// When a conditional field appears (e.g., after selecting \"Yes\"),\n// it's automatically detected and tracked without any additional code\n```\n\n**How it works:**\n- The tracker monitors the form for DOM changes\n- When new fields matching your custom field selectors are added, they're automatically detected\n- Both native Matomo fields and custom fields are re-scanned\n- Fields are only tracked once (duplicate detection prevents double-tracking)\n\n#### Paginated Forms\n\n**Paginated forms** are multi-step forms where fields are added to the DOM as users navigate through pages. The tracker handles this automatically:\n\n```javascript\n// Works seamlessly with multi-step/paginated forms\nFormAnalyticsCustomFieldTracker.init([\n    { fieldType: 'rating', FieldClass: RatingField },\n    { fieldType: 'wysiwyg', FieldClass: WysiwygField },\n], true);\n\n// As users navigate to page 2, 3, etc., new fields are automatically detected\n```\n\n**Features:**\n- ✅ Automatic detection of fields added on new pages\n- ✅ Debounced re-scanning (300ms) to handle rapid changes efficiently\n- ✅ Works with both native Matomo fields and custom fields\n- ✅ No additional configuration needed\n\n**Debug output for dynamic fields:**\nWhen debug mode is enabled, you'll see messages like:\n- `📄 New fields detected (pagination/conditional), re-scanning...`\n- `🔄 Re-scanned native tracker for new fields`\n- `👀 Set up dynamic field observer for pagination/conditional fields`\n- `✅ Integrated custom rating field: field-name` (for newly detected fields)\n\n**Technical details:**\n- Uses `MutationObserver` API to watch for DOM changes\n- Observes the entire form subtree for added nodes\n- Detects standard form fields (`input`, `select`, `textarea`) and custom field containers\n- Debounces re-scanning to optimize performance\n- Prevents duplicate tracking by checking if fields are already tracked\n\n## 📁 Project Structure\n\n```\nsrc/\n├── BaseField.js                    # Base class for custom fields\n├── FormAnalyticsCustomFieldTracker.js  # Main tracker with field management\n├── Enums/\n│   └── FieldCategories.js         # Field category definitions\n├── examples/                      # Example implementations\n│   ├── SampleWysiwygField.js\n│   ├── SampleButtonClickField.js\n│   ├── SampleRatingField.js\n│   └── index.js\n└── index.js                       # Main exports\n```\n\n## 🎯 Field Categories\n\nMatomo FormAnalytics supports three field categories:\n\n| Category | Description | Examples |\n|----------|-------------|----------|\n| **TEXT** | Text-based input fields | `password`, `text`, `url`, `tel`, `email`, `search`, `textarea` |\n| **SELECTABLE** | Selection-based fields | `color`, `date`, `datetime`, `datetime-local`, `month`, `number`, `range`, `time`, `week`, `select` |\n| **CHECKABLE** | Checkbox/radio fields | `radio`, `checkbox` |\n\n## 📚 Sample Implementations\n\nThe package includes sample implementations in the `examples/` folder that demonstrate proper usage of the cleanup functionality:\n\n### SampleWysiwygField\n- **Category**: TEXT\n- **Purpose**: Handles rich text editing with ProseMirror editor\n- **Selector**: `.formulate-input-element--wysiwyg[data-name]`\n- **Cleanup**: Uses default BaseField event listeners (automatically tracked)\n\n### SampleButtonClickField\n- **Category**: SELECTABLE\n- **Purpose**: Tracks button clicks and counts them as field interactions\n- **Selector**: `.custom-button[data-name]`\n- **Cleanup**: Uses `_addTrackedEventListener()` and `_trackTimer()` for proper cleanup\n\n### SampleRatingField\n- **Category**: SELECTABLE\n- **Purpose**: Handles star rating elements with click-based selection\n- **Selector**: `.formulate-input-element--rating-container[data-name]`\n- **Cleanup**: Uses `_addTrackedEventListener()` and `_trackTimer()` for proper cleanup\n\nAll sample implementations now include proper memory management and cleanup patterns that prevent memory leaks.\n\n## 🚀 Build Formats\n\n### ES Modules\n```javascript\nimport FormAnalyticsCustomFieldTracker from '@doghouse/matomo-form-analytics-custom-field-tracker';\n```\n\n### CommonJS\n```javascript\nconst FormAnalyticsCustomFieldTracker = require('@doghouse/matomo-form-analytics-custom-field-tracker');\n```\n\n### Browser (UMD)\n```html\n<script src=\"https://unpkg.com/@doghouse/matomo-form-analytics-custom-field-tracker/dist/index.umd.js\"></script>\n<script>\n  MatomoFormAnalyticsCustomFieldTracker.init();\n</script>\n```\n\n## 🧪 Testing\n\n```bash\n# Run tests\nnpm test\n\n# Run tests with coverage\nnpm run test:coverage\n\n# Run tests in watch mode\nnpm run test:watch\n```\n\n## 📦 Building\n\n```bash\n# Build all formats\nnpm run build\n\n# Build specific format\nnpm run build:esm\nnpm run build:cjs\nnpm run build:umd\n```\n\n## 🤝 Contributing\n\n1. Fork the repository\n2. Create a feature branch: `git checkout -b feature-name`\n3. Make your changes\n4. Add tests for new functionality\n5. Run tests: `npm test`\n6. Commit your changes: `git commit -am 'Add feature'`\n7. Push to the branch: `git push origin feature-name`\n8. Submit a pull request\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- Built for Matomo FormAnalytics integration\n- Inspired by modern JavaScript patterns and best practices\n- Community feedback and contributions\n\n## 📞 Support\n\n- 📧 Email: support@doghouse.agency \n- 🐛 Issues: [GitHub Issues](https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/issues)\n- 📖 Documentation: [GitHub Wiki](https://github.com/DoghouseMedia/matomo-form-analytics-custom-field-tracker/wiki)\n\n---\n\n**Made with ❤️ by [Doghouse Agency](https://doghouse.agency/)**","readmeFilename":"README.md"}