{"id":17042141,"url":"https://github.com/bluem/form-change-tracker","last_synced_at":"2026-01-20T03:02:39.754Z","repository":{"id":57240247,"uuid":"94967128","full_name":"BlueM/form-change-tracker","owner":"BlueM","description":"Tracks pristine/dirty state of in-browser form controls","archived":false,"fork":false,"pushed_at":"2021-06-27T05:16:27.000Z","size":44,"stargazers_count":2,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-05T22:19:01.716Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/BlueM.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-21T05:42:47.000Z","updated_at":"2021-06-27T05:16:14.000Z","dependencies_parsed_at":"2022-08-29T21:24:13.215Z","dependency_job_id":null,"html_url":"https://github.com/BlueM/form-change-tracker","commit_stats":null,"previous_names":[],"tags_count":6,"template":false,"template_full_name":null,"purl":"pkg:github/BlueM/form-change-tracker","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueM%2Fform-change-tracker","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueM%2Fform-change-tracker/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueM%2Fform-change-tracker/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueM%2Fform-change-tracker/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/BlueM","download_url":"https://codeload.github.com/BlueM/form-change-tracker/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/BlueM%2Fform-change-tracker/sbom","scorecard":{"id":23116,"data":{"date":"2025-08-11","repo":{"name":"github.com/BlueM/form-change-tracker","commit":"cea9d06e6e776ce7ff0a475d6145ed4f9ab56a37"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":2.6,"checks":[{"name":"SAST","score":0,"reason":"no SAST tool detected","details":["Warn: no pull requests merged into dev branch"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}},{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Pinned-Dependencies","score":-1,"reason":"no dependencies found","details":null,"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"Token-Permissions","score":-1,"reason":"No tokens found","details":null,"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Code-Review","score":0,"reason":"Found 0/30 approved changesets -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Dangerous-Workflow","score":-1,"reason":"no workflows found","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":0,"reason":"license file not detected","details":["Warn: project does not have a license file"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":0,"reason":"branch protection not enabled on development/release branches","details":["Warn: branch protection not enabled for branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}}]},"last_synced_at":"2025-08-14T17:15:18.012Z","repository_id":57240247,"created_at":"2025-08-14T17:15:18.012Z","updated_at":"2025-08-14T17:15:18.012Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28594958,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T02:08:49.799Z","status":"ssl_error","status_checked_at":"2026-01-20T02:08:44.148Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-14T09:15:14.577Z","updated_at":"2026-01-20T03:02:39.739Z","avatar_url":"https://github.com/BlueM.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Overview\r\n\r\n`form-change-tracker` is a small (roughly 3 kB gzipped including its only dependency) JavaScript browser library for keeping track of the state (pristine vs. changed) of controls in a DOM-based form.\r\n\r\nUsing this state (i.e.: via CSS class names added or removed from controls and their associated `\u003clabel\u003e` elements), you can provide visual feedback regarding which controls have changed and which have not. Of course, it will detect if an element is first changed and then changed back to its initial value. Additionally, `form-change-tracker` automatically manages disabling or enabling a reset button, if there is one in the form, and will call a callback, if you like.\r\n\r\nThis library is probably not what you need in a project where you already are using some SPA framework (React, Angular, Vue or the like), but is a nice addition for “classical” mainly server-side rendered applications.\r\n\r\nThis Library on npm: https://www.npmjs.com/package/@bluem/form-change-tracker\r\n\r\n## Browser support\r\n\r\nThis library will work (at least) on:\r\n\r\n* Google Chrome Desktop and Android (no particularly new version required)\r\n* Firefox Desktop and Android (no particularly new version required)\r\n* Safari Desktop and iOS (no particularly new version required)\r\n* Microsoft Edge (no particularly new version required)\r\n* Microsoft IE11\r\n\r\n\r\n# How to set up and use\r\n\r\n## Installation\r\n\r\nDepending on your favorite package manager, run either of:\r\n* `npm install @bluem/form-change-tracker`\r\n* `yarn add @bluem/form-change-tracker`\r\n\r\n## Importing\r\n\r\nThe library is an ES6 class, so the way to use it depends on your tooling and the browsers you want to support.\r\n\r\n### With Webpack\r\nFirst, write your code using an ES6 import:\r\n\r\n    import FormChangeTracker from '@bluem/form-change-tracker';\r\n\r\nThen, assuming you have Webpack installed locally in your project:\r\n\r\n`./node_modules/.bin/webpack -p demo.js --output dist/webpack-bundle.js`\r\n\r\nThen, add `\u003cscript src=\"dist/webpack-bundle.js\"\u003e\u003c/script\u003e` to your HTML.\r\n\r\nThe above command would be sufficient, but of course, you can use a `webpack.config.js` configuration file.\r\n\r\n\r\n### With Parcel\r\nFirst, write your code using an ES6 import:\r\n\r\n    import FormChangeTracker from '@bluem/form-change-tracker';\r\n\r\nThen, assuming you have Parcel installed locally in your project:\r\n\r\n`./node_modules/.bin/parcel build --public-url /dist demo.js` \r\n\r\nThis will write generated files to directory “dist” in the working directory.\r\n\r\n\r\n## Usage\r\n\r\nThe most simple invocation is:\r\n\r\n```js\r\nnew FormChangeTracker();\r\n```\r\nThis will invoke `FormChangeTracker` with the default options, which is equivalent to …\r\n\r\n```js\r\nnew FormChangeTracker({\r\n  selector: 'form',\r\n  classname: 'control-changed',\r\n  confirm: function (callback) {\r\n    if (confirm('Are you sure you want to reset the form and lose unsaved changes?')) {\r\n      callback();\r\n    }\r\n  }\r\n});\r\n```\r\n\r\nThe options are:\r\n\r\n* `selector`: A CSS selector (compatible with `document.querySelector`). The first element that matches is used.\r\n* `element`: Instead of a selector, you can directly pass an element (which must be a `\u003cform\u003e` element)\r\n* `classname`: A CSS class name to add to both the control and the corresponding label\r\n* `callback`: A function which will be called when an control’s state changes. The function will be given two arguments: first, the control, second a Boolean indicating if the control is now in a dirty/changed state or not.\r\n* `confirm`: A confirmation function which will be invoked if the reset button (if there is one in the form) is clicked and the form is dirty. This must be a function which is expected to take a function as argument, which should be invoked if the user confirms.\r\n\r\nThe `confirm` property is built this way to make it easy to use some external function or library for this. For instance, this would be the code for integrating SweetAlert:\r\n\r\n```js\r\nnew FormChangeTracker({\r\n  confirm: function(confirmationCallback) {\r\n    swal({\r\n        title: \"Are you sure?\",\r\n        text: \"Your unsaved changes will be lost.\",\r\n        type: \"warning\",\r\n        showCancelButton: true,\r\n        confirmButtonColor: \"#DD6B55\",\r\n        confirmButtonText: \"Go ahead\",\r\n        closeOnConfirm: true\r\n      },\r\n      function () {\r\n        console.info('Reset');\r\n        confirmationCallback();\r\n      });\r\n  }\r\n});\r\n```\r\n\r\n\r\n# Tests\r\nAs the library is simple, highly browser-oriented and easy to test manually, I chose to remove the tests I had for the 0.* versions. Which means that there are no automated tests of any kind.\r\n\r\n\r\n# License\r\n[MIT License](https://spdx.org/licenses/MIT.html)\r\n\r\n# Version History\r\n\r\n## 1.2 (2019-08-31)\r\n- Gracefully handle a non-matching selector passed as option, as this seems more appropriate in typical usage scenarios. (Note: in the unlikely case that client code relied on passing in a non-matching selector and expect the library to throw an error, this is a breaking change.)\r\n- Fix module loading\r\n\r\n## 1.1 (2019-08-25)\r\n- Replace code for getting controls’ event names with npm module `@bluem/form-control-event-name`\r\n- Fix bug regarding missing quoting of radiobutton attributes\r\n\r\n## 1.0 (2018-11-03)\r\n- Migrate to a native ES6 class\r\n- Add option `callback`\r\n- Remove tests\r\n- Improve Readme\r\n\r\n# 0.5.1 (2017-06-21)\r\n- Vanilla JS rewrite of legacy jQuery code (which was a rewrite of legacy Prototype.js code)\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluem%2Fform-change-tracker","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fbluem%2Fform-change-tracker","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fbluem%2Fform-change-tracker/lists"}