gina 0.6.3 → 0.6.4
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/CHANGELOG.md +29 -0
- package/README.md +32 -40
- package/ROADMAP.md +3 -1
- package/framework/v0.6.4/VERSION +1 -0
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/css/gina.min.css +1 -0
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/css/gina.min.css.br +0 -0
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/css/gina.min.css.gz +0 -0
- package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/js/gina.js +1522 -79
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/js/gina.min.js +640 -0
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/js/gina.min.js.br +0 -0
- package/framework/v0.6.4/core/asset/plugin/dist/vendor/gina/js/gina.min.js.gz +0 -0
- package/framework/{v0.6.3 → v0.6.4}/core/config.js +22 -4
- package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.js +62 -2
- package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-nunjucks.js +11 -3
- package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-swig.js +15 -1
- package/framework/{v0.6.3 → v0.6.4}/core/gna.js +33 -1
- package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/validator/src/main.js +892 -21
- package/framework/{v0.6.3 → v0.6.4}/core/server.js +60 -2
- package/framework/v0.6.4/core/template/_gitignore +27 -0
- package/framework/{v0.6.3 → v0.6.4}/lib/cmd/secrets/arguments.json +1 -0
- package/framework/v0.6.4/lib/cmd/secrets/check.js +861 -0
- package/framework/{v0.6.3 → v0.6.4}/lib/cmd/secrets/help.txt +29 -5
- package/framework/v0.6.4/lib/loading-state/package.json +7 -0
- package/framework/v0.6.4/lib/loading-state/src/main.js +366 -0
- package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/mq/listener.js +23 -0
- package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/mq/speaker.js +27 -0
- package/framework/v0.6.4/lib/secrets/src/backends/file.js +180 -0
- package/framework/v0.6.4/lib/secrets/src/env-file.js +220 -0
- package/framework/{v0.6.3 → v0.6.4}/lib/secrets/src/main.js +84 -1
- package/framework/{v0.6.3 → v0.6.4}/package.json +1 -1
- package/gna.js +4 -4
- package/llms.txt +7 -7
- package/package.json +3 -3
- package/schema/settings.json +14 -0
- package/framework/v0.6.3/VERSION +0 -1
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/css/gina.min.css +0 -1
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/css/gina.min.css.br +0 -0
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/css/gina.min.css.gz +0 -0
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/js/gina.min.js +0 -625
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/js/gina.min.js.br +0 -0
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/js/gina.min.js.gz +0 -0
- package/framework/v0.6.3/core/template/_gitignore +0 -19
- package/framework/v0.6.3/lib/cmd/secrets/check.js +0 -507
- /package/framework/{v0.6.3 → v0.6.4}/AUTHORS +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/LICENSE +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/html/nolayout.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/html/static.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/android-chrome-192x192.png +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/android-chrome-512x512.png +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/apple-touch-icon.png +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/favicon-16x16.png +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/favicon-32x32.png +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/img/favicon.ico +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.css +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/beemaster/index.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/html/statusbar.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.br +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/html/statusbar.html.gz +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/inspector/have_heart_one-webfont.woff2 +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/inspector/index.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/inspector/inspector.css +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/inspector/inspector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/inspector/logo.svg +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.br +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.gz +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/ai/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/ai/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/connector.v3.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/connector.v4.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/n1ql.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/session-store.v3.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/couchbase/lib/session-store.v4.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/duckdb/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/duckdb/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mongodb/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mongodb/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mongodb/lib/job-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mongodb/lib/pipeline-loader.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mongodb/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mysql/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/mysql/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/postgresql/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/postgresql/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/redis/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/redis/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/redis/lib/job-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/redis/lib/render-cache-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/redis/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/scylladb/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/scylladb/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/scylladb/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/sql-parser.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/sqlite/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/sqlite/lib/connector.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/sqlite/lib/job-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/connectors/sqlite/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/content.encoding +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.framework.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-json.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-nunjucks-async.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-stream.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-swig-async.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/controller.render-v1.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/inspector-window-emit.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/controller/release-banner.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/dev/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/dev/lib/class.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/dev/lib/factory.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/dev/lib/tools.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/currency.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/dist/language/en.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/dist/language/fr.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/dist/region/en.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/dist/region/fr.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/locales/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/mime.types +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/model/entity.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/model/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/model/template/entityFactory.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/model/template/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/csrf/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/csrf/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/csrf/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coep/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coep/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coep/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coop/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coop/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/coop/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/corp/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/corp/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/corp/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/csp/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/csp/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/csp/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hide-powered-by/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hide-powered-by/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hide-powered-by/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hsts/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hsts/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/hsts/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/origin-agent-cluster/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/origin-agent-cluster/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/origin-agent-cluster/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/referrer-policy/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/referrer-policy/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/referrer-policy/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-content-type-options/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-content-type-options/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-content-type-options/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-dns-prefetch-control/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-dns-prefetch-control/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-dns-prefetch-control/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-download-options/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-download-options/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-download-options/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-frame-options/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-frame-options/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-frame-options/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-xss-protection/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-xss-protection/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/security-headers/x-xss-protection/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/session/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/session/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/session/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/storage/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/storage/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/storage/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/storage/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/validator/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/validator/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/validator/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/plugins/lib/validator/src/form-validator.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/router.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/server.express.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/server.isaac.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/status.codes +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/app.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/connectors.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/routing.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/settings.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/settings.server.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/templates.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/config/watchers.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/controllers/controller.content.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/controllers/controller.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/controllers/setup.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle/locales/en.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_namespace/controllers/controller.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/css/default.css +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/css/home.css +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/css/vendor/readme.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/favicon.ico +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/js/components/x-checklist.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/js/vendor/readme.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/manifest.webmanifest +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/readme.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_public/sw.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/handlers/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/html/content/homepage.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/html/includes/error-msg-noscript.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/html/includes/error-msg-outdated-browser.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/html/includes/x-checklist.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/boilerplate/bundle_templates/html/layouts/main.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/command/gina.bat.tpl +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/command/gina.tpl +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/env.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/manifest.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/settings.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/statics.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/conf/templates.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/client/json/401.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/client/json/403.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/client/json/404.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/server/html/50x.html +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/server/json/500.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/error/server/json/503.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/core/template/extensions/logger/config.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/console.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/context.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/data/LICENSE +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/data/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/data/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/data/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/dateFormat.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/json/LICENSE +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/json/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/json/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/json/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/path.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/plugins/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/plugins/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/plugins/src/api-error.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/plugins/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/prototypes.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/task.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/helpers/text.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/admin/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/admin/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/archiver/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/archiver/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/archiver/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/archiver/src/dep/jszip.min.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/archiver/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/async/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/async/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/audit/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/audit/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/audit-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authn/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authn/src/lockout.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authn/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authn/src/totp.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authz-gate/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/authz-gate/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cache/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cache/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cache/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cache/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/aliases.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/audit/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/audit/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/audit/verify.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/build.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/copy.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/cp.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/inc/name-rewrite.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/mcp-start.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/mcp.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/oas.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/openapi.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/rename.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/restart.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/start.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/status.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/stop.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/bundle/types.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/cache/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/cache/clear.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/cache/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/cache/stats.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/infer.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/migrate.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/models.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/connector/test.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/ps.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/container/stop.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/inc/args.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/inc/namespace.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/inc/reference-rewrite.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/inc/reference-scan.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/inc/scaffold.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/rename.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/controller/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/get.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/link-dev.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/set.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/unset.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/env/use.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/build.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/dot.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/get.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/init.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/link-node-modules.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/link.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/msg.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/open.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/reset.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/restart.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/set.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/start.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/status.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/stop.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/tail.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/update.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/framework/version.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/gina-dev.1.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/gina-framework.1.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/gina.1.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/helper.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/export.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/import.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/i18n/scan.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/_host.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/build.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/image/run.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/inspector/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/inspector/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/inspector/open.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/man-render.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/minion/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/minion/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/minion/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/minion/kill.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/minion/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/msg.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/inc/scan.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/reset.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/port/set.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/backup.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/build.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/import.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/move.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/rename.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/restart.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/restore.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/start.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/status.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/project/stop.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/arguments.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/protocol/set.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/link-local.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/link-production.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/remove.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/rm.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/scope/use.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/secrets/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/secrets/scan.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/service/help.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/service/help.txt +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/service/list.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/service/man.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/service/start.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd/view/add.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd-status-format/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cmd-status-format/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/collection/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/collection/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/collection/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/collection/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/config.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-config/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-config/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-error/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-error/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-registry/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/connector-registry/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cron/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cron/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/cron/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/domain/LICENSE +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/domain/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/domain/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/domain/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto-pipe/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto-pipe/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto-types/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/dto-types/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/generator/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/i18n/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/i18n/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/image-build/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/image-build/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inherits/LICENSE +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inherits/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inherits/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inherits/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inspector-events/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inspector-events/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inspector-redact/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/inspector-redact/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/instrument/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/instrument/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/job/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/job/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/job-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/json-config-header/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/json-config-header/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/default/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/file/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/file/lib/logrotator/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/file/lib/logrotator/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/containers/mq/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/helper.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/logger/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/math/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-dispatch/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-dispatch/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-http/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-http/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-server/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/mcp-server/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/merge/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/merge/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/merge/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/metrics/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/metrics/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/model.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/net-locality/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/net-locality/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/nunjucks-filters/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/nunjucks-filters/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/nunjucks-filters/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/nunjucks-resolver/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/nunjucks-resolver/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/proc.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/release-watch/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/release-watch/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/render-cache/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/render-cache/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/render-cache-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing/build.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing/src/radix.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing-introspect/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/routing-introspect/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/secrets/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/secrets/src/backends/env.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/session-store.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/shell.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/sqlite-driver.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/state.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/swig-filters/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/swig-filters/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/swig-filters/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/swig-resolver/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/swig-resolver/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/template-loaders/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/template-loaders/src/loaders/http.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/template-loaders/src/loaders/memory.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/template-loaders/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/url/README.md +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/url/index.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/url/routing.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/uuid/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/uuid/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/validator.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/watcher/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/watcher/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-framing/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-framing/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-query/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-query/src/main.js +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-session/package.json +0 -0
- /package/framework/{v0.6.3 → v0.6.4}/lib/ws-session/src/main.js +0 -0
|
@@ -9274,10 +9274,378 @@ if ( _isNode ) {
|
|
|
9274
9274
|
});
|
|
9275
9275
|
}
|
|
9276
9276
|
;
|
|
9277
|
-
|
|
9277
|
+
|
|
9278
|
+
/**
|
|
9279
|
+
* This file is part of the gina package.
|
|
9280
|
+
* Copyright (c) 2009-2026 Rhinostone <contact@gina.io>
|
|
9281
|
+
*
|
|
9282
|
+
* For the full copyright and license information, please view the LICENSE
|
|
9283
|
+
* file that was distributed with this source code.
|
|
9284
|
+
*/
|
|
9285
|
+
|
|
9286
|
+
/**
|
|
9287
|
+
* @module lib/loading-state
|
|
9288
|
+
* @description Framework-owned loading state for submit-like triggers. Works in
|
|
9289
|
+
* Node.js (CommonJS) and browser (AMD / GFF) contexts.
|
|
9290
|
+
*
|
|
9291
|
+
* A submit-like trigger — `<button type="submit">`, `<input type="submit">` or an
|
|
9292
|
+
* `<a data-gina-form-submit>` — carries `data-gina-loading="true"` for exactly as
|
|
9293
|
+
* long as the action it started is running, and `"false"` once that action
|
|
9294
|
+
* completes OR is interrupted. Consumers style the running state with CSS.
|
|
9295
|
+
*
|
|
9296
|
+
* The module owns three things and no more: resolving the configured attribute
|
|
9297
|
+
* NAME, writing the two values, and walking a click target up to the trigger that
|
|
9298
|
+
* actually owns it. It holds NO state — the caller decides which element is armed
|
|
9299
|
+
* and where to remember it, so the validator, popin and link plugins can share one
|
|
9300
|
+
* implementation without sharing a registry.
|
|
9301
|
+
*
|
|
9302
|
+
* ## The `"false"` value is deliberate, and it constrains readers
|
|
9303
|
+
*
|
|
9304
|
+
* `disarm()` writes the STRING `"false"`; it does not remove the attribute. That
|
|
9305
|
+
* diverges on purpose from the form-scoped `data-gina-form-loading`, which #B175
|
|
9306
|
+
* changed from `setAttribute(..., false)` to `removeAttribute()` precisely because
|
|
9307
|
+
* `"false"` is attribute-PRESENT and therefore truthy for a presence check.
|
|
9308
|
+
*
|
|
9309
|
+
* The consequence is a hard rule for every reader, in the framework and in
|
|
9310
|
+
* consumer CSS alike: **match on the VALUE, never on presence**. Use
|
|
9311
|
+
* `[data-gina-loading="true"]`, never a bare `[data-gina-loading]`, and in JS use
|
|
9312
|
+
* {@link module:lib/loading-state~isArmed} rather than reading the attribute
|
|
9313
|
+
* directly. A bare presence selector matches a disarmed trigger and pins the
|
|
9314
|
+
* loading style on forever.
|
|
9315
|
+
*
|
|
9316
|
+
* ## Configuring the attribute name
|
|
9317
|
+
*
|
|
9318
|
+
* The name is read from `gina.config.loadingAttribute`, lazily, at every call —
|
|
9319
|
+
* `gina.config` is populated after the bundle loads (via `setOptions`), so a value
|
|
9320
|
+
* captured at module-definition time would be stale. A project already built on
|
|
9321
|
+
* `data-loading` opts in with:
|
|
9322
|
+
*
|
|
9323
|
+
* ```html
|
|
9324
|
+
* <script src="/js/vendor/gina/gina.min.js"
|
|
9325
|
+
* data-gina-config="{ loadingAttribute: 'data-loading' }"></script>
|
|
9326
|
+
* ```
|
|
9327
|
+
*
|
|
9328
|
+
* or `gina.setOptions({ loadingAttribute: 'data-loading' })`. There is no
|
|
9329
|
+
* auto-detection: a DOM probe reads nothing at rest (the attribute only exists
|
|
9330
|
+
* while something is loading) and a stylesheet probe races late-loaded sheets and
|
|
9331
|
+
* throws on cross-origin ones. Configuration is explicit by design.
|
|
9332
|
+
*
|
|
9333
|
+
* @example
|
|
9334
|
+
* var loadingState = require('lib/loading-state');
|
|
9335
|
+
*
|
|
9336
|
+
* var $trigger = loadingState.resolveTrigger(event.target, $form);
|
|
9337
|
+
* loadingState.arm($trigger); // data-gina-loading="true"
|
|
9338
|
+
* // ... the action runs, then settles, errors, times out or is rejected ...
|
|
9339
|
+
* loadingState.disarm($trigger); // data-gina-loading="false"
|
|
9340
|
+
*/
|
|
9341
|
+
|
|
9342
|
+
/**
|
|
9343
|
+
* Loading-state factory — returns the stateless API object.
|
|
9344
|
+
* Exported as the module itself via `module.exports = LoadingState()`.
|
|
9345
|
+
*
|
|
9346
|
+
* @function LoadingState
|
|
9347
|
+
* @returns {object} The `{ arm, disarm, isArmed, getAttributeName, resolveTrigger, DEFAULT_ATTRIBUTE }` API
|
|
9348
|
+
*
|
|
9349
|
+
* @memberof module:lib
|
|
9350
|
+
* @author Rhinostone <contact@gina.io>
|
|
9351
|
+
* @api Public
|
|
9352
|
+
*/
|
|
9353
|
+
function LoadingState() {
|
|
9354
|
+
|
|
9355
|
+
/**
|
|
9356
|
+
* The attribute written when no `gina.config.loadingAttribute` override is set.
|
|
9357
|
+
*
|
|
9358
|
+
* @constant {string}
|
|
9359
|
+
* @inner
|
|
9360
|
+
*/
|
|
9361
|
+
var DEFAULT_ATTRIBUTE = 'data-gina-loading';
|
|
9362
|
+
|
|
9363
|
+
/**
|
|
9364
|
+
* The value written by `arm()`.
|
|
9365
|
+
*
|
|
9366
|
+
* @constant {string}
|
|
9367
|
+
* @inner
|
|
9368
|
+
*/
|
|
9369
|
+
var ARMED = 'true';
|
|
9370
|
+
|
|
9371
|
+
/**
|
|
9372
|
+
* The value written by `disarm()`. NOT `removeAttribute` — see the module
|
|
9373
|
+
* description for why, and for the presence-check rule it imposes on readers.
|
|
9374
|
+
*
|
|
9375
|
+
* @constant {string}
|
|
9376
|
+
* @inner
|
|
9377
|
+
*/
|
|
9378
|
+
var DISARMED = 'false';
|
|
9379
|
+
|
|
9380
|
+
/**
|
|
9381
|
+
* How many ancestors `resolveTrigger()` will climb before giving up. A submit
|
|
9382
|
+
* trigger is a direct child of its form in every realistic markup, so this is a
|
|
9383
|
+
* runaway guard rather than a real limit — a detached or cyclic node can not
|
|
9384
|
+
* spin the loop.
|
|
9385
|
+
*
|
|
9386
|
+
* @constant {number}
|
|
9387
|
+
* @inner
|
|
9388
|
+
*/
|
|
9389
|
+
var MAX_DEPTH = 10;
|
|
9390
|
+
|
|
9391
|
+
/**
|
|
9392
|
+
* isNode
|
|
9393
|
+
*
|
|
9394
|
+
* True when `$el` can carry attributes. Guards every public entry point so a
|
|
9395
|
+
* `null`, a text node, a `window` or a plain object is a silent no-op rather
|
|
9396
|
+
* than a thrown TypeError inside an event handler.
|
|
9397
|
+
*
|
|
9398
|
+
* @param {object} $el - candidate element
|
|
9399
|
+
*
|
|
9400
|
+
* @returns {boolean} true when `$el` exposes the attribute API
|
|
9401
|
+
*
|
|
9402
|
+
* @example
|
|
9403
|
+
* isNode(document.querySelector('button')); // true
|
|
9404
|
+
* isNode(null); // false
|
|
9405
|
+
*
|
|
9406
|
+
* @inner
|
|
9407
|
+
*/
|
|
9408
|
+
var isNode = function($el) {
|
|
9409
|
+
return !!(
|
|
9410
|
+
$el
|
|
9411
|
+
&& typeof($el.setAttribute) == 'function'
|
|
9412
|
+
&& typeof($el.getAttribute) == 'function'
|
|
9413
|
+
);
|
|
9414
|
+
};
|
|
9415
|
+
|
|
9416
|
+
/**
|
|
9417
|
+
* isSubmitTrigger
|
|
9418
|
+
*
|
|
9419
|
+
* True when `$el` is an element a user submits a form WITH. Mirrors the shapes
|
|
9420
|
+
* the validator's click proxy already recognises: a `button`/`input` whose type
|
|
9421
|
+
* is `submit`, or an anchor carrying `data-gina-form-submit`.
|
|
9422
|
+
*
|
|
9423
|
+
* @param {object} $el - candidate element
|
|
9424
|
+
*
|
|
9425
|
+
* @returns {boolean} true when `$el` is a submit-like trigger
|
|
9426
|
+
*
|
|
9427
|
+
* @example
|
|
9428
|
+
* isSubmitTrigger($button); // true for <button type="submit">
|
|
9429
|
+
* isSubmitTrigger($span); // false
|
|
9430
|
+
*
|
|
9431
|
+
* @inner
|
|
9432
|
+
*/
|
|
9433
|
+
var isSubmitTrigger = function($el) {
|
|
9434
|
+
if ( !isNode($el) || !$el.tagName ) {
|
|
9435
|
+
return false;
|
|
9436
|
+
}
|
|
9437
|
+
if ( /^(button|input)$/i.test($el.tagName) && /^submit$/i.test($el.type || '') ) {
|
|
9438
|
+
return true;
|
|
9439
|
+
}
|
|
9440
|
+
if ( /^a$/i.test($el.tagName) && $el.getAttribute('data-gina-form-submit') != null ) {
|
|
9441
|
+
return true;
|
|
9442
|
+
}
|
|
9443
|
+
return false;
|
|
9444
|
+
};
|
|
9445
|
+
|
|
9446
|
+
/**
|
|
9447
|
+
* getAttributeName
|
|
9448
|
+
*
|
|
9449
|
+
* Resolves the attribute name to write. Reads `gina.config.loadingAttribute`
|
|
9450
|
+
* LAZILY on every call: `gina.config` is populated after the bundle loads, so a
|
|
9451
|
+
* value captured once at definition time would always be the default. Falls
|
|
9452
|
+
* back to `data-gina-loading` when unset, empty or not a string.
|
|
9453
|
+
*
|
|
9454
|
+
* @returns {string} the configured attribute name, or `data-gina-loading`
|
|
9455
|
+
*
|
|
9456
|
+
* @example
|
|
9457
|
+
* getAttributeName(); // 'data-gina-loading'
|
|
9458
|
+
* gina.setOptions({ loadingAttribute: 'data-loading' });
|
|
9459
|
+
* getAttributeName(); // 'data-loading'
|
|
9460
|
+
*
|
|
9461
|
+
* @api Public
|
|
9462
|
+
*/
|
|
9463
|
+
var getAttributeName = function() {
|
|
9464
|
+
if (
|
|
9465
|
+
typeof(gina) != 'undefined' && gina && gina.config
|
|
9466
|
+
&& typeof(gina.config.loadingAttribute) == 'string'
|
|
9467
|
+
&& gina.config.loadingAttribute !== ''
|
|
9468
|
+
) {
|
|
9469
|
+
return gina.config.loadingAttribute;
|
|
9470
|
+
}
|
|
9471
|
+
return DEFAULT_ATTRIBUTE;
|
|
9472
|
+
};
|
|
9473
|
+
|
|
9474
|
+
/**
|
|
9475
|
+
* arm
|
|
9476
|
+
*
|
|
9477
|
+
* Marks `$el` as running by writing `<attribute>="true"`. Idempotent — arming an
|
|
9478
|
+
* already-armed trigger rewrites the same value. A non-element is a no-op.
|
|
9479
|
+
*
|
|
9480
|
+
* @param {object} $el - the trigger to mark (see `resolveTrigger`)
|
|
9481
|
+
*
|
|
9482
|
+
* @returns {boolean} true when the attribute was written
|
|
9483
|
+
*
|
|
9484
|
+
* @example
|
|
9485
|
+
* arm($button); // $button now carries data-gina-loading="true"
|
|
9486
|
+
*
|
|
9487
|
+
* @api Public
|
|
9488
|
+
*/
|
|
9489
|
+
var arm = function($el) {
|
|
9490
|
+
if ( !isNode($el) ) {
|
|
9491
|
+
return false;
|
|
9492
|
+
}
|
|
9493
|
+
$el.setAttribute(getAttributeName(), ARMED);
|
|
9494
|
+
return true;
|
|
9495
|
+
};
|
|
9496
|
+
|
|
9497
|
+
/**
|
|
9498
|
+
* disarm
|
|
9499
|
+
*
|
|
9500
|
+
* Releases `$el` by writing `<attribute>="false"`. Called on EVERY terminal
|
|
9501
|
+
* outcome — settled, errored, timed out, aborted, rate-limited and
|
|
9502
|
+
* validation-rejected — so a trigger can not stay visually loading after its
|
|
9503
|
+
* action stopped. Idempotent; a non-element is a no-op.
|
|
9504
|
+
*
|
|
9505
|
+
* Writes `"false"` rather than removing the attribute; see the module
|
|
9506
|
+
* description for the reasoning and the presence-check rule it imposes.
|
|
9507
|
+
*
|
|
9508
|
+
* @param {object} $el - the trigger to release
|
|
9509
|
+
*
|
|
9510
|
+
* @returns {boolean} true when the attribute was written
|
|
9511
|
+
*
|
|
9512
|
+
* @example
|
|
9513
|
+
* disarm($button); // $button now carries data-gina-loading="false"
|
|
9514
|
+
*
|
|
9515
|
+
* @api Public
|
|
9516
|
+
*/
|
|
9517
|
+
var disarm = function($el) {
|
|
9518
|
+
if ( !isNode($el) ) {
|
|
9519
|
+
return false;
|
|
9520
|
+
}
|
|
9521
|
+
$el.setAttribute(getAttributeName(), DISARMED);
|
|
9522
|
+
return true;
|
|
9523
|
+
};
|
|
9524
|
+
|
|
9525
|
+
/**
|
|
9526
|
+
* isArmed
|
|
9527
|
+
*
|
|
9528
|
+
* True only when `$el` is currently marked as running. Compares the VALUE
|
|
9529
|
+
* against `"true"` — never tests presence, because a disarmed trigger still
|
|
9530
|
+
* carries the attribute with `"false"`. Use this instead of reading the
|
|
9531
|
+
* attribute directly.
|
|
9532
|
+
*
|
|
9533
|
+
* @param {object} $el - the trigger to inspect
|
|
9534
|
+
*
|
|
9535
|
+
* @returns {boolean} true when `$el` carries `<attribute>="true"`
|
|
9536
|
+
*
|
|
9537
|
+
* @example
|
|
9538
|
+
* arm($button); isArmed($button); // true
|
|
9539
|
+
* disarm($button); isArmed($button); // false — attribute present, value "false"
|
|
9540
|
+
*
|
|
9541
|
+
* @api Public
|
|
9542
|
+
*/
|
|
9543
|
+
var isArmed = function($el) {
|
|
9544
|
+
if ( !isNode($el) ) {
|
|
9545
|
+
return false;
|
|
9546
|
+
}
|
|
9547
|
+
return $el.getAttribute(getAttributeName()) === ARMED;
|
|
9548
|
+
};
|
|
9549
|
+
|
|
9550
|
+
/**
|
|
9551
|
+
* resolveTrigger
|
|
9552
|
+
*
|
|
9553
|
+
* Walks `$el` up to the submit trigger that owns it, so the state lands on the
|
|
9554
|
+
* control the user perceives as the button rather than on whatever inner node
|
|
9555
|
+
* happened to receive the click. `<button type="submit"><span>Save</span></button>`
|
|
9556
|
+
* clicked on the label yields the `button`, not the `span`.
|
|
9557
|
+
*
|
|
9558
|
+
* Returns `$el` itself when no submit-like ancestor is found, so a caller that
|
|
9559
|
+
* already knows it is handling a submit still gets a usable element. Stops at
|
|
9560
|
+
* the boundary element (typically the form), at `form`/`body`/`html`, or after
|
|
9561
|
+
* `MAX_DEPTH` hops.
|
|
9562
|
+
*
|
|
9563
|
+
* ## Recognising a non-submit trigger (`isTrigger`)
|
|
9564
|
+
*
|
|
9565
|
+
* The default predicate recognises submit-like controls only — a `button` or
|
|
9566
|
+
* `input` of type `submit`, or an `a[data-gina-form-submit]`. That is what the
|
|
9567
|
+
* validator needs and nothing else. Other plugins arm elements this module has
|
|
9568
|
+
* no business knowing about: link arms `a[data-gina-link]`, popin arms
|
|
9569
|
+
* `a[data-gina-dialog]`. Pass `isTrigger` to say what counts as YOUR trigger.
|
|
9570
|
+
*
|
|
9571
|
+
* Without it the climb finds no match, breaks at `form`/`body`/`html`, and
|
|
9572
|
+
* returns the ORIGINAL `$el` — so a click on the `<span>` inside
|
|
9573
|
+
* `<a data-gina-link><span>Go</span></a>` would arm the span and leave the
|
|
9574
|
+
* anchor unstyled.
|
|
9575
|
+
*
|
|
9576
|
+
* The predicate lives with the caller deliberately rather than being folded
|
|
9577
|
+
* into the default: this module owns the WALK, each plugin owns its own notion
|
|
9578
|
+
* of a trigger. Folding plugin attribute names in here would also couple the
|
|
9579
|
+
* module to the popin deprecation/alias work, which changes which attributes
|
|
9580
|
+
* are honoured over time.
|
|
9581
|
+
*
|
|
9582
|
+
* @param {object} $el - the clicked element (`event.target`)
|
|
9583
|
+
* @param {object} [$boundary] - element to stop at, usually the `<form>`
|
|
9584
|
+
* @param {function} [isTrigger] - `($node) => boolean`; defaults to the
|
|
9585
|
+
* submit-like predicate. Ignored when not a function. A predicate that
|
|
9586
|
+
* THROWS is deliberately not caught: every caller is framework code, so
|
|
9587
|
+
* swallowing would hide a framework bug behind a silently unarmed trigger.
|
|
9588
|
+
*
|
|
9589
|
+
* @returns {object} the owning trigger, or `$el`, or `null` when `$el` is not an element
|
|
9590
|
+
*
|
|
9591
|
+
* @example
|
|
9592
|
+
* // <button type="submit"><span>Save</span></button>
|
|
9593
|
+
* resolveTrigger(event.target, $form); // the <button>, even when the <span> was clicked
|
|
9594
|
+
*
|
|
9595
|
+
* @example
|
|
9596
|
+
* // <a data-gina-link><span>Go</span></a> — the span was clicked
|
|
9597
|
+
* resolveTrigger(event.target, null, function($n) {
|
|
9598
|
+
* return /^a$/i.test($n.tagName) && $n.getAttribute('data-gina-link') != null;
|
|
9599
|
+
* }); // the <a>, not the <span>
|
|
9600
|
+
*
|
|
9601
|
+
* @api Public
|
|
9602
|
+
*/
|
|
9603
|
+
var resolveTrigger = function($el, $boundary, isTrigger) {
|
|
9604
|
+
if ( !isNode($el) ) {
|
|
9605
|
+
return null;
|
|
9606
|
+
}
|
|
9607
|
+
var matches = ( typeof(isTrigger) == 'function' ) ? isTrigger : isSubmitTrigger;
|
|
9608
|
+
var $node = $el;
|
|
9609
|
+
var depth = 0;
|
|
9610
|
+
while ( isNode($node) && depth < MAX_DEPTH ) {
|
|
9611
|
+
if ( matches($node) ) {
|
|
9612
|
+
return $node;
|
|
9613
|
+
}
|
|
9614
|
+
if ( $boundary && $node === $boundary ) {
|
|
9615
|
+
break;
|
|
9616
|
+
}
|
|
9617
|
+
if ( $node.tagName && /^(form|body|html)$/i.test($node.tagName) ) {
|
|
9618
|
+
break;
|
|
9619
|
+
}
|
|
9620
|
+
$node = $node.parentNode;
|
|
9621
|
+
++depth;
|
|
9622
|
+
}
|
|
9623
|
+
return $el;
|
|
9624
|
+
};
|
|
9625
|
+
|
|
9626
|
+
return {
|
|
9627
|
+
'DEFAULT_ATTRIBUTE' : DEFAULT_ATTRIBUTE,
|
|
9628
|
+
'getAttributeName' : getAttributeName,
|
|
9629
|
+
'arm' : arm,
|
|
9630
|
+
'disarm' : disarm,
|
|
9631
|
+
'isArmed' : isArmed,
|
|
9632
|
+
'resolveTrigger' : resolveTrigger
|
|
9633
|
+
};
|
|
9634
|
+
}
|
|
9635
|
+
|
|
9636
|
+
if ( ( typeof(module) !== 'undefined' ) && module.exports ) {
|
|
9637
|
+
// Publish as node.js module
|
|
9638
|
+
module.exports = LoadingState()
|
|
9639
|
+
} else if ( typeof(define) === 'function' && define.amd) {
|
|
9640
|
+
// Publish as AMD module
|
|
9641
|
+
define('lib/loading-state', [],function() { return LoadingState() })
|
|
9642
|
+
}
|
|
9643
|
+
;
|
|
9644
|
+
define('gina/link', [ 'require', 'lib/domain', 'lib/loading-state', 'lib/merge', 'lib/uuid', 'utils/events' ], function (require) {
|
|
9278
9645
|
|
|
9279
9646
|
var Domain = require('lib/domain');
|
|
9280
9647
|
var domainInstance = null;
|
|
9648
|
+
var loadingState = require('lib/loading-state');
|
|
9281
9649
|
var merge = require('lib/merge');
|
|
9282
9650
|
var uuid = require('lib/uuid');
|
|
9283
9651
|
|
|
@@ -9333,8 +9701,52 @@ define('gina/link', [ 'require', 'lib/domain', 'lib/merge', 'lib/uuid', 'utils/e
|
|
|
9333
9701
|
|
|
9334
9702
|
|
|
9335
9703
|
|
|
9336
|
-
// XML Request
|
|
9337
|
-
|
|
9704
|
+
// XML Request — the request currently in flight, plus a monotonic sequence.
|
|
9705
|
+
//
|
|
9706
|
+
// These replace a single module-scope `xhr` that every link click reused.
|
|
9707
|
+
// That is the #B175 class popin already fixed and nav deliberately avoids:
|
|
9708
|
+
// calling `open()` on an object that is still carrying a request implicitly
|
|
9709
|
+
// ABORTS it, and an aborted request reaches readyState 4 with status 0 —
|
|
9710
|
+
// which `handleXhr` has no branch for. So the first click's completion never
|
|
9711
|
+
// arrived at all, and anything waiting on it waited forever.
|
|
9712
|
+
//
|
|
9713
|
+
// The sequence exists because aborting is not enough on its own: the
|
|
9714
|
+
// superseded request may already have reached readyState 4 and queued its
|
|
9715
|
+
// handler. `_linkSeq` lets that stale response be dropped rather than acted
|
|
9716
|
+
// upon, so a slow first response can never overwrite a newer one.
|
|
9717
|
+
var _linkXhr = null;
|
|
9718
|
+
var _linkSeq = 0;
|
|
9719
|
+
|
|
9720
|
+
/**
|
|
9721
|
+
* Build a fresh transport for a single request.
|
|
9722
|
+
*
|
|
9723
|
+
* Was inlined in the `init` handler, which created ONE object for the whole
|
|
9724
|
+
* page lifetime. Per-request construction is what makes concurrent link
|
|
9725
|
+
* clicks independent.
|
|
9726
|
+
*
|
|
9727
|
+
* @returns {object} a new XHR-like object, or `null` when the browser has none
|
|
9728
|
+
*
|
|
9729
|
+
* @example
|
|
9730
|
+
* var xhr = createXhr(); // fresh per request — never shared
|
|
9731
|
+
*
|
|
9732
|
+
* @inner
|
|
9733
|
+
*/
|
|
9734
|
+
var createXhr = function() {
|
|
9735
|
+
if (window.XMLHttpRequest) { // Mozilla, Safari, ...
|
|
9736
|
+
return new XMLHttpRequest();
|
|
9737
|
+
}
|
|
9738
|
+
if (window.ActiveXObject) { // IE
|
|
9739
|
+
try {
|
|
9740
|
+
return new ActiveXObject("Msxml2.XMLHTTP");
|
|
9741
|
+
} catch (e) {
|
|
9742
|
+
try {
|
|
9743
|
+
return new ActiveXObject("Microsoft.XMLHTTP");
|
|
9744
|
+
}
|
|
9745
|
+
catch (e) {}
|
|
9746
|
+
}
|
|
9747
|
+
}
|
|
9748
|
+
return null;
|
|
9749
|
+
};
|
|
9338
9750
|
|
|
9339
9751
|
/**
|
|
9340
9752
|
* XML Request options
|
|
@@ -9386,11 +9798,42 @@ define('gina/link', [ 'require', 'lib/domain', 'lib/merge', 'lib/uuid', 'utils/e
|
|
|
9386
9798
|
/**
|
|
9387
9799
|
* linkRequest
|
|
9388
9800
|
*
|
|
9389
|
-
*
|
|
9390
|
-
*
|
|
9801
|
+
* Builds and sends the request for a bound link. Every entry point funnels
|
|
9802
|
+
* through here — the direct click, the `proxyClick` child delegation and the
|
|
9803
|
+
* public `gina.link.request()` — which is why the loading state is armed here
|
|
9804
|
+
* rather than in the click handlers: `$el` is already the anchor at this point,
|
|
9805
|
+
* so no click target ever has to be walked back up to it.
|
|
9806
|
+
*
|
|
9807
|
+
* Side effects: supersedes any request still in flight, arms `data-gina-loading`
|
|
9808
|
+
* on the anchor for the duration of this one, and releases it from a `loadend`
|
|
9809
|
+
* listener. An indefinite hang is the single outcome that never releases, because
|
|
9810
|
+
* no `xhr.timeout` is set.
|
|
9811
|
+
*
|
|
9812
|
+
* @param {string} url - URL to request
|
|
9813
|
+
* @param {object} [options] - XHR options, merged over the link's own
|
|
9814
|
+
*
|
|
9815
|
+
* @returns {void}
|
|
9816
|
+
*
|
|
9817
|
+
* @example
|
|
9818
|
+
* gina.link.request('/some/route'); // arms the bound anchor, releases on loadend
|
|
9819
|
+
*
|
|
9820
|
+
* @inner
|
|
9391
9821
|
* */
|
|
9392
9822
|
function linkRequest(url, options) {
|
|
9393
9823
|
|
|
9824
|
+
// One transport per request, and a sequence taken BEFORE the abort so a
|
|
9825
|
+
// supersede-abort is stale by construction — its handler sees
|
|
9826
|
+
// `seq !== _linkSeq` and drops out, which is what keeps the abort from
|
|
9827
|
+
// being mistaken for a real network failure.
|
|
9828
|
+
var seq = ++_linkSeq;
|
|
9829
|
+
if ( _linkXhr && _linkXhr.readyState !== 4 ) {
|
|
9830
|
+
try {
|
|
9831
|
+
_linkXhr.abort();
|
|
9832
|
+
} catch (abortErr) { /* already dead — nothing to unwind */ }
|
|
9833
|
+
}
|
|
9834
|
+
var xhr = createXhr();
|
|
9835
|
+
_linkXhr = xhr;
|
|
9836
|
+
|
|
9394
9837
|
// link object
|
|
9395
9838
|
var $link = getLinkByUrl(url);
|
|
9396
9839
|
var id = $link.id;
|
|
@@ -9489,10 +9932,83 @@ define('gina/link', [ 'require', 'lib/domain', 'lib/merge', 'lib/uuid', 'utils/e
|
|
|
9489
9932
|
|
|
9490
9933
|
|
|
9491
9934
|
options.$link = $link;
|
|
9935
|
+
// The CORS branches above can swap the transport (XDomainRequest) or drop
|
|
9936
|
+
// it entirely, so re-point the in-flight tracker at whatever will actually run.
|
|
9937
|
+
_linkXhr = xhr;
|
|
9492
9938
|
//xhr = handleXhr(xhr, $el, options);
|
|
9493
9939
|
handleXhr(xhr, $el, options, require);
|
|
9940
|
+
|
|
9941
|
+
// Sequence guard, applied by WRAPPING the handler `handleXhr` just installed
|
|
9942
|
+
// rather than by teaching `handleXhr` about link's sequence. `handleXhr` is
|
|
9943
|
+
// shared and the sequence belongs to the plugin that owns the clicks, so the
|
|
9944
|
+
// guard lives here and `utils/events.js` stays untouched.
|
|
9945
|
+
//
|
|
9946
|
+
// Only `onreadystatechange` needs wrapping: an aborted request fires
|
|
9947
|
+
// `onabort` (which `handleXhr` does not install), never `onerror`, so a
|
|
9948
|
+
// superseded request has exactly one way back into the completion path.
|
|
9949
|
+
var onSettled = xhr.onreadystatechange;
|
|
9950
|
+
xhr.onreadystatechange = function(event) {
|
|
9951
|
+
if ( seq !== _linkSeq ) {
|
|
9952
|
+
return; // superseded by a newer click — drop the stale response
|
|
9953
|
+
}
|
|
9954
|
+
if ( typeof(onSettled) == 'function' ) {
|
|
9955
|
+
onSettled.call(this, event);
|
|
9956
|
+
}
|
|
9957
|
+
};
|
|
9958
|
+
|
|
9959
|
+
// #B247 — loading state for the link the user actually clicked.
|
|
9960
|
+
//
|
|
9961
|
+
// Armed HERE rather than in the click handlers because `$el` is already the
|
|
9962
|
+
// anchor at this point (`getElementById($link.id)` above), and because this
|
|
9963
|
+
// is the one funnel every entry reaches: the direct click, the `proxyClick`
|
|
9964
|
+
// child delegation — which dispatches its custom event ON the anchor, so the
|
|
9965
|
+
// handler's `e.target` is never the inner node — and the public
|
|
9966
|
+
// `gina.link.request()`. Arming below the `!xhr` throw also means a transport
|
|
9967
|
+
// that never materialises can not leave a trigger lit.
|
|
9968
|
+
//
|
|
9969
|
+
// Released on `loadend`, the same fail-safe the validator uses: a LISTENER
|
|
9970
|
+
// emits no events of its own, so it covers success, error, abort AND the
|
|
9971
|
+
// readyState-4/status-0 network failure `handleXhr` has no branch for —
|
|
9972
|
+
// without any of the consumer-visible surface that adding such a branch
|
|
9973
|
+
// would carry (#B282). One listener per transport, and transports are built
|
|
9974
|
+
// per request, so nothing accumulates.
|
|
9975
|
+
//
|
|
9976
|
+
// Never arm what can not be released: the CORS branch above can swap in a
|
|
9977
|
+
// legacy `XDomainRequest`, which has no `addEventListener` and so no
|
|
9978
|
+
// `loadend` to release on. An armed trigger with no release is exactly the
|
|
9979
|
+
// permanent strand this feature exists to prevent.
|
|
9980
|
+
//
|
|
9981
|
+
// Deliberately NOT sequence-guarded, unlike the response wrapper above. The
|
|
9982
|
+
// sequence drops a stale RESPONSE; a superseded request must still RELEASE
|
|
9983
|
+
// its trigger. It releases before the newer click arms, because `abort()`
|
|
9984
|
+
// fires `loadend` synchronously — inside the abort at the top of this
|
|
9985
|
+
// function, which runs before this line. Guarding here would strand the
|
|
9986
|
+
// trigger it was meant to protect.
|
|
9987
|
+
//
|
|
9988
|
+
// Residual: a request that never terminates never fires `loadend`, so an
|
|
9989
|
+
// indefinite hang still strands the trigger. That is #B283 (no `xhr.timeout`
|
|
9990
|
+
// is set, which is also why the `ontimeout` handleXhr installs is dead code)
|
|
9991
|
+
// — a separate, consumer-visible behaviour change, NOT covered here.
|
|
9992
|
+
if ( typeof(xhr.addEventListener) == 'function' ) {
|
|
9993
|
+
loadingState.arm($el);
|
|
9994
|
+
xhr.addEventListener('loadend', function onLinkSettled() {
|
|
9995
|
+
loadingState.disarm($el);
|
|
9996
|
+
});
|
|
9997
|
+
}
|
|
9998
|
+
|
|
9494
9999
|
// sending
|
|
9495
|
-
|
|
10000
|
+
try {
|
|
10001
|
+
xhr.send();
|
|
10002
|
+
} catch (sendErr) {
|
|
10003
|
+
// A synchronous throw out of `send()` (a cross-origin synchronous
|
|
10004
|
+
// request, a transport already in an invalid state) means no request ran,
|
|
10005
|
+
// so no `loadend` is ever coming. Release, then let the error out
|
|
10006
|
+
// unchanged — the caller's contract is untouched.
|
|
10007
|
+
if ( loadingState.isArmed($el) ) {
|
|
10008
|
+
loadingState.disarm($el);
|
|
10009
|
+
}
|
|
10010
|
+
throw sendErr;
|
|
10011
|
+
}
|
|
9496
10012
|
}
|
|
9497
10013
|
|
|
9498
10014
|
function registerLink($link, options) {
|
|
@@ -9661,19 +10177,10 @@ define('gina/link', [ 'require', 'lib/domain', 'lib/merge', 'lib/uuid', 'utils/e
|
|
|
9661
10177
|
setupInstanceProto();
|
|
9662
10178
|
instance.on('init', function(event) {
|
|
9663
10179
|
|
|
9664
|
-
//
|
|
9665
|
-
|
|
9666
|
-
|
|
9667
|
-
|
|
9668
|
-
try {
|
|
9669
|
-
xhr = new ActiveXObject("Msxml2.XMLHTTP");
|
|
9670
|
-
} catch (e) {
|
|
9671
|
-
try {
|
|
9672
|
-
xhr = new ActiveXObject("Microsoft.XMLHTTP");
|
|
9673
|
-
}
|
|
9674
|
-
catch (e) {}
|
|
9675
|
-
}
|
|
9676
|
-
}
|
|
10180
|
+
// AJAX setup used to happen HERE, building one transport for the whole
|
|
10181
|
+
// page lifetime. It moved to `createXhr()`, called per request from
|
|
10182
|
+
// `linkRequest`, so two link clicks no longer share one object — see the
|
|
10183
|
+
// `_linkXhr` / `_linkSeq` comment at the top of this closure.
|
|
9677
10184
|
|
|
9678
10185
|
// proxies
|
|
9679
10186
|
// click on main document
|
|
@@ -10321,6 +10828,7 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
10321
10828
|
var FormValidator = (isGFFCtx) ? require('lib/form-validator') : require('./form-validator');
|
|
10322
10829
|
//var Collection = (isGFFCtx) ? require('lib/collection') : require('../../../../../lib/collection');
|
|
10323
10830
|
var routing = (isGFFCtx) ? require('lib/routing') : require('../../../../../lib/routing');
|
|
10831
|
+
var loadingState = (isGFFCtx) ? require('lib/loading-state') : require('../../../../../lib/loading-state');
|
|
10324
10832
|
|
|
10325
10833
|
|
|
10326
10834
|
/** definitions */
|
|
@@ -11005,9 +11513,14 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11005
11513
|
if (isErrorMessageHidden) {
|
|
11006
11514
|
// hide error messages
|
|
11007
11515
|
$children[c].className = $children[c].className +' hidden';
|
|
11516
|
+
// #A11Y5 — this hide fires when the field regains focus, and it does not
|
|
11517
|
+
// touch aria-invalid: a committed error stays asserted while its message
|
|
11518
|
+
// would otherwise leave the a11y tree. Clip it instead.
|
|
11519
|
+
clipErrorMessage($children[c]);
|
|
11008
11520
|
} else {
|
|
11009
11521
|
// display error messages
|
|
11010
11522
|
$children[c].className = $children[c].className.replace(/(\s+hidden|hidden)/, '');
|
|
11523
|
+
revealErrorMessage($children[c]);
|
|
11011
11524
|
}
|
|
11012
11525
|
break
|
|
11013
11526
|
}
|
|
@@ -11015,17 +11528,38 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11015
11528
|
}
|
|
11016
11529
|
|
|
11017
11530
|
/**
|
|
11018
|
-
* #
|
|
11019
|
-
*
|
|
11020
|
-
*
|
|
11021
|
-
*
|
|
11022
|
-
*
|
|
11531
|
+
* #A11Y2 — create (or recover) a form's visually-hidden polite status region WITHOUT
|
|
11532
|
+
* writing to it. Split out of announceA11yError so the region can exist LONG before the
|
|
11533
|
+
* first error: a region that is inserted and populated in the same tick reaches assistive
|
|
11534
|
+
* tech as a single mutation batch, which is commonly never spoken, so the very first
|
|
11535
|
+
* announcement per form — the one that matters most — was the one most likely lost.
|
|
11536
|
+
* bindForm calls this at bind time, which is what makes that first error audible.
|
|
11537
|
+
*
|
|
11538
|
+
* The region is a CHILD OF THE FORM deliberately. A popin renders its form inside a native
|
|
11539
|
+
* `<dialog>` opened with showModal(), which leaves everything outside the top layer inert;
|
|
11540
|
+
* a body-level region would sit in that inert subtree and go unspoken for exactly the forms
|
|
11541
|
+
* that live in popins. Keeping it inside the form keeps it inside the dialog. The price is
|
|
11542
|
+
* that a subtree replacement (a popin re-render's `innerHTML =`, or a nav fragment swap)
|
|
11543
|
+
* destroys it — hence create-OR-RECOVER, and hence the deferred first write in
|
|
11544
|
+
* announceA11yError, which is what stops a recovery from silently repeating the defect.
|
|
11545
|
+
*
|
|
11546
|
+
* The bookkeeping flag lives on the element rather than in a module-scope map so it dies
|
|
11547
|
+
* WITH the region: a destroyed region leaves no stale entry behind, and no form id keeps
|
|
11548
|
+
* an unbounded map alive. Browser-only, like readCsrfCookie — this engine is shared with
|
|
11549
|
+
* the server form-body path, which has no document.
|
|
11550
|
+
*
|
|
11551
|
+
* @inner
|
|
11023
11552
|
* @param {object} $form - the HTMLFormElement the region belongs to
|
|
11024
|
-
* @
|
|
11025
|
-
* @
|
|
11553
|
+
* @returns {object|null} the live-region element, or null outside a browser document
|
|
11554
|
+
* @example
|
|
11555
|
+
* // at bind time: the region is in the a11y tree before any error can occur
|
|
11556
|
+
* ensureA11yLiveRegion($form.target);
|
|
11026
11557
|
*/
|
|
11027
|
-
var
|
|
11028
|
-
if ( !$form
|
|
11558
|
+
var ensureA11yLiveRegion = function($form) {
|
|
11559
|
+
if ( !$form ) return null;
|
|
11560
|
+
if ( typeof(document) === 'undefined' || !document || typeof(document.getElementById) !== 'function' ) {
|
|
11561
|
+
return null;
|
|
11562
|
+
}
|
|
11029
11563
|
var _fid = ( typeof($form.id) != 'undefined' && $form.id ) ? $form.id : ( $form.getAttribute('id') || 'form' );
|
|
11030
11564
|
var _liveId = 'gina-aria-live-' + _fid;
|
|
11031
11565
|
var _live = document.getElementById(_liveId);
|
|
@@ -11037,33 +11571,253 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11037
11571
|
_live.setAttribute('aria-atomic', 'true');
|
|
11038
11572
|
_live.className = 'gina-visually-hidden';
|
|
11039
11573
|
_live.style.cssText = 'position:absolute;width:1px;height:1px;margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;';
|
|
11574
|
+
_live.ginaA11yFresh = true;
|
|
11575
|
+
$form.appendChild(_live);
|
|
11576
|
+
} else if ( _live.parentNode !== $form ) {
|
|
11577
|
+
// Same id, different form node — a re-render replaced the form, or two forms share
|
|
11578
|
+
// an id. Re-home it so the region always sits inside the form that announces, which
|
|
11579
|
+
// is the property the inert reasoning above depends on; a move is a fresh insertion.
|
|
11580
|
+
_live.ginaA11yFresh = true;
|
|
11040
11581
|
$form.appendChild(_live);
|
|
11041
11582
|
}
|
|
11042
|
-
_live
|
|
11043
|
-
|
|
11583
|
+
return _live;
|
|
11584
|
+
};
|
|
11585
|
+
|
|
11586
|
+
/**
|
|
11587
|
+
* #A11Y1 (slice 4) — announce a blur-time committed error through the region created at
|
|
11588
|
+
* bind time. A CSS :user-invalid display toggle is not reliably announced by screen
|
|
11589
|
+
* readers, and on blur the field has lost focus so its own aria-invalid /
|
|
11590
|
+
* aria-errormessage are not re-read; the polite region decouples the announcement
|
|
11591
|
+
* from visual display. Submit-time errors use focus (see onValidate), not this region.
|
|
11592
|
+
*
|
|
11593
|
+
* #A11Y2 — when the region had to be created (or re-homed) HERE rather than at bind time,
|
|
11594
|
+
* the insertion and this write would land in the same tick and likely never be spoken, so
|
|
11595
|
+
* that first write is deferred by one macrotask. Only the fresh case defers; an already
|
|
11596
|
+
* bound region writes synchronously, exactly as before. While a deferred write is pending
|
|
11597
|
+
* a later call replaces the pending text, so the LATEST error wins and a stale first
|
|
11598
|
+
* message can never land on top of it. The timer re-enters this function, which then takes
|
|
11599
|
+
* the synchronous branch — keeping exactly ONE textContent write site.
|
|
11600
|
+
*
|
|
11601
|
+
* @param {object} $form - the HTMLFormElement the region belongs to
|
|
11602
|
+
* @param {string} text - the error text to announce
|
|
11603
|
+
* @returns {object|null} the live-region element, or null when nothing was announced
|
|
11604
|
+
* @example
|
|
11605
|
+
* announceA11yError($form, 'This field is required');
|
|
11606
|
+
*/
|
|
11607
|
+
var announceA11yError = function($form, text) {
|
|
11608
|
+
if ( !$form || !text ) return null;
|
|
11609
|
+
var _live = ensureA11yLiveRegion($form);
|
|
11610
|
+
if ( !_live ) return null;
|
|
11611
|
+
if ( _live.ginaA11yFresh ) {
|
|
11612
|
+
_live.ginaA11yPending = text;
|
|
11613
|
+
if ( !_live.ginaA11yTimer ) {
|
|
11614
|
+
_live.ginaA11yTimer = setTimeout(function() {
|
|
11615
|
+
_live.ginaA11yTimer = null;
|
|
11616
|
+
_live.ginaA11yFresh = false;
|
|
11617
|
+
announceA11yError($form, _live.ginaA11yPending);
|
|
11618
|
+
}, 0);
|
|
11619
|
+
}
|
|
11620
|
+
return _live;
|
|
11621
|
+
}
|
|
11622
|
+
text = a11yDistinctText(_live, text);
|
|
11623
|
+
_live.textContent = text;
|
|
11624
|
+
return _live;
|
|
11625
|
+
};
|
|
11626
|
+
|
|
11627
|
+
/**
|
|
11628
|
+
* #B178 — announcement text for a field's error container.
|
|
11629
|
+
* The container renders one `<p>` per rule message; visually they stack as
|
|
11630
|
+
* blocks, but `textContent` concatenates them with NO separator, so an
|
|
11631
|
+
* aria-live announcement read multiple messages as one run-on string.
|
|
11632
|
+
* Joins the per-message texts with '. ' instead; falls back to the raw
|
|
11633
|
+
* `textContent` when the container has no `<p>` children.
|
|
11634
|
+
* @inner
|
|
11635
|
+
* @param {object} $err - the error-message container element
|
|
11636
|
+
* @returns {string} announcement text
|
|
11637
|
+
*/
|
|
11638
|
+
var getA11yAnnounceText = function($err) {
|
|
11639
|
+
var $msgs = $err.getElementsByTagName('p');
|
|
11640
|
+
if ( !$msgs.length ) {
|
|
11641
|
+
return $err.textContent;
|
|
11642
|
+
}
|
|
11643
|
+
var parts = [];
|
|
11644
|
+
for (var m = 0, mLen = $msgs.length; m < mLen; ++m) {
|
|
11645
|
+
parts.push($msgs[m].textContent);
|
|
11646
|
+
}
|
|
11647
|
+
return parts.join('. ');
|
|
11648
|
+
};
|
|
11649
|
+
|
|
11650
|
+
/**
|
|
11651
|
+
* A11Y_LABELS — English defaults for gina's own accessibility status strings.
|
|
11652
|
+
*
|
|
11653
|
+
* Deliberately separate from `setErrorLabels`, which owns per-culture overrides
|
|
11654
|
+
* for *rule* error labels and is keyed by rule name. These are framework-authored
|
|
11655
|
+
* announcements about what gina is doing, so they need a home of their own.
|
|
11656
|
+
*
|
|
11657
|
+
* `%s` in a value is replaced with a runtime detail (currently the file name);
|
|
11658
|
+
* it follows the same placeholder convention the rule error labels already use,
|
|
11659
|
+
* so a translation keeps control of where the detail lands in the sentence.
|
|
11660
|
+
*
|
|
11661
|
+
* @constant {object}
|
|
11662
|
+
* @inner
|
|
11663
|
+
*/
|
|
11664
|
+
var A11Y_LABELS = {
|
|
11665
|
+
submitting : 'Submitting…',
|
|
11666
|
+
// #A11Y7/U2 — staged uploads announce only their TRANSITIONS (start and
|
|
11667
|
+
// success), never per-tick progress: `aria-live="polite"` coalesces but does
|
|
11668
|
+
// not throttle, and one announcement per onprogress event would bury every
|
|
11669
|
+
// other message on the page. There is deliberately NO `uploadError` key —
|
|
11670
|
+
// the error path announces the server's own message instead (#A11Y7/U3), and
|
|
11671
|
+
// a generic second write in the same beat would clobber it (see the rationale
|
|
11672
|
+
// on `releaseSubmitA11y`).
|
|
11673
|
+
uploadStarted : 'Upload started',
|
|
11674
|
+
uploadComplete : 'Upload complete',
|
|
11675
|
+
// #A11Y7/U5 — spoken when a staged file's reset/delete control removes it.
|
|
11676
|
+
fileRemoved : '%s removed'
|
|
11677
|
+
};
|
|
11678
|
+
|
|
11679
|
+
/**
|
|
11680
|
+
* a11yLabel — resolve one accessibility status string.
|
|
11681
|
+
*
|
|
11682
|
+
* Follows the same philosophy `setErrorLabels` documents: an English default
|
|
11683
|
+
* ships inline and fills anything the project does not translate. A project
|
|
11684
|
+
* overrides by assigning `gina.config.a11y`, typically once at boot keyed off
|
|
11685
|
+
* the negotiated culture.
|
|
11686
|
+
*
|
|
11687
|
+
* @param {string} key - Label key, e.g. `submitting`.
|
|
11688
|
+
* @returns {string} the project's override when it supplies a non-empty string,
|
|
11689
|
+
* otherwise the English default (empty string for unknown keys).
|
|
11690
|
+
*
|
|
11691
|
+
* @example
|
|
11692
|
+
* // project side, once at boot:
|
|
11693
|
+
* gina.config.a11y = { submitting: 'Envoi…' };
|
|
11694
|
+
*
|
|
11695
|
+
* @inner
|
|
11696
|
+
*/
|
|
11697
|
+
var a11yLabel = function(key) {
|
|
11698
|
+
var _over = ( typeof(gina) != 'undefined' && gina && gina.config && gina.config.a11y )
|
|
11699
|
+
? gina.config.a11y
|
|
11700
|
+
: null;
|
|
11701
|
+
if ( _over && typeof(_over[key]) == 'string' && _over[key] ) {
|
|
11702
|
+
return _over[key];
|
|
11703
|
+
}
|
|
11704
|
+
return A11Y_LABELS[key] || '';
|
|
11705
|
+
};
|
|
11706
|
+
|
|
11707
|
+
/**
|
|
11708
|
+
* announceA11yStatus — announce a non-error status through the form's region.
|
|
11709
|
+
*
|
|
11710
|
+
* The region #A11Y2 stands up at bind time is `role="status" aria-live="polite"`,
|
|
11711
|
+
* i.e. already a status channel rather than an error-only one — so submit progress
|
|
11712
|
+
* rides that same element instead of a second region competing with it. Kept as a
|
|
11713
|
+
* named delegate purely so call sites read as status, not as errors.
|
|
11714
|
+
*
|
|
11715
|
+
* @param {object} $form - form target (HTMLFormElement), not the form instance.
|
|
11716
|
+
* @param {string} text - resolved, human-readable status text.
|
|
11717
|
+
* @returns {object|null} the live region, or null when it could not be resolved.
|
|
11718
|
+
*
|
|
11719
|
+
* @example
|
|
11720
|
+
* announceA11yStatus($myForm, 'Envoi…');
|
|
11721
|
+
*
|
|
11722
|
+
* @inner
|
|
11723
|
+
*/
|
|
11724
|
+
var announceA11yStatus = function($form, text) {
|
|
11725
|
+
return announceA11yError($form, text);
|
|
11726
|
+
};
|
|
11727
|
+
|
|
11728
|
+
/**
|
|
11729
|
+
* a11yDistinctText — make a repeated announcement observably new.
|
|
11730
|
+
*
|
|
11731
|
+
* An `aria-live="polite"` region is announced when its content CHANGES, so re-writing
|
|
11732
|
+
* byte-identical text is commonly not spoken at all. That is the normal case for a
|
|
11733
|
+
* validation message: blurring a field that still fails the same rule produces exactly
|
|
11734
|
+
* the same string, and the user heard nothing the second time. Appending a no-break
|
|
11735
|
+
* space makes the node's content differ while leaving what is read out unchanged, and
|
|
11736
|
+
* it self-cancels — the next identical announcement compares against the suffixed text,
|
|
11737
|
+
* differs, and writes the clean string again.
|
|
11738
|
+
*
|
|
11739
|
+
* Lives outside `announceA11yError` deliberately: that function sits inside a fixed
|
|
11740
|
+
* character window asserted by a source pin, and the rationale above does not fit in it.
|
|
11741
|
+
*
|
|
11742
|
+
* ⚠️ Unverified: that a screen reader actually re-announces as a result. The string
|
|
11743
|
+
* demonstrably changes; no assistive-technology pass has been run to confirm the effect.
|
|
11744
|
+
*
|
|
11745
|
+
* @param {object} $live - the live region node.
|
|
11746
|
+
* @param {string} text - the announcement about to be written.
|
|
11747
|
+
* @returns {string} `text`, suffixed only when it would otherwise be a no-op write.
|
|
11748
|
+
*
|
|
11749
|
+
* @example
|
|
11750
|
+
* var next = a11yDistinctText($region, 'This field is required');
|
|
11751
|
+
*
|
|
11752
|
+
* @inner
|
|
11753
|
+
*/
|
|
11754
|
+
var a11yDistinctText = function($live, text) {
|
|
11755
|
+
if ( !$live || typeof(text) != 'string' ) {
|
|
11756
|
+
return text;
|
|
11757
|
+
}
|
|
11758
|
+
return ( $live.textContent === text ) ? text + ' ' : text;
|
|
11759
|
+
};
|
|
11760
|
+
|
|
11761
|
+
/**
|
|
11762
|
+
* ERR_MSG_CLIP — inline declarations that hide an element from VIEW while leaving it
|
|
11763
|
+
* in the accessibility tree.
|
|
11764
|
+
*
|
|
11765
|
+
* `display` carries `!important` because gina's own `.hidden` helper is
|
|
11766
|
+
* `display: none !important`, and an inline `!important` is what outranks it (measured:
|
|
11767
|
+
* a plain inline `display:block` loses to it). The class is deliberately left in place
|
|
11768
|
+
* so consumer CSS keyed on `.hidden` keeps matching.
|
|
11769
|
+
*
|
|
11770
|
+
* @constant {string}
|
|
11771
|
+
* @inner
|
|
11772
|
+
*/
|
|
11773
|
+
var ERR_MSG_CLIP = 'display:block !important;position:absolute;width:1px;height:1px;'
|
|
11774
|
+
+ 'margin:-1px;padding:0;overflow:hidden;clip:rect(0 0 0 0);white-space:nowrap;border:0;';
|
|
11775
|
+
|
|
11776
|
+
/**
|
|
11777
|
+
* clipErrorMessage — hide a validation message visually, but keep it reachable.
|
|
11778
|
+
*
|
|
11779
|
+
* `.hidden` is `display: none !important`, which removes the node from the
|
|
11780
|
+
* accessibility tree outright. That is the wrong tool wherever `aria-invalid="true"`
|
|
11781
|
+
* stays asserted on the field, because the `aria-errormessage` association then points
|
|
11782
|
+
* assistive tech at a target it cannot resolve — the field is announced invalid with no
|
|
11783
|
+
* retrievable reason. Both hide paths that can coexist with an asserted `aria-invalid`
|
|
11784
|
+
* (the focus-driven hide in `refreshWarning`, and the refresh re-create) clip instead.
|
|
11785
|
+
*
|
|
11786
|
+
* gina creates and owns this element, so replacing `style.cssText` wholesale is safe.
|
|
11787
|
+
*
|
|
11788
|
+
* @param {object} $err - the `form-item-error-message` element.
|
|
11789
|
+
* @returns {boolean} true when the clip was applied.
|
|
11790
|
+
*
|
|
11791
|
+
* @example
|
|
11792
|
+
* clipErrorMessage($someMessageDiv);
|
|
11793
|
+
*
|
|
11794
|
+
* @inner
|
|
11795
|
+
*/
|
|
11796
|
+
var clipErrorMessage = function($err) {
|
|
11797
|
+
if ( !$err || typeof($err.style) == 'undefined' || !$err.style ) {
|
|
11798
|
+
return false;
|
|
11799
|
+
}
|
|
11800
|
+
$err.style.cssText = ERR_MSG_CLIP;
|
|
11801
|
+
return true;
|
|
11044
11802
|
};
|
|
11045
11803
|
|
|
11046
11804
|
/**
|
|
11047
|
-
*
|
|
11048
|
-
*
|
|
11049
|
-
*
|
|
11050
|
-
*
|
|
11051
|
-
*
|
|
11052
|
-
*
|
|
11805
|
+
* revealErrorMessage — undo `clipErrorMessage`, restoring normal visual flow.
|
|
11806
|
+
*
|
|
11807
|
+
* @param {object} $err - the `form-item-error-message` element.
|
|
11808
|
+
* @returns {boolean} true when the clip was cleared.
|
|
11809
|
+
*
|
|
11810
|
+
* @example
|
|
11811
|
+
* revealErrorMessage($someMessageDiv);
|
|
11812
|
+
*
|
|
11053
11813
|
* @inner
|
|
11054
|
-
* @param {object} $err - the error-message container element
|
|
11055
|
-
* @returns {string} announcement text
|
|
11056
11814
|
*/
|
|
11057
|
-
var
|
|
11058
|
-
|
|
11059
|
-
|
|
11060
|
-
return $err.textContent;
|
|
11061
|
-
}
|
|
11062
|
-
var parts = [];
|
|
11063
|
-
for (var m = 0, mLen = $msgs.length; m < mLen; ++m) {
|
|
11064
|
-
parts.push($msgs[m].textContent);
|
|
11815
|
+
var revealErrorMessage = function($err) {
|
|
11816
|
+
if ( !$err || typeof($err.style) == 'undefined' || !$err.style ) {
|
|
11817
|
+
return false;
|
|
11065
11818
|
}
|
|
11066
|
-
|
|
11819
|
+
$err.style.cssText = '';
|
|
11820
|
+
return true;
|
|
11067
11821
|
};
|
|
11068
11822
|
|
|
11069
11823
|
/**
|
|
@@ -11361,6 +12115,14 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11361
12115
|
// global pass, so without this focus guard it re-shows the message mid-typing.
|
|
11362
12116
|
// On blur (field no longer active) the message is created shown (focusout commits).
|
|
11363
12117
|
$err.setAttribute('class', ( document.activeElement && document.activeElement.name == name ) ? 'form-item-error-message hidden' : 'form-item-error-message');
|
|
12118
|
+
// #A11Y5 — the branch below re-asserts aria-invalid="true" on this same
|
|
12119
|
+
// field, so when the message is hidden it must stay resolvable: clip it
|
|
12120
|
+
// out of view rather than out of the accessibility tree. Reads the class
|
|
12121
|
+
// just written instead of re-deriving the condition, so the ternary above
|
|
12122
|
+
// stays exactly as pinned.
|
|
12123
|
+
if ( /hidden/.test($err.className) ) {
|
|
12124
|
+
clipErrorMessage($err);
|
|
12125
|
+
}
|
|
11364
12126
|
|
|
11365
12127
|
// #A11Y1 (slice 2) — preserve the aria-errormessage wire we own across refresh.
|
|
11366
12128
|
if ( _ginaOwnsErrMsg && _ariaErrId ) {
|
|
@@ -11690,6 +12452,231 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11690
12452
|
}
|
|
11691
12453
|
|
|
11692
12454
|
|
|
12455
|
+
/**
|
|
12456
|
+
* armSubmitLoading
|
|
12457
|
+
*
|
|
12458
|
+
* Marks `$trigger` as running (`data-gina-loading="true"`, or whatever
|
|
12459
|
+
* `gina.config.loadingAttribute` names) and remembers it on the form instance so
|
|
12460
|
+
* every terminal path can release it — including the ones that never reach an
|
|
12461
|
+
* XHR and therefore have no `$submitTrigger` of their own in scope.
|
|
12462
|
+
*
|
|
12463
|
+
* The element is stashed rather than re-derived because the two are NOT always
|
|
12464
|
+
* the same: `send()` resolves `$submitTrigger` once from `$form.submitTrigger`
|
|
12465
|
+
* (an id) at its own entry, which a rejected submit never reaches, and which a
|
|
12466
|
+
* second click on a different button would have overwritten by then. The stash
|
|
12467
|
+
* is a single reference per form, replaced on each arm and nulled on disarm, so
|
|
12468
|
+
* it can not retain a detached node past the submit that created it.
|
|
12469
|
+
*
|
|
12470
|
+
* @param {object} $formInstance - the form instance (`instance.$forms[id]`)
|
|
12471
|
+
* @param {object} $trigger - the element the user operated
|
|
12472
|
+
*
|
|
12473
|
+
* @returns {boolean} true when the trigger was marked
|
|
12474
|
+
*
|
|
12475
|
+
* FIRST ARM WINS until the state is released. A form runs one submit at a time — that
|
|
12476
|
+
* is what `withRateLimit` enforces — so a second attempt arriving mid-flight is about
|
|
12477
|
+
* to be refused, and must not take ownership: on a form with several submit buttons it
|
|
12478
|
+
* would move the stash to the refused trigger, leaving the trigger that actually owns
|
|
12479
|
+
* the request armed with nothing left to release it.
|
|
12480
|
+
*
|
|
12481
|
+
* @example
|
|
12482
|
+
* armSubmitLoading(instance.$forms[$form.id], loadingState.resolveTrigger($el, $target));
|
|
12483
|
+
*
|
|
12484
|
+
* @inner
|
|
12485
|
+
*/
|
|
12486
|
+
var armSubmitLoading = function($formInstance, $trigger) {
|
|
12487
|
+
if ( !$formInstance || !$trigger ) {
|
|
12488
|
+
return false;
|
|
12489
|
+
}
|
|
12490
|
+
if ($formInstance.loadingTrigger) {
|
|
12491
|
+
return false;
|
|
12492
|
+
}
|
|
12493
|
+
$formInstance.loadingTrigger = $trigger;
|
|
12494
|
+
return loadingState.arm($trigger);
|
|
12495
|
+
};
|
|
12496
|
+
|
|
12497
|
+
/**
|
|
12498
|
+
* disarmSubmitLoading
|
|
12499
|
+
*
|
|
12500
|
+
* Releases whatever `armSubmitLoading` marked for this form
|
|
12501
|
+
* (`data-gina-loading="false"`) and drops the stash. Idempotent and safe to call
|
|
12502
|
+
* on a form that was never armed — every terminal path calls it unconditionally
|
|
12503
|
+
* rather than trying to work out whether arming happened.
|
|
12504
|
+
*
|
|
12505
|
+
* #B247: the validation-rejected path is the one that stranded consumer loading
|
|
12506
|
+
* state, because a rejected submit sends nothing and so never reaches any XHR
|
|
12507
|
+
* settle. `send()`'s rate-limit early return is the same shape and is covered
|
|
12508
|
+
* too; `loadend` covers success, error, timeout and abort alike.
|
|
12509
|
+
*
|
|
12510
|
+
* @param {object} $formInstance - the form instance (`instance.$forms[id]`)
|
|
12511
|
+
*
|
|
12512
|
+
* @returns {boolean} true when a marked trigger was released
|
|
12513
|
+
*
|
|
12514
|
+
* @example
|
|
12515
|
+
* disarmSubmitLoading(instance.$forms[_id]); // on reject, settle, timeout or abort
|
|
12516
|
+
*
|
|
12517
|
+
* @inner
|
|
12518
|
+
*/
|
|
12519
|
+
var disarmSubmitLoading = function($formInstance) {
|
|
12520
|
+
if ( !$formInstance || !$formInstance.loadingTrigger ) {
|
|
12521
|
+
return false;
|
|
12522
|
+
}
|
|
12523
|
+
var released = loadingState.disarm($formInstance.loadingTrigger);
|
|
12524
|
+
$formInstance.loadingTrigger = null;
|
|
12525
|
+
return released;
|
|
12526
|
+
};
|
|
12527
|
+
|
|
12528
|
+
/**
|
|
12529
|
+
* holdTriggerFocus — remember the submit trigger gina is about to blur.
|
|
12530
|
+
*
|
|
12531
|
+
* A natively `disabled` control cannot hold focus: the instant gina disables an
|
|
12532
|
+
* in-flight submit trigger the browser moves focus to `<body>`, and re-enabling
|
|
12533
|
+
* does not bring it back (both measured). Every keyboard submit therefore loses
|
|
12534
|
+
* the user's place. Only the native-`disabled` branch is recorded — an `<a>`
|
|
12535
|
+
* receives `aria-disabled`, which does not blur (measured), so it needs no restore.
|
|
12536
|
+
*
|
|
12537
|
+
* @param {object} $form - the form instance, which carries the stash.
|
|
12538
|
+
* @param {object} $trigger - resolved submit trigger; may be null.
|
|
12539
|
+
* @returns {boolean} true when focus was captured for a later restore.
|
|
12540
|
+
*
|
|
12541
|
+
* @example
|
|
12542
|
+
* holdTriggerFocus($myFormInstance, $mySaveButton);
|
|
12543
|
+
*
|
|
12544
|
+
* @inner
|
|
12545
|
+
*/
|
|
12546
|
+
var holdTriggerFocus = function($form, $trigger) {
|
|
12547
|
+
if ( !$form || !$trigger ) {
|
|
12548
|
+
return false;
|
|
12549
|
+
}
|
|
12550
|
+
if ( typeof(document) === 'undefined' || !document ) {
|
|
12551
|
+
return false;
|
|
12552
|
+
}
|
|
12553
|
+
if ( document.activeElement !== $trigger ) {
|
|
12554
|
+
return false;
|
|
12555
|
+
}
|
|
12556
|
+
$form.ginaA11yFocusReturn = $trigger;
|
|
12557
|
+
return true;
|
|
12558
|
+
};
|
|
12559
|
+
|
|
12560
|
+
/**
|
|
12561
|
+
* releaseTriggerFocus — put focus back on the trigger gina blurred.
|
|
12562
|
+
*
|
|
12563
|
+
* Deliberately conservative: it restores ONLY when focus is still exactly where
|
|
12564
|
+
* the disable dropped it (`<body>`) and the trigger is still in the document. If
|
|
12565
|
+
* anything else claimed focus while the request was in flight — a popin opened, a
|
|
12566
|
+
* redirect ran, the failed-submit branch moved focus to the first invalid field —
|
|
12567
|
+
* that decision wins and gina undoes nothing. gina restores what gina took, never
|
|
12568
|
+
* more.
|
|
12569
|
+
*
|
|
12570
|
+
* @param {object} $form - the form instance holding the stash.
|
|
12571
|
+
* @returns {boolean} true when focus was actually restored.
|
|
12572
|
+
*
|
|
12573
|
+
* @example
|
|
12574
|
+
* releaseTriggerFocus($myFormInstance);
|
|
12575
|
+
*
|
|
12576
|
+
* @inner
|
|
12577
|
+
*/
|
|
12578
|
+
var releaseTriggerFocus = function($form) {
|
|
12579
|
+
if ( !$form || !$form.ginaA11yFocusReturn ) {
|
|
12580
|
+
return false;
|
|
12581
|
+
}
|
|
12582
|
+
var $trigger = $form.ginaA11yFocusReturn;
|
|
12583
|
+
$form.ginaA11yFocusReturn = null;
|
|
12584
|
+
if ( typeof(document) === 'undefined' || !document ) {
|
|
12585
|
+
return false;
|
|
12586
|
+
}
|
|
12587
|
+
// Nothing else may have claimed focus in the meantime.
|
|
12588
|
+
if ( document.activeElement && document.activeElement !== document.body ) {
|
|
12589
|
+
return false;
|
|
12590
|
+
}
|
|
12591
|
+
var _stillThere = ( typeof($trigger.isConnected) == 'boolean' )
|
|
12592
|
+
? $trigger.isConnected
|
|
12593
|
+
: ( document.body && document.body.contains($trigger) );
|
|
12594
|
+
if ( !_stillThere || typeof($trigger.focus) != 'function' ) {
|
|
12595
|
+
return false;
|
|
12596
|
+
}
|
|
12597
|
+
$trigger.focus();
|
|
12598
|
+
return true;
|
|
12599
|
+
};
|
|
12600
|
+
|
|
12601
|
+
/**
|
|
12602
|
+
* armSubmitA11y — expose an in-flight submit to assistive technology.
|
|
12603
|
+
*
|
|
12604
|
+
* Three things at once, all scoped to the request window: capture the trigger's
|
|
12605
|
+
* focus before the caller's native disable blurs it, mark the trigger busy, and
|
|
12606
|
+
* announce the start once through the form's polite region.
|
|
12607
|
+
*
|
|
12608
|
+
* Two placement decisions worth keeping:
|
|
12609
|
+
* - `aria-busy` goes on the TRIGGER, never the form. The live region lives inside
|
|
12610
|
+
* the form, and an ancestor marked busy MAY be treated as "defer announcements in
|
|
12611
|
+
* this subtree", which would silence the very region used to announce. ARIA 1.2
|
|
12612
|
+
* defines no normative behaviour here, so this is a cheap hedge, not a spec
|
|
12613
|
+
* requirement — and it is explicitly NOT a claim about what implementations do:
|
|
12614
|
+
* measured 2026-08-05 on VoiceOver/Chrome, an announcement from inside an
|
|
12615
|
+
* `aria-busy="true"` ancestor WAS spoken, so at least that pairing does not defer.
|
|
12616
|
+
* The placement costs nothing and still guards ATs that might; do not restate it
|
|
12617
|
+
* as "assistive tech commonly defers" — that wording was wrong and was corrected.
|
|
12618
|
+
* - This window is only ever reached once a request is genuinely in flight, so a
|
|
12619
|
+
* validation-rejected submit never arms and never announces. That is what keeps
|
|
12620
|
+
* the arm-before-validate loading state from producing a busy/not-busy flap.
|
|
12621
|
+
*
|
|
12622
|
+
* @param {object} $form - the form instance.
|
|
12623
|
+
* @param {object} $trigger - resolved submit trigger; may be null.
|
|
12624
|
+
* @returns {boolean} true when this call produced the announcement.
|
|
12625
|
+
*
|
|
12626
|
+
* @example
|
|
12627
|
+
* armSubmitA11y($myFormInstance, $mySaveButton);
|
|
12628
|
+
*
|
|
12629
|
+
* @inner
|
|
12630
|
+
*/
|
|
12631
|
+
var armSubmitA11y = function($form, $trigger) {
|
|
12632
|
+
if ( !$form ) {
|
|
12633
|
+
return false;
|
|
12634
|
+
}
|
|
12635
|
+
if ($trigger) {
|
|
12636
|
+
if ( !/^A$/i.test($trigger.tagName) ) {
|
|
12637
|
+
holdTriggerFocus($form, $trigger);
|
|
12638
|
+
}
|
|
12639
|
+
$trigger.setAttribute('aria-busy', 'true');
|
|
12640
|
+
}
|
|
12641
|
+
// readyState 1 and 3 both reach here; announce once per request.
|
|
12642
|
+
if ( $form.ginaA11yBusy ) {
|
|
12643
|
+
return false;
|
|
12644
|
+
}
|
|
12645
|
+
$form.ginaA11yBusy = true;
|
|
12646
|
+
if ( $form.target ) {
|
|
12647
|
+
announceA11yStatus($form.target, a11yLabel('submitting'));
|
|
12648
|
+
}
|
|
12649
|
+
return true;
|
|
12650
|
+
};
|
|
12651
|
+
|
|
12652
|
+
/**
|
|
12653
|
+
* releaseSubmitA11y — clear the in-flight submit exposure.
|
|
12654
|
+
*
|
|
12655
|
+
* Idempotent, because both the readyState-4 release and the `loadend` fail-safe
|
|
12656
|
+
* run it. Deliberately announces nothing on completion: an errored response is
|
|
12657
|
+
* already announced field-by-field by `handleErrorsDisplay`, and writing a second
|
|
12658
|
+
* status over a polite region in the same beat can cut that announcement off.
|
|
12659
|
+
*
|
|
12660
|
+
* @param {object} $form - the form instance.
|
|
12661
|
+
* @param {object} $trigger - resolved submit trigger; may be null.
|
|
12662
|
+
* @returns {boolean} true when focus was restored to the trigger.
|
|
12663
|
+
*
|
|
12664
|
+
* @example
|
|
12665
|
+
* releaseSubmitA11y($myFormInstance, $mySaveButton);
|
|
12666
|
+
*
|
|
12667
|
+
* @inner
|
|
12668
|
+
*/
|
|
12669
|
+
var releaseSubmitA11y = function($form, $trigger) {
|
|
12670
|
+
if ( !$form ) {
|
|
12671
|
+
return false;
|
|
12672
|
+
}
|
|
12673
|
+
if ($trigger) {
|
|
12674
|
+
$trigger.removeAttribute('aria-busy');
|
|
12675
|
+
}
|
|
12676
|
+
$form.ginaA11yBusy = false;
|
|
12677
|
+
return releaseTriggerFocus($form);
|
|
12678
|
+
};
|
|
12679
|
+
|
|
11693
12680
|
/**
|
|
11694
12681
|
* send
|
|
11695
12682
|
* N.B.: no validation here; if you want to validate against rules, use `.submit()` or `.validateFormById(formId)` before
|
|
@@ -11724,6 +12711,11 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11724
12711
|
&& typeof($form.sent) != 'undefined'
|
|
11725
12712
|
&& /^true$/i.test($form.sent)
|
|
11726
12713
|
) {
|
|
12714
|
+
// #B247 — deliberately NO loading-state release here. This return means a
|
|
12715
|
+
// request for this form is already in flight, so the trigger that owns it is
|
|
12716
|
+
// still legitimately loading and its own settle will release it. Releasing
|
|
12717
|
+
// here would clear the state mid-request; and because `armSubmitLoading` is
|
|
12718
|
+
// first-wins, the refused attempt never armed anything of its own to clear.
|
|
11727
12719
|
return;
|
|
11728
12720
|
}
|
|
11729
12721
|
|
|
@@ -11879,12 +12871,20 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11879
12871
|
}
|
|
11880
12872
|
}
|
|
11881
12873
|
$form.target.removeAttribute('data-gina-form-loading');
|
|
12874
|
+
// #B247 — the trigger-scoped release rides the same fail-safe:
|
|
12875
|
+
// `loadend` is the one hook that covers abort and error too.
|
|
12876
|
+
disarmSubmitLoading($form);
|
|
12877
|
+
// #A11Y4 — last, so focus lands on a trigger that is fully settled:
|
|
12878
|
+
// re-enabled above and no longer flagged loading.
|
|
12879
|
+
releaseSubmitA11y($form, $submitTrigger);
|
|
11882
12880
|
});
|
|
11883
12881
|
}
|
|
11884
12882
|
// catching ready state cb
|
|
11885
12883
|
// Data loading ...
|
|
11886
12884
|
if ( /^(1|3)$/.test(xhr.readyState) ) {
|
|
11887
12885
|
$form.target.setAttribute('data-gina-form-loading', true);
|
|
12886
|
+
// #A11Y4 — must run BEFORE the native disable below, which blurs the trigger.
|
|
12887
|
+
armSubmitA11y($form, $submitTrigger);
|
|
11888
12888
|
if ($submitTrigger) {
|
|
11889
12889
|
// For A tag: aria-disabled=true
|
|
11890
12890
|
if ( /^A$/i.test($submitTrigger.tagName) ) {
|
|
@@ -11913,6 +12913,8 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11913
12913
|
// Data loading ...
|
|
11914
12914
|
if ( /^(1|3)$/.test(xhr.readyState) ) {
|
|
11915
12915
|
$form.target.setAttribute('data-gina-form-loading', true);
|
|
12916
|
+
// #A11Y4 — must run BEFORE the native disable below, which blurs the trigger.
|
|
12917
|
+
armSubmitA11y($form, $submitTrigger);
|
|
11916
12918
|
if ($submitTrigger) {
|
|
11917
12919
|
// For A tag: aria-disabled=true
|
|
11918
12920
|
if ( /^A$/i.test($submitTrigger.tagName) ) {
|
|
@@ -11947,6 +12949,11 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
11947
12949
|
}
|
|
11948
12950
|
}
|
|
11949
12951
|
$form.target.removeAttribute('data-gina-form-loading');
|
|
12952
|
+
// #B247 — idempotent with the `loadend` release above
|
|
12953
|
+
disarmSubmitLoading($form);
|
|
12954
|
+
// #A11Y4 — last, so focus lands on a fully settled trigger; idempotent
|
|
12955
|
+
// with the `loadend` release, which may already have restored it.
|
|
12956
|
+
releaseSubmitA11y($form, $submitTrigger);
|
|
11950
12957
|
|
|
11951
12958
|
var $popin = null;
|
|
11952
12959
|
var blob = null;
|
|
@@ -12725,7 +13732,16 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12725
13732
|
* computable) so the browser renders its native indeterminate animation;
|
|
12726
13733
|
* `error` empties the bar (value 0 — NOT indeterminate, whose animation
|
|
12727
13734
|
* would read as still working)
|
|
12728
|
-
* - any other element: `textContent` shows the integer percentage (`42%`)
|
|
13735
|
+
* - any other element: `textContent` shows the integer percentage (`42%`), and
|
|
13736
|
+
* `role="progressbar"` + `aria-valuemin="0"` / `aria-valuemax="100"` /
|
|
13737
|
+
* `aria-valuenow="<percent>"` give it the semantics a native `<progress>` gets
|
|
13738
|
+
* for free (#A11Y7/U2 — without them the indicator is unlabelled text to
|
|
13739
|
+
* assistive tech). `aria-valuenow` tracks `data-gina-upload-progress` exactly:
|
|
13740
|
+
* both are ABSENT while indeterminate and on `error`, because an absent
|
|
13741
|
+
* `aria-valuenow` is how a progressbar signals "unknown" — a stale or zero
|
|
13742
|
+
* value would read as real, stalled progress. A native `<progress>` is left
|
|
13743
|
+
* untouched: it already exposes all of this, and a redundant explicit role
|
|
13744
|
+
* risks overriding the implicit one.
|
|
12729
13745
|
*
|
|
12730
13746
|
* Every target also carries two data attributes as styling hooks:
|
|
12731
13747
|
* `data-gina-upload-progress` (integer percent, absent while indeterminate)
|
|
@@ -12761,10 +13777,28 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12761
13777
|
}
|
|
12762
13778
|
$indicator.removeAttribute('data-gina-upload-progress');
|
|
12763
13779
|
$indicator.removeAttribute('data-gina-upload-progress-state');
|
|
13780
|
+
// #A11Y7/U2 — `reset` strips everything this layer ever set, and the ARIA
|
|
13781
|
+
// below is part of "everything": leaving a stale `role="progressbar"` on a
|
|
13782
|
+
// cleared element would expose a permanently 0%-looking bar to assistive tech.
|
|
13783
|
+
if (!isNativeProgress) {
|
|
13784
|
+
$indicator.removeAttribute('role');
|
|
13785
|
+
$indicator.removeAttribute('aria-valuemin');
|
|
13786
|
+
$indicator.removeAttribute('aria-valuemax');
|
|
13787
|
+
$indicator.removeAttribute('aria-valuenow');
|
|
13788
|
+
}
|
|
12764
13789
|
return;
|
|
12765
13790
|
}
|
|
12766
13791
|
|
|
12767
13792
|
$indicator.setAttribute('data-gina-upload-progress-state', state);
|
|
13793
|
+
// #A11Y7/U2 — a native <progress> already carries implicit progressbar
|
|
13794
|
+
// semantics (and its own value/max), so it is deliberately left alone; every
|
|
13795
|
+
// other element is text with no role at all until we give it one. The bounds
|
|
13796
|
+
// are constant because `data-gina-upload-progress` is already a percentage.
|
|
13797
|
+
if (!isNativeProgress) {
|
|
13798
|
+
$indicator.setAttribute('role', 'progressbar');
|
|
13799
|
+
$indicator.setAttribute('aria-valuemin', '0');
|
|
13800
|
+
$indicator.setAttribute('aria-valuemax', '100');
|
|
13801
|
+
}
|
|
12768
13802
|
|
|
12769
13803
|
if (state == 'processing') {
|
|
12770
13804
|
// #R8 — byte-complete, server still post-processing. Advance the STATE only:
|
|
@@ -12786,6 +13820,9 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12786
13820
|
$indicator.textContent = '100%';
|
|
12787
13821
|
}
|
|
12788
13822
|
$indicator.setAttribute('data-gina-upload-progress', 100);
|
|
13823
|
+
if (!isNativeProgress) {
|
|
13824
|
+
$indicator.setAttribute('aria-valuenow', '100');
|
|
13825
|
+
}
|
|
12789
13826
|
return;
|
|
12790
13827
|
}
|
|
12791
13828
|
|
|
@@ -12799,6 +13836,13 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12799
13836
|
$indicator.textContent = '';
|
|
12800
13837
|
}
|
|
12801
13838
|
$indicator.removeAttribute('data-gina-upload-progress');
|
|
13839
|
+
// #A11Y7/U2 — an errored bar is EMPTY, not indeterminate (the native branch
|
|
13840
|
+
// above says the same about `value`): drop `aria-valuenow` so assistive tech
|
|
13841
|
+
// reports an unknown state rather than a confident 0% that reads as "no
|
|
13842
|
+
// progress yet, still working".
|
|
13843
|
+
if (!isNativeProgress) {
|
|
13844
|
+
$indicator.removeAttribute('aria-valuenow');
|
|
13845
|
+
}
|
|
12802
13846
|
return;
|
|
12803
13847
|
}
|
|
12804
13848
|
|
|
@@ -12807,6 +13851,12 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12807
13851
|
$indicator.removeAttribute('value'); // native indeterminate animation
|
|
12808
13852
|
}
|
|
12809
13853
|
$indicator.removeAttribute('data-gina-upload-progress');
|
|
13854
|
+
// #A11Y7/U2 — mirrors the `value` removal above: an absent `aria-valuenow`
|
|
13855
|
+
// on a progressbar IS the indeterminate signal, so this must track the
|
|
13856
|
+
// percent attribute exactly rather than reporting a stale last-known value.
|
|
13857
|
+
if (!isNativeProgress) {
|
|
13858
|
+
$indicator.removeAttribute('aria-valuenow');
|
|
13859
|
+
}
|
|
12810
13860
|
return;
|
|
12811
13861
|
}
|
|
12812
13862
|
|
|
@@ -12816,6 +13866,7 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
12816
13866
|
$indicator.value = result.loaded;
|
|
12817
13867
|
} else {
|
|
12818
13868
|
$indicator.textContent = result.progress + '%';
|
|
13869
|
+
$indicator.setAttribute('aria-valuenow', result.progress);
|
|
12819
13870
|
}
|
|
12820
13871
|
$indicator.setAttribute('data-gina-upload-progress', result.progress);
|
|
12821
13872
|
};
|
|
@@ -13030,9 +14081,27 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13030
14081
|
|
|
13031
14082
|
$error.innerHTML = '<p>'+ errMsg +'</p>';
|
|
13032
14083
|
fadeIn($error);
|
|
14084
|
+
// #A11Y7/U3 — the container is `display:none` when the text is written and
|
|
14085
|
+
// only revealed by the fadeIn above, which is exactly the case where a
|
|
14086
|
+
// `role="alert"` on it is unreliable; route through the form's own polite
|
|
14087
|
+
// region instead — the same channel field validation errors already use.
|
|
14088
|
+
// Announce the RENDERED text, not `errMsg`: the message can carry markup
|
|
14089
|
+
// (the url-action checker substitutes `<br>`), and textContent is what a
|
|
14090
|
+
// user would actually read.
|
|
14091
|
+
if ( $uploadTriger && $uploadTriger.form ) {
|
|
14092
|
+
announceA11yError($uploadTriger.form, $error.textContent);
|
|
14093
|
+
}
|
|
13033
14094
|
} else if(!$error && status != 'success') {
|
|
13034
14095
|
throw new Error(errMsg)
|
|
13035
14096
|
} else {
|
|
14097
|
+
// #A11Y7/U2 — success is the other end of the `uploadStarted` transition.
|
|
14098
|
+
// It lives in this branch rather than at the indicator chokepoint above so
|
|
14099
|
+
// it can never fire alongside the error announcement and overwrite it: a
|
|
14100
|
+
// polite region is latest-wins, and a generic "complete" landing on top of
|
|
14101
|
+
// a specific server message would lose the message.
|
|
14102
|
+
if ( $uploadTriger && $uploadTriger.form ) {
|
|
14103
|
+
announceA11yStatus($uploadTriger.form, a11yLabel('uploadComplete'));
|
|
14104
|
+
}
|
|
13036
14105
|
|
|
13037
14106
|
var fieldsObjectList = null
|
|
13038
14107
|
, $li = null
|
|
@@ -13046,11 +14115,12 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13046
14115
|
let resetLinkNeedToBeAdded = false;
|
|
13047
14116
|
let $resetLink = document.getElementById(resetLinkId);
|
|
13048
14117
|
let defaultClassNameArr = ['reset','js-upload-reset'];
|
|
14118
|
+
let resetLabel = $uploadTriger.getAttribute('data-gina-form-upload-reset-label') || 'Reset';
|
|
13049
14119
|
if (!$resetLink) {
|
|
13050
14120
|
resetLinkNeedToBeAdded = true;
|
|
13051
14121
|
$resetLink = document.createElement('A');
|
|
13052
14122
|
$resetLink.href = '#';
|
|
13053
|
-
$resetLink.innerHTML =
|
|
14123
|
+
$resetLink.innerHTML = resetLabel;
|
|
13054
14124
|
$resetLink.className = defaultClassNameArr.join(' ');
|
|
13055
14125
|
$resetLink.id = resetLinkId;
|
|
13056
14126
|
} else {
|
|
@@ -13058,7 +14128,7 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13058
14128
|
$resetLink.href = '#';
|
|
13059
14129
|
}
|
|
13060
14130
|
if ( !$resetLink.innerHTML || $resetLink.innerHTML == '' ) {
|
|
13061
|
-
$resetLink.innerHTML =
|
|
14131
|
+
$resetLink.innerHTML = resetLabel;
|
|
13062
14132
|
}
|
|
13063
14133
|
if ( typeof($resetLink.className) == 'undefined' ) {
|
|
13064
14134
|
$resetLink.className = "";
|
|
@@ -13066,6 +14136,27 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13066
14136
|
let classNameArr = merge($resetLink.className.split(/\s+/g), defaultClassNameArr);
|
|
13067
14137
|
$resetLink.className = classNameArr.join(' ');
|
|
13068
14138
|
}
|
|
14139
|
+
// #A11Y7/U5 — the control gina generates is an anchor, so assistive tech
|
|
14140
|
+
// announces it as a link and Space does not activate it. Give it button
|
|
14141
|
+
// semantics; the matching Space handler lives with the click binding in
|
|
14142
|
+
// `bindUploadResetOrDeleteTrigger`, because a role that PROMISES button
|
|
14143
|
+
// behaviour without delivering the key is worse than no role at all.
|
|
14144
|
+
// Stamped only on an anchor: a consumer supplying their own <button> under
|
|
14145
|
+
// this id already has the right semantics, and overriding an implicit role
|
|
14146
|
+
// is a regression. Strict `/^a$/i` here, unlike the loose `/a/i` guarding
|
|
14147
|
+
// `href` above (that one also matches TEXTAREA, CANVAS, LABEL…).
|
|
14148
|
+
if ( /^a$/i.test($resetLink.tagName) ) {
|
|
14149
|
+
$resetLink.setAttribute('role', 'button');
|
|
14150
|
+
// The accessible name names the file it acts on: these controls stack
|
|
14151
|
+
// one per staged file and are otherwise identical, so a controls list
|
|
14152
|
+
// reads "Reset, Reset, Reset". The visible label stays the PREFIX so
|
|
14153
|
+
// the name still contains it (WCAG 2.5.3 Label in Name), and it reuses
|
|
14154
|
+
// the consumer's own `-reset-label`, so it is translated wherever that
|
|
14155
|
+
// already is.
|
|
14156
|
+
if ( files[f].originalFilename ) {
|
|
14157
|
+
$resetLink.setAttribute('aria-label', resetLabel + ' ' + files[f].originalFilename);
|
|
14158
|
+
}
|
|
14159
|
+
}
|
|
13069
14160
|
$resetLink.style.display = 'none';
|
|
13070
14161
|
|
|
13071
14162
|
// image preview
|
|
@@ -13076,6 +14167,12 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13076
14167
|
) {
|
|
13077
14168
|
let $img = document.createElement('IMG');
|
|
13078
14169
|
$img.src = files[f].tmpUri;
|
|
14170
|
+
// #A11Y7/U1 — the preview tells the user WHICH file is staged, so it is
|
|
14171
|
+
// informative content, not decoration; without a text alternative assistive
|
|
14172
|
+
// tech falls back to reading the temp URI aloud, once per staged file.
|
|
14173
|
+
// Empty string when the name is missing: a silently ignored image beats
|
|
14174
|
+
// announcing a placeholder.
|
|
14175
|
+
$img.alt = files[f].originalFilename || '';
|
|
13079
14176
|
$img.style.display = 'none';
|
|
13080
14177
|
$img.setAttribute('data-upload-original-filename', files[f].originalFilename);
|
|
13081
14178
|
$img.setAttribute('data-upload-reset-link-id', $resetLink.id);
|
|
@@ -13171,6 +14268,12 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13171
14268
|
// creating IMG tag
|
|
13172
14269
|
let $img = document.createElement('IMG');
|
|
13173
14270
|
$img.src = files[f][key].tmpUri;
|
|
14271
|
+
// #A11Y7/U1 — name the file the user actually chose, not the
|
|
14272
|
+
// server-generated preview variant recorded just below: the
|
|
14273
|
+
// generated name is an internal artefact and means nothing to
|
|
14274
|
+
// the person listening. Same empty-string fallback as the
|
|
14275
|
+
// no-preview branch.
|
|
14276
|
+
$img.alt = files[f].originalFilename || '';
|
|
13174
14277
|
$img.style.display = 'none';
|
|
13175
14278
|
// retrieve img `originalFilename` (not the preview img[key] `originalFilename`)
|
|
13176
14279
|
// these 2 metadatas will be used to remove files from the server
|
|
@@ -13411,6 +14514,39 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
13411
14514
|
// display upload input
|
|
13412
14515
|
restoreUploadAffordance($uploadTrigger, uploadHiddenClass);
|
|
13413
14516
|
|
|
14517
|
+
// #A11Y7/U5 — the control about to be removed is the one the user
|
|
14518
|
+
// just activated, so it holds focus; removing a focused element
|
|
14519
|
+
// drops focus to <body> and the user loses their place with no
|
|
14520
|
+
// signal. Move focus first, onto the file input that owns the
|
|
14521
|
+
// staged files — which `restoreUploadAffordance` just made visible
|
|
14522
|
+
// again. Guarded on it actually holding focus, so a programmatic
|
|
14523
|
+
// reset never yanks focus away from wherever the user really is.
|
|
14524
|
+
if ( document.activeElement === $resetLink || $resetLink.contains(document.activeElement) ) {
|
|
14525
|
+
if ( typeof($uploadTrigger.focus) == 'function' ) {
|
|
14526
|
+
$uploadTrigger.focus();
|
|
14527
|
+
}
|
|
14528
|
+
// #A11Y5's lesson, applied: `typeof focus == 'function'` is true
|
|
14529
|
+
// for EVERY HTMLElement, and focus() is a silent no-op on one
|
|
14530
|
+
// that cannot take focus (hidden, disabled, detached) — so
|
|
14531
|
+
// confirm the move instead of assuming it. Signal-only: there is
|
|
14532
|
+
// no better fallback than the document, and failing loudly here
|
|
14533
|
+
// would break a removal that otherwise succeeded.
|
|
14534
|
+
if ( document.activeElement !== $uploadTrigger ) {
|
|
14535
|
+
console.debug('[FormValidator][upload]['+ ($uploadTrigger.id || '?') +'] '+ bindingType +': could not move focus to the file input before removing the '+ bindingType +' control; focus falls back to the document.');
|
|
14536
|
+
}
|
|
14537
|
+
}
|
|
14538
|
+
// Announce the removal. `aria-live="polite"` queues rather than
|
|
14539
|
+
// interrupts, so this lands after the focus move above has been
|
|
14540
|
+
// announced instead of racing it. Function replacer, not a string:
|
|
14541
|
+
// a file name may contain `$`, and a string replacement would expand
|
|
14542
|
+
// `$&` / `$1` patterns inside it.
|
|
14543
|
+
if ( $uploadTrigger.form && childNodeFile ) {
|
|
14544
|
+
announceA11yStatus(
|
|
14545
|
+
$uploadTrigger.form,
|
|
14546
|
+
a11yLabel('fileRemoved').replace('%s', function () { return childNodeFile; })
|
|
14547
|
+
);
|
|
14548
|
+
}
|
|
14549
|
+
|
|
13414
14550
|
// remove link & image - must be done last
|
|
13415
14551
|
// (the reset/delete link's own click listener dies with the node)
|
|
13416
14552
|
$resetLink.remove();
|
|
@@ -15420,6 +16556,19 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
15420
16556
|
|
|
15421
16557
|
onUploadResetOrDelete($uploadTrigger, bindingType);
|
|
15422
16558
|
});
|
|
16559
|
+
// #A11Y7/U5 — the generated control is an anchor carrying `role="button"`,
|
|
16560
|
+
// and a button MUST activate on Space; an anchor natively answers Enter only,
|
|
16561
|
+
// so without this the role would advertise an interaction that does not work.
|
|
16562
|
+
// Anchors only: a real <button> already fires click on Space, and binding
|
|
16563
|
+
// this there would run the removal twice.
|
|
16564
|
+
if ( /^a$/i.test($uploadResetOrDeleteTrigger.tagName) ) {
|
|
16565
|
+
addListener(gina, $uploadResetOrDeleteTrigger, 'keydown', function onUploadResetOrDeleteTriggerKeydown(e) {
|
|
16566
|
+
if ( e.key === ' ' || e.keyCode === 32 ) {
|
|
16567
|
+
e.preventDefault(); // Space would otherwise scroll the page
|
|
16568
|
+
onUploadResetOrDelete($uploadTrigger, bindingType);
|
|
16569
|
+
}
|
|
16570
|
+
});
|
|
16571
|
+
}
|
|
15423
16572
|
$uploadResetOrDeleteTrigger.isBinded = true;
|
|
15424
16573
|
} else {
|
|
15425
16574
|
console.warn('[FormValidator::bindForm][upload]['+$uploadTrigger.id+'] : did not find `upload '+bindingType+' trigger`.\nPlease, make sure that your '+bindingType+' element ID is `'+ uploadResetOrDeleteTriggerId +'`, or add to your file input ('+ $uploadTrigger.id +') -> `data-gina-form-upload-'+bindingType+'-trigger="your-custom-id"` definition.');
|
|
@@ -15871,6 +17020,13 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
15871
17020
|
throw new Error('Validator::bindForm($target, customRule) could not bind form `'+ $target +'`\n'+err.stack );
|
|
15872
17021
|
}
|
|
15873
17022
|
|
|
17023
|
+
// #A11Y2 — stand the polite live region up HERE, at bind time, rather than lazily on the
|
|
17024
|
+
// first error. Creating and populating it in one tick reaches assistive tech as a single
|
|
17025
|
+
// mutation batch that is commonly never spoken, so the first announcement per form used to
|
|
17026
|
+
// be the one most likely lost. Every registration path funnels through bindForm, so this
|
|
17027
|
+
// one call covers them all. Announcing stays announceA11yError's job; this only creates.
|
|
17028
|
+
ensureA11yLiveRegion($target);
|
|
17029
|
+
|
|
15874
17030
|
// console.debug('binding for: '+ _id);
|
|
15875
17031
|
var withRules = false, rule = null, evt = '', proceed = null;
|
|
15876
17032
|
|
|
@@ -16619,6 +17775,24 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
16619
17775
|
updateUploadProgressIndicator($uploadForm.uploadProperties.progressContainer, 'preparing');
|
|
16620
17776
|
}
|
|
16621
17777
|
|
|
17778
|
+
// #A11Y7/U2 — announce the transition into "uploading". Note this
|
|
17779
|
+
// is deliberately NOT gated on `progressContainer`: the indicator is
|
|
17780
|
+
// opt-in by presence, but a user who cannot see it is precisely the
|
|
17781
|
+
// one who needs to be told the upload began.
|
|
17782
|
+
// The announcement targets the file input's REAL owning form, not
|
|
17783
|
+
// `$uploadForm` (the virtual one built just above): the real form is
|
|
17784
|
+
// where `bindForm` already stood up a live region, so upload status
|
|
17785
|
+
// and validation errors share one region instead of splitting across
|
|
17786
|
+
// two. Selection always sends today — the `.send()` below is
|
|
17787
|
+
// unconditional and `data-gina-file-autosend="false"` is still a TODO
|
|
17788
|
+
// — so this is a true start; gate it if that ever lands.
|
|
17789
|
+
if ( $uploadForm.uploadProperties && $uploadForm.uploadProperties.uploadTriggerId ) {
|
|
17790
|
+
var $a11yUploadInput = document.getElementById($uploadForm.uploadProperties.uploadTriggerId);
|
|
17791
|
+
if ( $a11yUploadInput && $a11yUploadInput.form ) {
|
|
17792
|
+
announceA11yStatus($a11yUploadInput.form, a11yLabel('uploadStarted'));
|
|
17793
|
+
}
|
|
17794
|
+
}
|
|
17795
|
+
|
|
16622
17796
|
// binding form
|
|
16623
17797
|
try {
|
|
16624
17798
|
var $uploadFormValidator = getFormById(uploadFormId);
|
|
@@ -17544,6 +18718,44 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17544
18718
|
_evt = 'reset.'+_evt
|
|
17545
18719
|
}
|
|
17546
18720
|
|
|
18721
|
+
// #B246 — a disabled submit trigger must not run the submit cycle.
|
|
18722
|
+
// `updateSubmitTriggerState()` marks an invalid form's trigger with
|
|
18723
|
+
// `aria-disabled="true"` and never with native `disabled`, precisely so
|
|
18724
|
+
// the click still reaches us. Nothing READ that marker, so the trigger
|
|
18725
|
+
// stayed fully operable: a click ran the collect -> validate ->
|
|
18726
|
+
// `validate.<id>` chain and only the `isValid()` gate stopped the send.
|
|
18727
|
+
// The trigger was inert in appearance ONLY, and that also contradicted
|
|
18728
|
+
// the `aria-disabled` contract it advertises to assistive tech (which
|
|
18729
|
+
// requires the author to suppress the action).
|
|
18730
|
+
//
|
|
18731
|
+
// Intercept HERE — before the `submit.<id>` dispatch below — so
|
|
18732
|
+
// `bindSubmitEl`'s handler never runs, `isSubmitting` is never latched
|
|
18733
|
+
// and no send path is reachable. The click is still answered with a
|
|
18734
|
+
// display-only reveal, so the user learns WHY the trigger is disabled
|
|
18735
|
+
// (which is what the operable-trigger design was bought for).
|
|
18736
|
+
// Checked on the CLICKED element, not `$formInstance.submitTrigger`:
|
|
18737
|
+
// a form may carry several submit buttons and only one registers.
|
|
18738
|
+
if ( /^submit\./i.test(_evt) && isTriggerDisabled($el) ) {
|
|
18739
|
+
cancelEvent(event);
|
|
18740
|
+
revealValidationState( instance.$forms[$form.id] || $form );
|
|
18741
|
+
return false;
|
|
18742
|
+
}
|
|
18743
|
+
|
|
18744
|
+
// #B247 — arm the loading state on the element the user actually
|
|
18745
|
+
// operated. DELIBERATELY after the #B246 gate above: a disabled
|
|
18746
|
+
// trigger returns without starting anything, so arming it there
|
|
18747
|
+
// would strand exactly the state this feature exists to release.
|
|
18748
|
+
// `resolveTrigger` climbs to the owning button/anchor, because a
|
|
18749
|
+
// click on a wrapped label (`<button><span>Save</span></button>`)
|
|
18750
|
+
// targets the inner node, and the state belongs on the control the
|
|
18751
|
+
// user perceives as the trigger.
|
|
18752
|
+
if ( /^submit\./i.test(_evt) ) {
|
|
18753
|
+
armSubmitLoading(
|
|
18754
|
+
instance.$forms[$form.id] || $form,
|
|
18755
|
+
loadingState.resolveTrigger($el, $target)
|
|
18756
|
+
);
|
|
18757
|
+
}
|
|
18758
|
+
|
|
17547
18759
|
if (gina.events[_evt]) {
|
|
17548
18760
|
cancelEvent(event);
|
|
17549
18761
|
|
|
@@ -17679,6 +18891,22 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17679
18891
|
instance.$forms[_id].isSubmitting = false;
|
|
17680
18892
|
}
|
|
17681
18893
|
|
|
18894
|
+
// #B247 — release the trigger-scoped loading state. THIS is the path
|
|
18895
|
+
// that stranded it: a rejected submit produces no request at all, so
|
|
18896
|
+
// none of the XHR releases can ever run, and only the framework knows
|
|
18897
|
+
// the submit was refused before it started. Left armed, the trigger
|
|
18898
|
+
// stays visually loading until the page or popin is reloaded.
|
|
18899
|
+
//
|
|
18900
|
+
// Gated on nothing being in flight: a form can be submitted again
|
|
18901
|
+
// while an earlier request is still running, and that later attempt
|
|
18902
|
+
// may well be the one that fails validation. Releasing unconditionally
|
|
18903
|
+
// would clear the state belonging to the request still in progress —
|
|
18904
|
+
// whose own settle is what must release it.
|
|
18905
|
+
var _loadingForm = instance.$forms[_id] || $form;
|
|
18906
|
+
if ( !/^true$/i.test(_loadingForm.isSending) ) {
|
|
18907
|
+
disarmSubmitLoading(_loadingForm);
|
|
18908
|
+
}
|
|
18909
|
+
|
|
17682
18910
|
// #A11Y1 (slice 3) — failed submit: move focus to the first invalid field so
|
|
17683
18911
|
// assistive tech announces it (accessible name + aria-invalid + the
|
|
17684
18912
|
// aria-errormessage text). DOM order; hidden / unfocusable fields are skipped.
|
|
@@ -17696,7 +18924,13 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17696
18924
|
&& typeof(_aField.focus) == 'function'
|
|
17697
18925
|
) {
|
|
17698
18926
|
_aField.focus();
|
|
17699
|
-
|
|
18927
|
+
// #A11Y5 (V8) — kept in step with focusFirstInvalidField:
|
|
18928
|
+
// only stop once focus actually moved, since focus() is a
|
|
18929
|
+
// no-op on an unfocusable host that still passes the
|
|
18930
|
+
// typeof-function gate above.
|
|
18931
|
+
if ( typeof(document) === 'undefined' || !document || document.activeElement === _aField ) {
|
|
18932
|
+
break;
|
|
18933
|
+
}
|
|
17700
18934
|
}
|
|
17701
18935
|
}
|
|
17702
18936
|
}
|
|
@@ -17917,6 +19151,27 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17917
19151
|
return false;
|
|
17918
19152
|
}
|
|
17919
19153
|
|
|
19154
|
+
// #B247 — a submit that never went through the click proxy still gets a
|
|
19155
|
+
// loading state: Enter inside a field, `form.submit()`, `$validator.submit()`,
|
|
19156
|
+
// and — less obviously — a click on a wrapped label such as
|
|
19157
|
+
// `<button type="submit"><span>Save</span></button>`, whose event.target is
|
|
19158
|
+
// the span (no `.type`), so the click proxy's submit branch never fires and
|
|
19159
|
+
// the event surfaces here instead. There is no clicked element on this path,
|
|
19160
|
+
// so the registered trigger is the best and only referent. Placed after the
|
|
19161
|
+
// disabled + defaultPrevented guards above, which both return first.
|
|
19162
|
+
// NB. the disabled check at the top of this handler reads a DOMParser copy of
|
|
19163
|
+
// the form's innerHTML, so it sees neither a live `disabled` set by JS nor the
|
|
19164
|
+
// `aria-disabled` marker `updateSubmitTriggerState` uses. Re-check the live
|
|
19165
|
+
// node with #B246's predicate: without it, every Enter-key submit on an
|
|
19166
|
+
// invalid live-check form would flash the trigger armed for the length of the
|
|
19167
|
+
// validation pass before the rejected branch released it.
|
|
19168
|
+
if ($formInstance) {
|
|
19169
|
+
var $loadingTrigger = document.getElementById($formInstance.submitTrigger);
|
|
19170
|
+
if ( !isTriggerDisabled($loadingTrigger) ) {
|
|
19171
|
+
armSubmitLoading($formInstance, $loadingTrigger);
|
|
19172
|
+
}
|
|
19173
|
+
}
|
|
19174
|
+
|
|
17920
19175
|
if (withRules || isBinded) {
|
|
17921
19176
|
cancelEvent(e);
|
|
17922
19177
|
}
|
|
@@ -18106,13 +19361,17 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18106
19361
|
} else if ( document.getElementById($formInstance.submitTrigger) ) {
|
|
18107
19362
|
// Represent the "invalid + live-check-on" state with aria-disabled + a class
|
|
18108
19363
|
// INSTEAD of the native `disabled` property. A natively-disabled <button>
|
|
18109
|
-
// emits no click event, so the
|
|
18110
|
-
//
|
|
18111
|
-
//
|
|
18112
|
-
//
|
|
18113
|
-
//
|
|
18114
|
-
//
|
|
18115
|
-
//
|
|
19364
|
+
// emits no click event at all, so the click cannot be observed and the user
|
|
19365
|
+
// gets no feedback about WHY the trigger is dead. aria-disabled keeps the
|
|
19366
|
+
// trigger focusable and perceivable, and clickProxyHandler INTERCEPTS the
|
|
19367
|
+
// click (#B246) to answer it with a display-only reveal: every invalid field
|
|
19368
|
+
// is rendered and the first is focused, while the submit cycle is never
|
|
19369
|
+
// entered. The trigger is therefore genuinely not operable — which is what
|
|
19370
|
+
// the aria-disabled contract promises assistive tech, and what the earlier
|
|
19371
|
+
// "keep it operable so the click can still validate" shape got wrong: it
|
|
19372
|
+
// left the real submit path reachable from a control announced as disabled.
|
|
19373
|
+
// Mirrors gina's own <a>-tag submit-trigger handling, which already uses
|
|
19374
|
+
// aria-disabled in-flight. The show branch KEEPS clearing native `disabled` so a trigger
|
|
18116
19375
|
// rendered `disabled` in markup still enables on valid / when live-check is off.
|
|
18117
19376
|
// Tag-agnostic: setAttribute/classList work for both <button> and <a> submit
|
|
18118
19377
|
// triggers. Consumers must style the [aria-disabled="true"] /
|
|
@@ -18133,6 +19392,125 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18133
19392
|
}
|
|
18134
19393
|
}
|
|
18135
19394
|
|
|
19395
|
+
/**
|
|
19396
|
+
* isTriggerDisabled
|
|
19397
|
+
*
|
|
19398
|
+
* Tells whether a submit trigger is currently marked as disabled.
|
|
19399
|
+
* `updateSubmitTriggerState()` marks an invalid form's trigger with
|
|
19400
|
+
* `aria-disabled="true"` rather than the native `disabled` property, so a
|
|
19401
|
+
* native-only check can never see it. The predicate shape mirrors the popin
|
|
19402
|
+
* plugin's own trigger gate, so both subsystems agree on what "disabled"
|
|
19403
|
+
* means for a trigger.
|
|
19404
|
+
*
|
|
19405
|
+
* @param {object} $el - candidate trigger (DOMObject)
|
|
19406
|
+
*
|
|
19407
|
+
* @returns {boolean} true when the trigger must not be operated
|
|
19408
|
+
*
|
|
19409
|
+
* @example
|
|
19410
|
+
* isTriggerDisabled($button); // true while aria-disabled="true" is set
|
|
19411
|
+
*
|
|
19412
|
+
* @inner
|
|
19413
|
+
*/
|
|
19414
|
+
var isTriggerDisabled = function($el) {
|
|
19415
|
+
if ( !$el || typeof($el.getAttribute) != 'function' ) {
|
|
19416
|
+
return false;
|
|
19417
|
+
}
|
|
19418
|
+
return (
|
|
19419
|
+
$el.getAttribute('disabled') != null && $el.getAttribute('disabled') != 'false'
|
|
19420
|
+
||
|
|
19421
|
+
$el.getAttribute('aria-disabled') == 'true'
|
|
19422
|
+
);
|
|
19423
|
+
};
|
|
19424
|
+
|
|
19425
|
+
/**
|
|
19426
|
+
* focusFirstInvalidField
|
|
19427
|
+
*
|
|
19428
|
+
* Moves focus to the first field carrying an error, in DOM order, skipping
|
|
19429
|
+
* hidden and unfocusable controls (#A11Y1) so assistive tech announces the
|
|
19430
|
+
* accessible name + `aria-invalid` + the `aria-errormessage` text.
|
|
19431
|
+
*
|
|
19432
|
+
* NB. the `validate.<id>` guard keeps its own inline twin of this loop rather
|
|
19433
|
+
* than calling here. That is DELIBERATE: the inline shape is locked by source
|
|
19434
|
+
* pins in `test/core/validator-aria-invalid.test.js` (`_a11yErrs`, `_aField`),
|
|
19435
|
+
* so collapsing the two would break pins unrelated to #B246. Keep the two in
|
|
19436
|
+
* step if the focus rule ever changes.
|
|
19437
|
+
*
|
|
19438
|
+
* @param {object} $form - form target (DOMObject), not the instance
|
|
19439
|
+
* @param {object} errors - error map keyed by field name
|
|
19440
|
+
*
|
|
19441
|
+
* @returns {boolean} true when a field was focused
|
|
19442
|
+
*
|
|
19443
|
+
* @example
|
|
19444
|
+
* focusFirstInvalidField($form, result['fields'] || result['error']);
|
|
19445
|
+
*
|
|
19446
|
+
* @inner
|
|
19447
|
+
*/
|
|
19448
|
+
var focusFirstInvalidField = function($form, errors) {
|
|
19449
|
+
if ( !$form || !errors ) {
|
|
19450
|
+
return false;
|
|
19451
|
+
}
|
|
19452
|
+
for (var i = 0, len = $form.length; i < len; ++i) {
|
|
19453
|
+
var $field = $form[i];
|
|
19454
|
+
var name = $field.getAttribute('name');
|
|
19455
|
+
if (
|
|
19456
|
+
name
|
|
19457
|
+
&& typeof(errors[name]) != 'undefined'
|
|
19458
|
+
&& ( typeof(errors[name].count) != 'function' || errors[name].count() > 0 )
|
|
19459
|
+
&& $field.type != 'hidden'
|
|
19460
|
+
&& typeof($field.focus) == 'function'
|
|
19461
|
+
) {
|
|
19462
|
+
$field.focus();
|
|
19463
|
+
// #A11Y5 (V8) — `typeof focus == 'function'` is true for EVERY HTMLElement,
|
|
19464
|
+
// a custom element with neither `tabindex` nor `delegatesFocus` included,
|
|
19465
|
+
// whose focus() is a silent no-op (measured). Without confirming the move,
|
|
19466
|
+
// the loop reported success and stopped on a control that never took focus,
|
|
19467
|
+
// so a failed submit announced nothing. Confirming it is also what makes the
|
|
19468
|
+
// "skips unfocusable controls" contract above true rather than aspirational.
|
|
19469
|
+
if ( typeof(document) === 'undefined' || !document || document.activeElement === $field ) {
|
|
19470
|
+
return true;
|
|
19471
|
+
}
|
|
19472
|
+
}
|
|
19473
|
+
}
|
|
19474
|
+
return false;
|
|
19475
|
+
};
|
|
19476
|
+
|
|
19477
|
+
/**
|
|
19478
|
+
* revealValidationState
|
|
19479
|
+
*
|
|
19480
|
+
* Display-only validation pass, used when a DISABLED submit trigger is
|
|
19481
|
+
* clicked (#B246). It runs the same collect + validate chain the submit path
|
|
19482
|
+
* uses, but routes the result straight to the error renderer instead of
|
|
19483
|
+
* dispatching `validate.<id>` — so `bindSubmitEl`'s handler never runs, the
|
|
19484
|
+
* `isSubmitting` latch is never set and the `isValid()` send gate is never
|
|
19485
|
+
* reached. No request can start from this path by construction.
|
|
19486
|
+
*
|
|
19487
|
+
* The trigger state is re-synced from the fresh result, which also self-heals
|
|
19488
|
+
* a stale disabled marker on a form that has since become valid.
|
|
19489
|
+
*
|
|
19490
|
+
* @param {object} $formInstance - form instance (carries `.target` / `.rules`)
|
|
19491
|
+
*
|
|
19492
|
+
* @returns {void}
|
|
19493
|
+
*
|
|
19494
|
+
* @example
|
|
19495
|
+
* revealValidationState(instance.$forms['myForm']);
|
|
19496
|
+
*
|
|
19497
|
+
* @inner
|
|
19498
|
+
*/
|
|
19499
|
+
var revealValidationState = function($formInstance) {
|
|
19500
|
+
if ( !$formInstance || !$formInstance.target ) {
|
|
19501
|
+
return;
|
|
19502
|
+
}
|
|
19503
|
+
var $target = $formInstance.target;
|
|
19504
|
+
var validationInfo = getFormValidationInfos($target, $formInstance.rules);
|
|
19505
|
+
|
|
19506
|
+
validate($target, validationInfo.fields, validationInfo.$fields, $formInstance.rules, function onDisabledTriggerReveal(result) {
|
|
19507
|
+
var errors = result['fields'] || result['error'];
|
|
19508
|
+
handleErrorsDisplay($target, errors, result['data']);
|
|
19509
|
+
focusFirstInvalidField($target, errors);
|
|
19510
|
+
updateSubmitTriggerState($formInstance, result.isValid());
|
|
19511
|
+
});
|
|
19512
|
+
};
|
|
19513
|
+
|
|
18136
19514
|
/**
|
|
18137
19515
|
* getFormValidationInfos
|
|
18138
19516
|
*
|
|
@@ -19691,13 +21069,14 @@ if ( ( typeof(module) !== 'undefined' ) && module.exports ) {
|
|
|
19691
21069
|
module.exports = ValidatorPlugin
|
|
19692
21070
|
} else if ( typeof(define) === 'function' && define.amd) {
|
|
19693
21071
|
// Publish as AMD module
|
|
19694
|
-
define('gina/validator', ['utils/events', 'utils/dom', 'utils/effects', 'utils/data', 'lib/form-validator', 'lib/routing'], function(){ return ValidatorPlugin })
|
|
21072
|
+
define('gina/validator', ['utils/events', 'utils/dom', 'utils/effects', 'utils/data', 'lib/form-validator', 'lib/routing', 'lib/loading-state'], function(){ return ValidatorPlugin })
|
|
19695
21073
|
};
|
|
19696
|
-
define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], function (require) {
|
|
21074
|
+
define('gina/popin', [ 'require', 'lib/domain', 'lib/loading-state', 'lib/merge', 'utils/events' ], function (require) {
|
|
19697
21075
|
|
|
19698
21076
|
// TODO - Integrate dialog-polyfill : https://github.com/GoogleChrome/dialog-polyfill/blob/master/dist/dialog-polyfill.js
|
|
19699
21077
|
var Domain = require('lib/domain');
|
|
19700
21078
|
var domainInstance = null;
|
|
21079
|
+
var loadingState = require('lib/loading-state');
|
|
19701
21080
|
var merge = require('lib/merge');
|
|
19702
21081
|
|
|
19703
21082
|
require('utils/events'); // events
|
|
@@ -20163,7 +21542,19 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
20163
21542
|
* a body scroll-lock attribute (CSS), and best-effort `inert` on background
|
|
20164
21543
|
* siblings. Torn down by removeNonModalShims() on close.
|
|
20165
21544
|
*
|
|
21545
|
+
* "Background siblings" has to include any OTHER popin still open inside the
|
|
21546
|
+
* shared container: popinOpen() never closes the popin it supersedes, so a
|
|
21547
|
+
* second non-modal dialog would otherwise leave the first one fully
|
|
21548
|
+
* keyboard-reachable behind it. The container itself must stay reachable — it
|
|
21549
|
+
* holds $el — so it is descended into rather than skipped.
|
|
21550
|
+
*
|
|
21551
|
+
* Only `[open]` dialogs are inerted. A closed `<dialog>` is already
|
|
21552
|
+
* `display:none` per the UA stylesheet, so it is unreachable without help.
|
|
21553
|
+
*
|
|
20166
21554
|
* @inner
|
|
21555
|
+
* @param {object} $popin - popin descriptor; the Escape handler closes by $popin.name
|
|
21556
|
+
* @param {HTMLElement} $el - the dialog element being shown non-modally
|
|
21557
|
+
* @returns {void}
|
|
20167
21558
|
*/
|
|
20168
21559
|
function applyNonModalShims($popin, $el) {
|
|
20169
21560
|
if ( !$el ) {
|
|
@@ -20182,11 +21573,30 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
20182
21573
|
$el.__ginaOnKeydown = onKeydown;
|
|
20183
21574
|
$el.addEventListener('keydown', onKeydown);
|
|
20184
21575
|
|
|
20185
|
-
// Best-effort background inert (skip the dialog
|
|
21576
|
+
// Best-effort background inert (skip the dialog and its ancestors; descend
|
|
21577
|
+
// into the container so a superseded popin does not stay reachable).
|
|
20186
21578
|
var siblings = document.body.children;
|
|
20187
21579
|
var b = 0, len = siblings.length;
|
|
20188
21580
|
for (; b < len; ++b) {
|
|
20189
|
-
if ( siblings[b] ===
|
|
21581
|
+
if ( siblings[b] === instance.target ) {
|
|
21582
|
+
// The container holds $el, so it cannot be inerted wholesale — but any
|
|
21583
|
+
// OTHER popin still open inside it would remain keyboard-reachable
|
|
21584
|
+
// behind this one. Closed dialogs are already display:none (UA
|
|
21585
|
+
// stylesheet), so [open] is the whole set that needs help.
|
|
21586
|
+
var $open = siblings[b].querySelectorAll('dialog[open]');
|
|
21587
|
+
var d = 0, dLen = $open.length;
|
|
21588
|
+
for (; d < dLen; ++d) {
|
|
21589
|
+
if ( $open[d] === $el || $open[d].contains($el) ) {
|
|
21590
|
+
continue;
|
|
21591
|
+
}
|
|
21592
|
+
if ( $open[d].getAttribute('inert') == null ) {
|
|
21593
|
+
$open[d].setAttribute('inert', '');
|
|
21594
|
+
$open[d].setAttribute('data-gina-popin-inert', 'true');
|
|
21595
|
+
}
|
|
21596
|
+
}
|
|
21597
|
+
continue;
|
|
21598
|
+
}
|
|
21599
|
+
if ( siblings[b] === $el || siblings[b].contains($el) ) {
|
|
20190
21600
|
continue;
|
|
20191
21601
|
}
|
|
20192
21602
|
if ( siblings[b].getAttribute('inert') == null ) {
|
|
@@ -21551,6 +22961,43 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
21551
22961
|
}
|
|
21552
22962
|
}
|
|
21553
22963
|
|
|
22964
|
+
/**
|
|
22965
|
+
* armPopinTrigger
|
|
22966
|
+
*
|
|
22967
|
+
* Makes the control that opened a popin inoperable for the duration of the load
|
|
22968
|
+
* and marks it with the shared `data-gina-loading`.
|
|
22969
|
+
*
|
|
22970
|
+
* That attribute is NOT a duplicate of the container's `data-gina-popin-loading`:
|
|
22971
|
+
* they sit on different elements and answer different questions — the container
|
|
22972
|
+
* one says "this popin is filling", this one says "this control is busy". The
|
|
22973
|
+
* second is the same attribute the validator and link plugins write, so a single
|
|
22974
|
+
* stylesheet covers every busy control a project has, whichever plugin started
|
|
22975
|
+
* the work.
|
|
22976
|
+
*
|
|
22977
|
+
* Scoped to the TRIGGER rather than absorbing the whole arm block, deliberately:
|
|
22978
|
+
* the two arm sites must keep their own literal `showLoadingShell($popin, $el)`
|
|
22979
|
+
* call, which is what `popin.test.js` pins to prove the skeleton shows at both.
|
|
22980
|
+
*
|
|
22981
|
+
* @inner
|
|
22982
|
+
* @param {HTMLElement} [$popinTrigger] - the control that opened it, when it has an id
|
|
22983
|
+
* @returns {void}
|
|
22984
|
+
*
|
|
22985
|
+
* @example
|
|
22986
|
+
* armPopinTrigger(document.getElementById($popin.openTrigger));
|
|
22987
|
+
*/
|
|
22988
|
+
function armPopinTrigger($popinTrigger) {
|
|
22989
|
+
if ( !$popinTrigger ) {
|
|
22990
|
+
return;
|
|
22991
|
+
}
|
|
22992
|
+
// For A tag: aria-disabled=true
|
|
22993
|
+
if ( /^A$/i.test($popinTrigger.tagName) ) {
|
|
22994
|
+
$popinTrigger.setAttribute('aria-disabled', true);
|
|
22995
|
+
} else {
|
|
22996
|
+
$popinTrigger.setAttribute('disabled', true);
|
|
22997
|
+
}
|
|
22998
|
+
loadingState.arm($popinTrigger);
|
|
22999
|
+
}
|
|
23000
|
+
|
|
21554
23001
|
/**
|
|
21555
23002
|
* popinLoad
|
|
21556
23003
|
*
|
|
@@ -21728,14 +23175,7 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
21728
23175
|
if ( /^(1|3)$/.test(xhr.readyState) ) {
|
|
21729
23176
|
$popin.target.setAttribute('data-gina-popin-loading', true);
|
|
21730
23177
|
showLoadingShell($popin, $el);
|
|
21731
|
-
|
|
21732
|
-
// For A tag: aria-disabled=true
|
|
21733
|
-
if ( /^A$/i.test($popinTrigger.tagName) ) {
|
|
21734
|
-
$popinTrigger.setAttribute('aria-disabled', true);
|
|
21735
|
-
} else {
|
|
21736
|
-
$popinTrigger.setAttribute('disabled', true);
|
|
21737
|
-
}
|
|
21738
|
-
}
|
|
23178
|
+
armPopinTrigger($popinTrigger);
|
|
21739
23179
|
}
|
|
21740
23180
|
|
|
21741
23181
|
// catching ready state cb
|
|
@@ -21744,18 +23184,12 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
21744
23184
|
if ( /^(1|3)$/.test(xhr.readyState) ) {
|
|
21745
23185
|
$popin.target.setAttribute('data-gina-popin-loading', true);
|
|
21746
23186
|
showLoadingShell($popin, $el);
|
|
21747
|
-
|
|
21748
|
-
// For A tag: aria-disabled=true
|
|
21749
|
-
if ( /^A$/i.test($popinTrigger.tagName) ) {
|
|
21750
|
-
$popinTrigger.setAttribute('aria-disabled', true);
|
|
21751
|
-
} else {
|
|
21752
|
-
$popinTrigger.setAttribute('disabled', true);
|
|
21753
|
-
}
|
|
21754
|
-
}
|
|
23187
|
+
armPopinTrigger($popinTrigger);
|
|
21755
23188
|
}
|
|
21756
23189
|
if (xhr.readyState == 4) {
|
|
21757
23190
|
// Fixed: clear loading state on response complete — data-gina-popin-loading
|
|
21758
23191
|
// was set on readyState 1|3 but never removed, leaving the overlay blocked.
|
|
23192
|
+
// Covers every status including 0, since the branch is on readyState alone.
|
|
21759
23193
|
$popin.target.removeAttribute('data-gina-popin-loading');
|
|
21760
23194
|
if ($popinTrigger) {
|
|
21761
23195
|
if ( /^A$/i.test($popinTrigger.tagName) ) {
|
|
@@ -21763,6 +23197,7 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
21763
23197
|
} else {
|
|
21764
23198
|
$popinTrigger.removeAttribute('disabled');
|
|
21765
23199
|
}
|
|
23200
|
+
loadingState.disarm($popinTrigger);
|
|
21766
23201
|
}
|
|
21767
23202
|
// 200, 201, 201' etc ...
|
|
21768
23203
|
var result = null;
|
|
@@ -22343,6 +23778,12 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
22343
23778
|
// Fixed: clear loading state on reset — defensive cleanup for navigation
|
|
22344
23779
|
// within a popin that was in loading state when reset was called.
|
|
22345
23780
|
$el.removeAttribute('data-gina-popin-loading');
|
|
23781
|
+
// Trigger-scoped release. This function is ALSO reached from routing
|
|
23782
|
+
// transitions that never call popinClose, so without this the control
|
|
23783
|
+
// that opened a popin torn down by a route change would stay armed.
|
|
23784
|
+
// Resolved here rather than passed in: popinUnbind only has $popin, and
|
|
23785
|
+
// `disarm` is a no-op on the null a trigger-less popin resolves to.
|
|
23786
|
+
loadingState.disarm( document.getElementById($popin.openTrigger) );
|
|
22346
23787
|
|
|
22347
23788
|
// removing from FormValidator instance
|
|
22348
23789
|
if ($validatorInstance) {
|
|
@@ -22455,6 +23896,7 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
22455
23896
|
} else {
|
|
22456
23897
|
$popinTrigger.removeAttribute('disabled', true);
|
|
22457
23898
|
}
|
|
23899
|
+
loadingState.disarm($popinTrigger);
|
|
22458
23900
|
// a11y: return focus to the trigger that opened the popin.
|
|
22459
23901
|
if ( typeof($popinTrigger.focus) == 'function' ) {
|
|
22460
23902
|
$popinTrigger.focus();
|
|
@@ -25939,7 +27381,8 @@ require([
|
|
|
25939
27381
|
"lib/form-validator",
|
|
25940
27382
|
"lib/collection",
|
|
25941
27383
|
"lib/domain",
|
|
25942
|
-
"lib/routing"
|
|
27384
|
+
"lib/routing",
|
|
27385
|
+
"lib/loading-state"
|
|
25943
27386
|
], function () {
|
|
25944
27387
|
// Boot the popin handler at page load so the declarative `data-gina-dialog` API is
|
|
25945
27388
|
// active WITHOUT bundle code calling `new gina.popin()`. Constructing the handler
|