gina 0.6.2 → 0.6.3
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 +57 -0
- package/README.md +41 -12
- package/ROADMAP.md +3 -2
- package/bin/cli +19 -2
- package/framework/v0.6.3/VERSION +1 -0
- package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/html/statusbar.html +6 -0
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/html/statusbar.html.br +0 -0
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/html/statusbar.html.gz +0 -0
- package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/inspector/index.html +1 -0
- package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/inspector/inspector.css +50 -1
- package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/inspector/inspector.js +457 -57
- package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/js/gina.js +1457 -58
- package/framework/v0.6.3/core/asset/plugin/dist/vendor/gina/js/gina.min.js +625 -0
- 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.2 → v0.6.3}/core/connectors/couchbase/index.js +114 -0
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/connector.js +14 -3
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/session-store.js +14 -3
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/session-store.v3.js +29 -2
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/session-store.v4.js +29 -2
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/mongodb/lib/session-store.js +24 -2
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/redis/lib/session-store.js +33 -9
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/scylladb/lib/session-store.js +25 -2
- package/framework/{v0.6.2 → v0.6.3}/core/connectors/sqlite/lib/session-store.js +26 -2
- package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.js +201 -21
- package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-nunjucks.js +8 -0
- package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-swig.js +85 -4
- package/framework/{v0.6.2 → v0.6.3}/core/gna.js +23 -1
- package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/csrf/src/main.js +9 -5
- package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hide-powered-by/README.md +20 -0
- package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/validator/src/form-validator.js +119 -43
- package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/validator/src/main.js +451 -9
- package/framework/{v0.6.2 → v0.6.3}/core/server.isaac.js +50 -54
- package/framework/{v0.6.2 → v0.6.3}/core/server.js +240 -3
- package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/index.js +6 -4
- package/framework/{v0.6.2 → v0.6.3}/core/template/conf/settings.json +10 -0
- package/framework/{v0.6.2 → v0.6.3}/lib/cache/README.md +9 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/cmd/audit/verify.js +11 -9
- package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/mcp-start.js +21 -12
- package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/help.txt +1 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/init.js +13 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/dto/src/main.js +18 -11
- package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/file/index.js +29 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/mq/speaker.js +30 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/math/index.js +57 -6
- package/framework/{v0.6.2 → v0.6.3}/lib/merge/src/main.js +34 -5
- package/framework/{v0.6.2 → v0.6.3}/lib/render-cache/src/main.js +77 -4
- package/framework/{v0.6.2 → v0.6.3}/lib/routing/src/main.js +13 -1
- package/framework/{v0.6.2 → v0.6.3}/lib/routing-introspect/src/main.js +64 -2
- package/framework/v0.6.3/lib/secrets/src/backends/env.js +75 -0
- package/framework/{v0.6.2 → v0.6.3}/package.json +1 -1
- package/gna.js +5 -4
- package/llms.txt +19 -17
- package/package.json +5 -4
- package/schema/connectors.json +2 -2
- package/schema/routing.json +5 -0
- package/schema/settings.json +6 -1
- package/script/generate_gna_types.js +1 -1
- package/script/soak/couchbase-soak.js +1316 -0
- package/types/globals.d.ts +2 -0
- package/types/gna.d.ts +5 -0
- package/types/index.d.ts +1 -0
- package/utils/helper.js +38 -7
- package/framework/v0.6.2/VERSION +0 -1
- package/framework/v0.6.2/core/asset/plugin/dist/vendor/gina/html/statusbar.html.br +0 -0
- package/framework/v0.6.2/core/asset/plugin/dist/vendor/gina/html/statusbar.html.gz +0 -0
- package/framework/v0.6.2/core/asset/plugin/dist/vendor/gina/js/gina.min.js +0 -603
- package/framework/v0.6.2/core/asset/plugin/dist/vendor/gina/js/gina.min.js.br +0 -0
- package/framework/v0.6.2/core/asset/plugin/dist/vendor/gina/js/gina.min.js.gz +0 -0
- package/framework/v0.6.2/lib/secrets/src/backends/env.js +0 -60
- /package/framework/{v0.6.2 → v0.6.3}/AUTHORS +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/LICENSE +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/html/nolayout.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/html/static.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/android-chrome-192x192.png +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/android-chrome-512x512.png +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/apple-touch-icon.png +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/favicon-16x16.png +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/favicon-32x32.png +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/img/favicon.ico +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.css +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/beemaster/beemaster.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/beemaster/index.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/css/gina.min.css +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.br +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/css/gina.min.css.gz +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/inspector/have_heart_one-webfont.woff2 +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/inspector/logo.svg +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.br +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/asset/plugin/dist/vendor/gina/js/gina.onload.min.js.gz +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/config.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/ai/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/ai/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/connector.v3.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/connector.v4.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/couchbase/lib/n1ql.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/duckdb/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/duckdb/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mongodb/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mongodb/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mongodb/lib/job-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mongodb/lib/pipeline-loader.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mysql/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/mysql/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/postgresql/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/postgresql/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/redis/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/redis/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/redis/lib/job-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/redis/lib/render-cache-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/scylladb/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/scylladb/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/sql-parser.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/sqlite/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/sqlite/lib/connector.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/connectors/sqlite/lib/job-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/content.encoding +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.framework.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-json.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-nunjucks-async.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-stream.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-swig-async.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/controller.render-v1.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/inspector-window-emit.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/controller/release-banner.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/dev/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/dev/lib/class.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/dev/lib/factory.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/dev/lib/tools.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/currency.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/dist/language/en.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/dist/language/fr.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/dist/region/en.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/dist/region/fr.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/locales/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/mime.types +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/model/entity.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/model/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/model/template/entityFactory.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/model/template/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/csrf/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/csrf/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coep/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coep/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coep/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coop/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coop/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/coop/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/corp/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/corp/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/corp/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/csp/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/csp/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/csp/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hide-powered-by/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hide-powered-by/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hsts/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hsts/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/hsts/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/origin-agent-cluster/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/origin-agent-cluster/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/origin-agent-cluster/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/referrer-policy/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/referrer-policy/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/referrer-policy/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-content-type-options/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-content-type-options/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-content-type-options/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-dns-prefetch-control/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-dns-prefetch-control/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-dns-prefetch-control/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-download-options/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-download-options/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-download-options/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-frame-options/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-frame-options/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-frame-options/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-permitted-cross-domain-policies/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-xss-protection/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-xss-protection/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/security-headers/x-xss-protection/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/session/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/session/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/session/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/storage/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/storage/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/storage/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/storage/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/validator/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/validator/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/plugins/lib/validator/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/router.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/server.express.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/status.codes +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/_gitignore +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/app.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/connectors.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/routing.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/settings.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/settings.server.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/templates.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/config/watchers.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/controllers/controller.content.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/controllers/controller.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/controllers/setup.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle/locales/en.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_namespace/controllers/controller.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/css/default.css +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/css/home.css +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/css/vendor/readme.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/favicon.ico +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/js/components/x-checklist.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/js/vendor/readme.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/manifest.webmanifest +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/readme.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_public/sw.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/handlers/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/html/content/homepage.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/html/includes/error-msg-noscript.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/html/includes/error-msg-outdated-browser.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/html/includes/x-checklist.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/boilerplate/bundle_templates/html/layouts/main.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/command/gina.bat.tpl +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/command/gina.tpl +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/conf/env.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/conf/manifest.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/conf/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/conf/statics.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/conf/templates.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/client/json/401.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/client/json/403.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/client/json/404.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/server/html/50x.html +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/server/json/500.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/error/server/json/503.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/core/template/extensions/logger/config.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/console.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/context.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/data/LICENSE +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/data/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/data/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/data/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/dateFormat.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/json/LICENSE +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/json/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/json/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/json/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/path.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/plugins/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/plugins/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/plugins/src/api-error.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/plugins/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/prototypes.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/task.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/helpers/text.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/admin/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/admin/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/archiver/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/archiver/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/archiver/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/archiver/src/dep/jszip.min.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/archiver/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/async/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/async/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/audit/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/audit/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/audit-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authn/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authn/src/lockout.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authn/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authn/src/totp.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authz-gate/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/authz-gate/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cache/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cache/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cache/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/aliases.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/audit/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/audit/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/build.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/copy.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/cp.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/inc/name-rewrite.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/mcp.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/oas.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/openapi.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/rename.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/restart.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/start.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/status.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/stop.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/bundle/types.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/cache/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/cache/clear.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/cache/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/cache/stats.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/infer.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/migrate.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/models.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/connector/test.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/ps.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/container/stop.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/inc/args.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/inc/namespace.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/inc/reference-rewrite.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/inc/reference-scan.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/inc/scaffold.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/rename.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/controller/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/get.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/link-dev.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/set.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/unset.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/env/use.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/build.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/dot.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/get.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/link-node-modules.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/link.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/msg.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/open.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/reset.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/restart.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/set.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/start.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/status.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/stop.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/tail.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/update.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/framework/version.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/gina-dev.1.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/gina-framework.1.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/gina.1.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/helper.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/export.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/import.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/i18n/scan.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/_host.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/build.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/image/run.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/inspector/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/inspector/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/inspector/open.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/man-render.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/minion/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/minion/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/minion/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/minion/kill.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/minion/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/msg.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/inc/scan.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/reset.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/port/set.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/backup.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/build.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/import.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/move.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/rename.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/restart.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/restore.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/start.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/status.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/project/stop.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/protocol/set.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/link-local.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/link-production.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/remove.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/rm.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/scope/use.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/secrets/arguments.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/secrets/check.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/secrets/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/secrets/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/secrets/scan.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/service/help.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/service/help.txt +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/service/list.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/service/man.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/service/start.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd/view/add.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd-status-format/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cmd-status-format/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/collection/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/collection/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/collection/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/collection/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/config.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-config/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-config/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-error/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-error/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-registry/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/connector-registry/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cron/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cron/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/cron/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/domain/LICENSE +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/domain/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/domain/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/domain/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/dto/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/dto-pipe/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/dto-pipe/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/dto-types/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/dto-types/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/generator/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/i18n/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/i18n/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/image-build/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/image-build/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inherits/LICENSE +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inherits/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inherits/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inherits/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inspector-events/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inspector-events/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inspector-redact/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/inspector-redact/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/instrument/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/instrument/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/job/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/job/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/job-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/json-config-header/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/json-config-header/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/default/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/file/lib/logrotator/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/file/lib/logrotator/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/mq/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/containers/mq/listener.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/helper.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/logger/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-dispatch/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-dispatch/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-http/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-http/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-server/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/mcp-server/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/merge/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/merge/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/metrics/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/metrics/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/model.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/net-locality/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/net-locality/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/nunjucks-filters/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/nunjucks-filters/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/nunjucks-filters/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/nunjucks-resolver/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/nunjucks-resolver/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/proc.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/release-watch/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/release-watch/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/render-cache/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/render-cache-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/routing/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/routing/build.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/routing/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/routing/src/radix.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/routing-introspect/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/secrets/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/secrets/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/session-store.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/shell.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/sqlite-driver.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/state.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/swig-filters/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/swig-filters/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/swig-filters/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/swig-resolver/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/swig-resolver/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/template-loaders/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/template-loaders/src/loaders/http.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/template-loaders/src/loaders/memory.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/template-loaders/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/url/README.md +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/url/index.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/url/routing.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/uuid/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/uuid/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/validator.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/watcher/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/watcher/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-framing/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-framing/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-query/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-query/src/main.js +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-session/package.json +0 -0
- /package/framework/{v0.6.2 → v0.6.3}/lib/ws-session/src/main.js +0 -0
|
@@ -2197,6 +2197,7 @@ function Merge() {
|
|
|
2197
2197
|
* merge({ a: 1 }, { a: 9 }, true) // { a: 9 }
|
|
2198
2198
|
* merge([1, 2], [3, 4]) // [1, 2, 3, 4]
|
|
2199
2199
|
* merge([1, 2], [3, 4], true) // [3, 4]
|
|
2200
|
+
* merge({ a: [null, 'x'] }, { a: [null, 'x'] }) // { a: [null, 'x'] } — null elements are preserved (#B226)
|
|
2200
2201
|
*/
|
|
2201
2202
|
var browse = function (_target, _source) {
|
|
2202
2203
|
|
|
@@ -2401,8 +2402,25 @@ function Merge() {
|
|
|
2401
2402
|
return target;
|
|
2402
2403
|
};
|
|
2403
2404
|
|
|
2404
|
-
|
|
2405
|
-
|
|
2405
|
+
/**
|
|
2406
|
+
* Merge two arrays. Will not merge function items: this is normal.
|
|
2407
|
+
* Merging plain arrays is OK, merging collections is still experimental.
|
|
2408
|
+
*
|
|
2409
|
+
* `null` elements are VALUES and are preserved (#B226): `typeof null ==
|
|
2410
|
+
* 'object'`, so the object-exclusion guards below each carry an explicit
|
|
2411
|
+
* null exception — without it a no-override merge silently dropped `null`
|
|
2412
|
+
* from arrays (while `''` / `false` / `0` survived), which stripped the
|
|
2413
|
+
* first slot of positional argument arrays such as the documented
|
|
2414
|
+
* validator rule `"setFlash": [null, "message"]` on the client-side
|
|
2415
|
+
* rules path.
|
|
2416
|
+
*
|
|
2417
|
+
* @inner
|
|
2418
|
+
* @private
|
|
2419
|
+
* @param {Array} options - Source array (merged INTO target)
|
|
2420
|
+
* @param {Array} target - Target array (wins on conflicts unless `override`)
|
|
2421
|
+
* @param {boolean} override - `true` lets `options` win / replace
|
|
2422
|
+
* @returns {Array|undefined} the merged array
|
|
2423
|
+
*/
|
|
2406
2424
|
var mergeArray = function(options, target, override) {
|
|
2407
2425
|
newTarget = [];
|
|
2408
2426
|
|
|
@@ -2507,7 +2525,12 @@ function Merge() {
|
|
|
2507
2525
|
// ok, but don't merge objects
|
|
2508
2526
|
a = 0;
|
|
2509
2527
|
for (; a < target.length; ++a ) {
|
|
2510
|
-
|
|
2528
|
+
// #B226 — typeof null == 'object': a null element is a value
|
|
2529
|
+
// (e.g. the first slot of a positional rule-argument array),
|
|
2530
|
+
// not a collection item to exclude; this rebuild dropped it
|
|
2531
|
+
// while '' / false / 0 survived
|
|
2532
|
+
// was: if ( typeof(target[a]) != 'object' && newTarget.indexOf(target[a]) == -1 ) {
|
|
2533
|
+
if ( ( typeof(target[a]) != 'object' || target[a] === null ) && newTarget.indexOf(target[a]) == -1 ) {
|
|
2511
2534
|
newTarget.push(target[a]);
|
|
2512
2535
|
}
|
|
2513
2536
|
}
|
|
@@ -2592,7 +2615,11 @@ function Merge() {
|
|
|
2592
2615
|
localKeyComparison = ownPropertyNames;
|
|
2593
2616
|
if ( target.indexOf(options[a]) > -1 && override) {
|
|
2594
2617
|
target.splice(target.indexOf(options[a]), 1, options[a])
|
|
2595
|
-
|
|
2618
|
+
// #B226 — a null source element must not enter the index-merge:
|
|
2619
|
+
// `for (var k in null)` is a no-op, so null used to surface as
|
|
2620
|
+
// `{}` here; let it fall through to the primitive push below
|
|
2621
|
+
// was: } else if ( typeof(newTarget[a]) == 'undefined' && typeof(options[a]) == 'object' ) {
|
|
2622
|
+
} else if ( typeof(newTarget[a]) == 'undefined' && typeof(options[a]) == 'object' && options[a] != null ) {
|
|
2596
2623
|
// merge using index
|
|
2597
2624
|
newTarget = target;
|
|
2598
2625
|
|
|
@@ -2637,7 +2664,9 @@ function Merge() {
|
|
|
2637
2664
|
newTarget[a] = target[a]
|
|
2638
2665
|
}
|
|
2639
2666
|
// array with string key
|
|
2640
|
-
|
|
2667
|
+
// #B226 — same typeof-null exception as the rebuild above
|
|
2668
|
+
// was: else if (newTarget.indexOf(options[a]) == -1 && typeof(options[a]) != 'object') {
|
|
2669
|
+
else if (newTarget.indexOf(options[a]) == -1 && ( typeof(options[a]) != 'object' || options[a] === null )) {
|
|
2641
2670
|
newTarget.push(options[a]);
|
|
2642
2671
|
}
|
|
2643
2672
|
// collection without keyComparison
|
|
@@ -3009,7 +3038,11 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
3009
3038
|
'isStringMaxLength': 'Should not be more than %s characters',
|
|
3010
3039
|
'isJsonWebToken': 'Must be a valid JSON Web Token',
|
|
3011
3040
|
'query': 'Must be a valid response',
|
|
3012
|
-
|
|
3041
|
+
// #B233 rider - dropped: `isApiError` is not a rule, so nothing ever consulted this
|
|
3042
|
+
// label. The API-error path assigns the SERVER's message straight onto the error
|
|
3043
|
+
// object (main.js `errorObject[f].isApiError = result.fields[f]`) and never calls
|
|
3044
|
+
// replace(), so the entry only read as a translatable key that silently did nothing.
|
|
3045
|
+
//'isApiError': 'Condition not satisfied',
|
|
3013
3046
|
'isInList': 'Must be one of: %s'
|
|
3014
3047
|
};
|
|
3015
3048
|
/**
|
|
@@ -4023,19 +4056,20 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4023
4056
|
var errors = self[this['name']]['errors'] || {};
|
|
4024
4057
|
local.data[this.name] = self[this.name].value;
|
|
4025
4058
|
|
|
4026
|
-
|
|
4027
|
-
|
|
4028
|
-
|
|
4029
|
-
|
|
4030
|
-
|
|
4031
|
-
|
|
4032
|
-
|
|
4033
|
-
|
|
4034
|
-
|
|
4035
|
-
|
|
4036
|
-
|
|
4037
|
-
|
|
4038
|
-
|
|
4059
|
+
// #B233 - an empty value is adjudicated by isRequired alone: bypass on empty so a
|
|
4060
|
+
// required+empty field records only isRequired, not a second 'Condition not
|
|
4061
|
+
// satisfied'. This REVERSES a twice-declined exclusion (#B78 left `is` untouched,
|
|
4062
|
+
// #B82 re-declined it) on measurement: the old bypass was gated on
|
|
4063
|
+
// !errors['isRequired'] — i.e. disabled exactly when #B78 wants it applied — while
|
|
4064
|
+
// optional+empty already self-passed through it; and on required+empty the condition
|
|
4065
|
+
// is verdict-irrelevant (form validity is getErrors().count() and isRequired has
|
|
4066
|
+
// already recorded its error), so only the message list changes.
|
|
4067
|
+
// #B199 - strict: only the literal empty string is "empty". 0, false and null are
|
|
4068
|
+
// VALUES here and still evaluate the condition.
|
|
4069
|
+
// was: a two-disjunct guard whose arms were both DEAD (`x == '' && x != 0` has no
|
|
4070
|
+
// witness — `x == ''` forces ToNumber(x) === 0 for non-strings and x === '' for
|
|
4071
|
+
// strings), followed by the isRequired-gated string-only bypass described above.
|
|
4072
|
+
if ( this.value === '' ) {
|
|
4039
4073
|
isValid = true;
|
|
4040
4074
|
}
|
|
4041
4075
|
|
|
@@ -4176,7 +4210,8 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4176
4210
|
//delete errors['stack'];
|
|
4177
4211
|
}
|
|
4178
4212
|
|
|
4179
|
-
|
|
4213
|
+
// #B78 - keep .valid consistent with a surviving isRequired error.
|
|
4214
|
+
this.valid = isValid && !errors['isRequired'];
|
|
4180
4215
|
if ( errors.count() > 0 )
|
|
4181
4216
|
this['errors'] = errors;
|
|
4182
4217
|
|
|
@@ -4214,7 +4249,10 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4214
4249
|
|
|
4215
4250
|
// #B78 - an empty value is adjudicated by isRequired alone: bypass on empty so a
|
|
4216
4251
|
// required+empty field records only isRequired, not a second 'invalid' message.
|
|
4217
|
-
|
|
4252
|
+
// #B199 - strict: only the literal empty string is "empty". The loose ==
|
|
4253
|
+
// let 0, -0, false and [] coerce equal and ride this bypass, so e.g. a
|
|
4254
|
+
// JSON body's 0 in this field PASSED the rule outright.
|
|
4255
|
+
if ( this.value === '' ) {
|
|
4218
4256
|
isValid = true;
|
|
4219
4257
|
}
|
|
4220
4258
|
|
|
@@ -4256,7 +4294,10 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4256
4294
|
|
|
4257
4295
|
// #B78 - an empty value is adjudicated by isRequired alone: bypass on empty so a
|
|
4258
4296
|
// required+empty field records only isRequired, not a second 'invalid' message.
|
|
4259
|
-
|
|
4297
|
+
// #B199 - strict: only the literal empty string is "empty". The loose ==
|
|
4298
|
+
// let 0, -0, false and [] coerce equal and ride this bypass, so e.g. a
|
|
4299
|
+
// JSON body's 0 in this field PASSED the rule outright.
|
|
4300
|
+
if ( this.value === '' ) {
|
|
4260
4301
|
isValid = true;
|
|
4261
4302
|
}
|
|
4262
4303
|
|
|
@@ -4279,35 +4320,58 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4279
4320
|
}
|
|
4280
4321
|
|
|
4281
4322
|
/**
|
|
4282
|
-
* Check if boolean and convert to `true/false`
|
|
4283
|
-
*
|
|
4323
|
+
* Check if boolean and convert to `true/false` boolean if value is a string or a number.
|
|
4324
|
+
* Accepts `true`/`'true'`/`1` and `false`/`'false'`/`0` — the documented set.
|
|
4325
|
+
*
|
|
4326
|
+
* #B78 contract (#B235): an EMPTY value is adjudicated by `isRequired`
|
|
4327
|
+
* alone — the rule self-passes on the literal empty string, and the tail
|
|
4328
|
+
* keeps `this.valid` consistent with a surviving isRequired error
|
|
4329
|
+
* (Shape A). An ACCEPTED answer also clears a prior isRequired error:
|
|
4330
|
+
* `false` and `0` are loose-equal to the empty string so isRequired
|
|
4331
|
+
* flags them, but a recognized boolean false is a present answer (an
|
|
4332
|
+
* unchecked-but-required toggle does not fail). The pre-fix rescue ran
|
|
4333
|
+
* BEFORE the switch on a loose equality that also matched the empty
|
|
4334
|
+
* string, deleting the isRequired error a genuinely-empty field had
|
|
4335
|
+
* earned (#B235).
|
|
4284
4336
|
* */
|
|
4285
4337
|
self[el]['isBoolean'] = function() {
|
|
4286
4338
|
var val = null
|
|
4287
4339
|
, errors = self[this['name']]['errors'] || {}
|
|
4340
|
+
, isValid = false
|
|
4288
4341
|
;
|
|
4289
4342
|
|
|
4290
|
-
|
|
4343
|
+
// #B235 — was (the loose == also matched ''; `isValid = true` was a
|
|
4344
|
+
// dead write into the binding hoisted from below):
|
|
4345
|
+
// if ( errors['isRequired'] && this.value == false) {
|
|
4346
|
+
// isValid = true;
|
|
4347
|
+
// delete errors['isRequired'];
|
|
4348
|
+
// this['errors'] = errors;
|
|
4349
|
+
// }
|
|
4350
|
+
|
|
4351
|
+
if ( this.value === '' ) { // #B78/#B235 — emptiness is isRequired's verdict alone
|
|
4291
4352
|
isValid = true;
|
|
4292
|
-
|
|
4293
|
-
this
|
|
4294
|
-
|
|
4353
|
+
} else {
|
|
4354
|
+
switch(this.value) {
|
|
4355
|
+
case 'true':
|
|
4356
|
+
case true:
|
|
4357
|
+
case 1:
|
|
4358
|
+
val = this.value = local.data[this.name] = true;
|
|
4359
|
+
break;
|
|
4360
|
+
case 'false':
|
|
4361
|
+
case false:
|
|
4362
|
+
case 0:
|
|
4363
|
+
val = this.value = local.data[this.name] = false;
|
|
4364
|
+
break;
|
|
4365
|
+
}
|
|
4295
4366
|
|
|
4296
|
-
|
|
4297
|
-
|
|
4298
|
-
|
|
4299
|
-
|
|
4300
|
-
|
|
4301
|
-
|
|
4302
|
-
case 'false':
|
|
4303
|
-
case false:
|
|
4304
|
-
case 0:
|
|
4305
|
-
val = this.value = local.data[this.name] = false;
|
|
4306
|
-
break;
|
|
4367
|
+
isValid = (val !== null) ? true : false;
|
|
4368
|
+
// an engine-ACCEPTED answer clears the error that isRequired's
|
|
4369
|
+
// loose emptiness test recorded on false/0
|
|
4370
|
+
if ( val !== null && errors['isRequired'] ) {
|
|
4371
|
+
delete errors['isRequired'];
|
|
4372
|
+
}
|
|
4307
4373
|
}
|
|
4308
4374
|
|
|
4309
|
-
var isValid = (val !== null) ? true : false;
|
|
4310
|
-
|
|
4311
4375
|
if (!isValid) {
|
|
4312
4376
|
errors['isBoolean'] = replace(this.error || local.errorLabels['isBoolean'], this, 'isBoolean')
|
|
4313
4377
|
}
|
|
@@ -4317,7 +4381,8 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4317
4381
|
//delete errors['stack'];
|
|
4318
4382
|
}
|
|
4319
4383
|
|
|
4320
|
-
|
|
4384
|
+
// #B78 mirror (Shape A): keep .valid consistent with a surviving isRequired error
|
|
4385
|
+
this.valid = isValid && !errors['isRequired'];
|
|
4321
4386
|
if ( errors.count() > 0 )
|
|
4322
4387
|
this['errors'] = errors;
|
|
4323
4388
|
|
|
@@ -4362,7 +4427,10 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4362
4427
|
|
|
4363
4428
|
if ( +val === +val ) {
|
|
4364
4429
|
isValid = true;
|
|
4365
|
-
|
|
4430
|
+
// #B199 - strict !== : the loose != let the Number 0 (and -0/[] — and
|
|
4431
|
+
// '0', which the entry cast turns into 0) coerce equal to '' and skip
|
|
4432
|
+
// the bounds. Only the literal empty string bypasses.
|
|
4433
|
+
if ( !errors['isRequired'] && val !== '' ) {
|
|
4366
4434
|
len = val.toString().length;
|
|
4367
4435
|
// if so also test max and min length if defined
|
|
4368
4436
|
if (minLength && typeof(minLength) == 'number' && len < minLength) {
|
|
@@ -4429,6 +4497,33 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4429
4497
|
return self[this.name]
|
|
4430
4498
|
}
|
|
4431
4499
|
|
|
4500
|
+
/**
|
|
4501
|
+
* Check if value is a whole number.
|
|
4502
|
+
* - valid if the value is a number with no fractional part
|
|
4503
|
+
* - a numeric string is accepted; the value is cast to a `Number` on the way
|
|
4504
|
+
* OUT, after the bounds have been evaluated — whereas `isNumber` casts on
|
|
4505
|
+
* the way IN, before its own bounds. That ordering difference is why the
|
|
4506
|
+
* two rules must measure length differently at the bound site (see #B198)
|
|
4507
|
+
* - if the value is blank, no bound test is done: valid if not required
|
|
4508
|
+
*
|
|
4509
|
+
* Optional bounds constrain the LENGTH of the value's string form — the same
|
|
4510
|
+
* arity contract as `isString`/`isNumber`: `[N]` (or the scalar `N`) supplies
|
|
4511
|
+
* `minLength` only, and an exact length needs `[N, N]` since the exact-length
|
|
4512
|
+
* branch fires only when `minLength === maxLength`.
|
|
4513
|
+
*
|
|
4514
|
+
* #B198 — the bounds measure `val.toString().length`, never `val.length`. This
|
|
4515
|
+
* rule accepts a real `Number` (`+val === +val` passes for one), and
|
|
4516
|
+
* `Number.prototype.length` is `undefined`, so `val.length` made both bounds
|
|
4517
|
+
* silently inert on any numeric value — no error, no warn, `valid` left true.
|
|
4518
|
+
* Numbers reach here from JSON request bodies and from a preceding `toInteger`
|
|
4519
|
+
* (which leaves `Math.round()`'s real Number on `this.value`), so the browser
|
|
4520
|
+
* path was affected too. `isNumber` has always measured `toString().length`.
|
|
4521
|
+
*
|
|
4522
|
+
* @param {number} [ minLength ]
|
|
4523
|
+
* @param {number} [ maxLength ]
|
|
4524
|
+
*
|
|
4525
|
+
* @returns {object} result
|
|
4526
|
+
* */
|
|
4432
4527
|
self[el]['isInteger'] = function(minLength, maxLength) {
|
|
4433
4528
|
var val = this.value
|
|
4434
4529
|
, isValid = false
|
|
@@ -4440,13 +4535,18 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4440
4535
|
// test if val is a number
|
|
4441
4536
|
if ( +val === +val && val % 1 === 0 ) {
|
|
4442
4537
|
isValid = true;
|
|
4443
|
-
|
|
4538
|
+
// #B199 - strict !== : the loose != let the Number 0 (and -0/[]) coerce
|
|
4539
|
+
// equal to '' and skip the bounds. Only the literal empty string bypasses.
|
|
4540
|
+
if ( !errors['isRequired'] && val !== '' ) {
|
|
4444
4541
|
// if so also test max and min length if defined
|
|
4445
|
-
|
|
4542
|
+
// #B198 - was: `val.length`, which is `undefined` on a real Number
|
|
4543
|
+
// (this rule accepts one, and never casts), so both bounds were
|
|
4544
|
+
// silently inert. Measure the string form, as `isNumber` does.
|
|
4545
|
+
if (minLength && typeof(minLength) == 'number' && val.toString().length < minLength) {
|
|
4446
4546
|
isMinLength = false;
|
|
4447
4547
|
this['size'] = minLength;
|
|
4448
4548
|
}
|
|
4449
|
-
if (maxLength && typeof(maxLength) == 'number' && val.length > maxLength) {
|
|
4549
|
+
if (maxLength && typeof(maxLength) == 'number' && val.toString().length > maxLength) {
|
|
4450
4550
|
isMaxLength = false;
|
|
4451
4551
|
this['size'] = maxLength;
|
|
4452
4552
|
}
|
|
@@ -4618,7 +4718,10 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4618
4718
|
|
|
4619
4719
|
// #B78 - an empty value is adjudicated by isRequired alone: bypass on empty so a
|
|
4620
4720
|
// required+empty field records only isRequired, not a second 'invalid' message.
|
|
4621
|
-
|
|
4721
|
+
// #B199 - strict: only the literal empty string is "empty". The loose ==
|
|
4722
|
+
// let 0, -0, false and [] coerce equal and ride this bypass, so e.g. a
|
|
4723
|
+
// JSON body's 0 in this field PASSED the rule outright.
|
|
4724
|
+
if ( this.value === '' ) {
|
|
4622
4725
|
isValid = true
|
|
4623
4726
|
}
|
|
4624
4727
|
|
|
@@ -4723,7 +4826,9 @@ function FormValidatorUtil(data, $fields, xhrOptions, fieldsSet, culture) {
|
|
|
4723
4826
|
* // OR
|
|
4724
4827
|
* "isString": [7, 40] // Means at least 7 chars length and maximum 40 chars length
|
|
4725
4828
|
* // OR
|
|
4726
|
-
* "isString": [7] // Means
|
|
4829
|
+
* "isString": [7] // Means at least 7 chars length, same as 7 above: a one-element array supplies minLength only
|
|
4830
|
+
* // OR
|
|
4831
|
+
* "isString": [7, 7] // Means strictly equal to 7 chars length
|
|
4727
4832
|
* }
|
|
4728
4833
|
* }
|
|
4729
4834
|
* @param {number|undefined} [ minLength ]
|
|
@@ -5575,6 +5680,13 @@ function Routing() {
|
|
|
5575
5680
|
if ( typeof(routeObject.queryTimeout) != 'undefined' ) {
|
|
5576
5681
|
params.queryTimeout = parseTimeout(routeObject.queryTimeout);
|
|
5577
5682
|
}
|
|
5683
|
+
// #SPA1 — propagate the per-route content-negotiation capability to
|
|
5684
|
+
// req.routing.negotiate (top-level, NOT req.routing.param.* — the #CSRF2
|
|
5685
|
+
// trap). Assigned only when declared, so a routing.json that never mentions
|
|
5686
|
+
// `negotiate` produces a byte-identical params object.
|
|
5687
|
+
if ( typeof(routeObject.negotiate) != 'undefined' ) {
|
|
5688
|
+
params.negotiate = routeObject.negotiate;
|
|
5689
|
+
}
|
|
5578
5690
|
|
|
5579
5691
|
// isRoute
|
|
5580
5692
|
return self.compareUrls(params, routeObject.url, req);
|
|
@@ -6566,7 +6678,12 @@ function Routing() {
|
|
|
6566
6678
|
route.toUrl = function (ignoreWebRoot) {
|
|
6567
6679
|
|
|
6568
6680
|
var urlProps = null;
|
|
6569
|
-
|
|
6681
|
+
// Slice 3 (#SPA1) — the client-served map ships the derived boolean
|
|
6682
|
+
// `isRedirect` instead of `param.control` (a dispatch key that stays
|
|
6683
|
+
// server-side); server-side routes still carry the full `param`, so
|
|
6684
|
+
// both forms are honoured. The `this.param &&` guard also keeps a
|
|
6685
|
+
// param-less route from throwing here.
|
|
6686
|
+
if ( this.isRedirect === true || /^redirect$/i.test(this.param && this.param.control) ) {
|
|
6570
6687
|
urlProps = self.getUrlProps(this.bundle, (env||GINA_ENV));
|
|
6571
6688
|
}
|
|
6572
6689
|
|
|
@@ -10366,13 +10483,205 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
10366
10483
|
'setCustomRules': setCustomRules
|
|
10367
10484
|
};
|
|
10368
10485
|
|
|
10486
|
+
/**
|
|
10487
|
+
* backendIsPlainObject — plain-data-object test for the #B241 alias walk.
|
|
10488
|
+
* Arrays, Date instances and null are LEAF VALUES on the server form-body
|
|
10489
|
+
* path (a rule addresses the array/date itself), never containers to
|
|
10490
|
+
* descend into.
|
|
10491
|
+
*
|
|
10492
|
+
* @inner
|
|
10493
|
+
* @private
|
|
10494
|
+
* @param {*} value
|
|
10495
|
+
* @returns {boolean} true for a non-null, non-array, non-Date object
|
|
10496
|
+
*/
|
|
10497
|
+
var backendIsPlainObject = function (value) {
|
|
10498
|
+
return (
|
|
10499
|
+
value !== null
|
|
10500
|
+
&& typeof(value) == 'object'
|
|
10501
|
+
&& !Array.isArray(value)
|
|
10502
|
+
&& !(value instanceof Date)
|
|
10503
|
+
)
|
|
10504
|
+
};
|
|
10369
10505
|
|
|
10370
10506
|
/**
|
|
10371
|
-
*
|
|
10507
|
+
* backendAliasAugment — #B241: synthesize dotted-canon field entries
|
|
10508
|
+
* ALONGSIDE the raw posted keys so the per-field rule lookup can join.
|
|
10372
10509
|
*
|
|
10373
|
-
*
|
|
10374
|
-
*
|
|
10375
|
-
*
|
|
10510
|
+
* `parseRules` canonicalizes every rule key to a dotted path (a bracket
|
|
10511
|
+
* key `a[b]` becomes `a.b`, a nested rule tree flattens to its dotted
|
|
10512
|
+
* leaves) while the fields map keeps the RAW posted keys — so a rule
|
|
10513
|
+
* authored on a bracket key, or as a nested tree, never joined on this
|
|
10514
|
+
* path and the field was skipped with no warn (fail-open, check AND
|
|
10515
|
+
* drop directives alike). Both production wire shapes were affected:
|
|
10516
|
+
* flat bracket keys (the client posts the engine's name-keyed data as
|
|
10517
|
+
* JSON, which the server parses verbatim) and nested objects (the
|
|
10518
|
+
* multipart and urlencoded parsers expand bracket names).
|
|
10519
|
+
*
|
|
10520
|
+
* The originals are deliberately KEPT in the map: dollar-token
|
|
10521
|
+
* substitution reads the raw keys, so cross-field references to
|
|
10522
|
+
* bracket-named peers keep resolving exactly as before, and an all-flat
|
|
10523
|
+
* payload synthesizes nothing (identity). An alias is only added when
|
|
10524
|
+
* its key is still free, so a caller that already posts the dotted form
|
|
10525
|
+
* keeps its own entry untouched.
|
|
10526
|
+
*
|
|
10527
|
+
* @inner
|
|
10528
|
+
* @private
|
|
10529
|
+
* @param {object} fields - the fields map to augment IN PLACE
|
|
10530
|
+
* @param {object} data - the raw posted payload (never mutated)
|
|
10531
|
+
* @returns {object} aliases - { count: number, map: { alias: meta } }
|
|
10532
|
+
* where meta is { kind: 'bracket', original } or
|
|
10533
|
+
* { kind: 'nested', rootKey, path }
|
|
10534
|
+
*/
|
|
10535
|
+
var backendAliasAugment = function (fields, data) {
|
|
10536
|
+
var aliases = { count: 0, map: {} };
|
|
10537
|
+
var addNestedLeafAliases = function (rootKey, base, obj, pathSoFar) {
|
|
10538
|
+
for (var subKey in obj) {
|
|
10539
|
+
var aliasPath = pathSoFar.concat(subKey);
|
|
10540
|
+
var subAlias = base + '.' + subKey;
|
|
10541
|
+
if ( backendIsPlainObject(obj[subKey]) ) {
|
|
10542
|
+
addNestedLeafAliases(rootKey, subAlias, obj[subKey], aliasPath);
|
|
10543
|
+
} else if ( typeof(fields[subAlias]) == 'undefined' ) {
|
|
10544
|
+
fields[subAlias] = obj[subKey];
|
|
10545
|
+
aliases.map[subAlias] = { kind: 'nested', rootKey: rootKey, path: aliasPath };
|
|
10546
|
+
++aliases.count;
|
|
10547
|
+
}
|
|
10548
|
+
}
|
|
10549
|
+
};
|
|
10550
|
+
var key = null, alias = null;
|
|
10551
|
+
for (key in data) {
|
|
10552
|
+
if ( /\[/.test(key) ) {
|
|
10553
|
+
alias = key.replace(/\[/g, '.').replace(/\]/g, '');
|
|
10554
|
+
if ( typeof(fields[alias]) == 'undefined' ) {
|
|
10555
|
+
fields[alias] = data[key];
|
|
10556
|
+
aliases.map[alias] = { kind: 'bracket', original: key };
|
|
10557
|
+
++aliases.count;
|
|
10558
|
+
}
|
|
10559
|
+
} else if ( backendIsPlainObject(data[key]) ) {
|
|
10560
|
+
addNestedLeafAliases(key, key, data[key], [key]);
|
|
10561
|
+
}
|
|
10562
|
+
}
|
|
10563
|
+
return aliases;
|
|
10564
|
+
};
|
|
10565
|
+
|
|
10566
|
+
/**
|
|
10567
|
+
* backendAliasToBracketName — rebuild the client's DOM-name addressing
|
|
10568
|
+
* from a nested alias path (['account','username'] -> account[username]),
|
|
10569
|
+
* so restored error keys match what the browser side renders against.
|
|
10570
|
+
*
|
|
10571
|
+
* @inner
|
|
10572
|
+
* @private
|
|
10573
|
+
* @param {string} rootKey
|
|
10574
|
+
* @param {array} pathArr - path segments, rootKey first
|
|
10575
|
+
* @returns {string} the bracket-notation field name
|
|
10576
|
+
*/
|
|
10577
|
+
var backendAliasToBracketName = function (rootKey, pathArr) {
|
|
10578
|
+
var out = rootKey;
|
|
10579
|
+
for (var i = 1, len = pathArr.length; i < len; ++i) {
|
|
10580
|
+
out += '[' + pathArr[i] + ']';
|
|
10581
|
+
}
|
|
10582
|
+
return out;
|
|
10583
|
+
};
|
|
10584
|
+
|
|
10585
|
+
/**
|
|
10586
|
+
* backendRestoreAliases — #B241 egress: fold every alias outcome back
|
|
10587
|
+
* onto the original addressing, so the summary keeps today's contract.
|
|
10588
|
+
*
|
|
10589
|
+
* Error keys move to the DOM-name bracket form (the addressing the
|
|
10590
|
+
* client's error rendering looks up). On `.data` — which the engine has
|
|
10591
|
+
* already materialized (bracket originals arrive nested) — the alias
|
|
10592
|
+
* flat keys are stripped and their outcomes applied at the original
|
|
10593
|
+
* spot: an alias the engine dropped (an `exclude` directive) drops the
|
|
10594
|
+
* original leaf too, an alias a transform rewrote wins over the raw
|
|
10595
|
+
* value. Parents emptied BY AN EXCLUSION are pruned along that alias's
|
|
10596
|
+
* path only — an empty object the caller posted is not this function's
|
|
10597
|
+
* to remove.
|
|
10598
|
+
*
|
|
10599
|
+
* @inner
|
|
10600
|
+
* @private
|
|
10601
|
+
* @param {object} result - the { isValid, error, data } summary (mutated)
|
|
10602
|
+
* @param {object} aliases - backendAliasAugment's return value
|
|
10603
|
+
* @returns {object} result
|
|
10604
|
+
*/
|
|
10605
|
+
var backendRestoreAliases = function (result, aliases) {
|
|
10606
|
+
var alias = null, meta = null;
|
|
10607
|
+
var errors = {};
|
|
10608
|
+
for (alias in (result.error || {})) {
|
|
10609
|
+
meta = aliases.map[alias];
|
|
10610
|
+
if ( !meta ) {
|
|
10611
|
+
errors[alias] = result.error[alias];
|
|
10612
|
+
} else if ( meta.kind == 'bracket' ) {
|
|
10613
|
+
errors[meta.original] = result.error[alias];
|
|
10614
|
+
} else {
|
|
10615
|
+
errors[backendAliasToBracketName(meta.rootKey, meta.path)] = result.error[alias];
|
|
10616
|
+
}
|
|
10617
|
+
}
|
|
10618
|
+
result.error = errors;
|
|
10619
|
+
|
|
10620
|
+
var data = result.data;
|
|
10621
|
+
if ( !data || typeof(data) != 'object' ) {
|
|
10622
|
+
return result;
|
|
10623
|
+
}
|
|
10624
|
+
for (alias in aliases.map) {
|
|
10625
|
+
meta = aliases.map[alias];
|
|
10626
|
+
var aliasKept = Object.prototype.hasOwnProperty.call(data, alias);
|
|
10627
|
+
var aliasValue = aliasKept ? data[alias] : undefined;
|
|
10628
|
+
delete data[alias];
|
|
10629
|
+
|
|
10630
|
+
var segments = ( meta.kind == 'bracket' )
|
|
10631
|
+
? meta.original.replace(/\]/g, '').split(/\[/g)
|
|
10632
|
+
: meta.path;
|
|
10633
|
+
var sLen = segments.length - 1;
|
|
10634
|
+
var parent = data, s = 0;
|
|
10635
|
+
for (; s < sLen && parent; ++s) {
|
|
10636
|
+
parent = parent[ segments[s] ];
|
|
10637
|
+
}
|
|
10638
|
+
if ( !parent || typeof(parent) != 'object' ) {
|
|
10639
|
+
continue;
|
|
10640
|
+
}
|
|
10641
|
+
if ( !aliasKept ) {
|
|
10642
|
+
delete parent[ segments[sLen] ];
|
|
10643
|
+
// walk back up THIS path only, dropping parents the exclusion emptied
|
|
10644
|
+
for (var back = sLen - 1; back >= 0; --back) {
|
|
10645
|
+
var holder = data, b = 0;
|
|
10646
|
+
for (; b < back && holder; ++b) {
|
|
10647
|
+
holder = holder[ segments[b] ];
|
|
10648
|
+
}
|
|
10649
|
+
if (
|
|
10650
|
+
holder
|
|
10651
|
+
&& backendIsPlainObject(holder[ segments[back] ])
|
|
10652
|
+
&& Object.keys(holder[ segments[back] ]).length === 0
|
|
10653
|
+
) {
|
|
10654
|
+
delete holder[ segments[back] ];
|
|
10655
|
+
} else {
|
|
10656
|
+
break;
|
|
10657
|
+
}
|
|
10658
|
+
}
|
|
10659
|
+
} else {
|
|
10660
|
+
parent[ segments[sLen] ] = aliasValue;
|
|
10661
|
+
}
|
|
10662
|
+
}
|
|
10663
|
+
return result;
|
|
10664
|
+
};
|
|
10665
|
+
|
|
10666
|
+
/**
|
|
10667
|
+
* Backend init — the server half of form-body validation.
|
|
10668
|
+
*
|
|
10669
|
+
* Builds the fields map from the posted payload, parses the rule set
|
|
10670
|
+
* into the dotted canon, and runs the engine. #B241: bracket-notation
|
|
10671
|
+
* and nested-authored rule keys join through synthesized dotted aliases
|
|
10672
|
+
* (see backendAliasAugment above); verdict keys and the data egress are
|
|
10673
|
+
* restored to the original addressing before returning. The no-rules
|
|
10674
|
+
* branch is untouched and keeps returning the payload verbatim.
|
|
10675
|
+
*
|
|
10676
|
+
* @inner
|
|
10677
|
+
* @private
|
|
10678
|
+
* @param {object} rules - the form's rule set (authored keys)
|
|
10679
|
+
* @param {object} data - the posted payload
|
|
10680
|
+
* @param {string} [formId]
|
|
10681
|
+
* @param {string} [culture]
|
|
10682
|
+
* @returns {object} the { isValid, error, data } summary, or a bare
|
|
10683
|
+
* FormValidator instance on the no-rules branch
|
|
10684
|
+
*/
|
|
10376
10685
|
var backendInit = function (rules, data, formId, culture) {
|
|
10377
10686
|
|
|
10378
10687
|
var $form = ( typeof(formId) != 'undefined' ) ? { 'id': formId } : null;
|
|
@@ -10386,6 +10695,9 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
10386
10695
|
// parsing rules
|
|
10387
10696
|
if ( typeof(rules) != 'undefined' && rules.count() > 0 ) {
|
|
10388
10697
|
|
|
10698
|
+
// #B241 — join bracket/nested rule keys through dotted aliases
|
|
10699
|
+
var backendAliases = backendAliasAugment(fields, data);
|
|
10700
|
+
|
|
10389
10701
|
try {
|
|
10390
10702
|
parseRules(rules, '');
|
|
10391
10703
|
rules = checkForRulesImports(rules);
|
|
@@ -10395,7 +10707,16 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
10395
10707
|
|
|
10396
10708
|
backendProto.rules = instance.rules;
|
|
10397
10709
|
|
|
10398
|
-
|
|
10710
|
+
var backendResult = validate($form, fields, null, instance.rules, null, culture);
|
|
10711
|
+
if (
|
|
10712
|
+
backendAliases.count > 0
|
|
10713
|
+
&& backendResult
|
|
10714
|
+
&& typeof(backendResult.isValid) == 'function'
|
|
10715
|
+
&& typeof(backendResult.error) != 'undefined'
|
|
10716
|
+
) {
|
|
10717
|
+
backendRestoreAliases(backendResult, backendAliases);
|
|
10718
|
+
}
|
|
10719
|
+
return backendResult;
|
|
10399
10720
|
|
|
10400
10721
|
} else {
|
|
10401
10722
|
// without rules - by hand
|
|
@@ -14336,6 +14657,25 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
14336
14657
|
Object.defineProperty($el, 'value', descriptor);
|
|
14337
14658
|
}
|
|
14338
14659
|
|
|
14660
|
+
/**
|
|
14661
|
+
* addLiveForInput
|
|
14662
|
+
* Wires one form control for live checking: registers the gina event
|
|
14663
|
+
* name(s) the control's validation handler consumes, plus the handler
|
|
14664
|
+
* itself (field pass + whole-form silent pass -> updateSubmitTriggerState).
|
|
14665
|
+
* Text-like controls register change./keyup./focusin./focusout.<id>;
|
|
14666
|
+
* radios and checkboxes register changed.<id> (dispatched by their
|
|
14667
|
+
* update relays); a radio ALSO registers change.<id> (#B228) because the
|
|
14668
|
+
* form-level change proxy is the only dispatcher that fires on a user
|
|
14669
|
+
* pick and it only dispatches names that are registered.
|
|
14670
|
+
*
|
|
14671
|
+
* @inner
|
|
14672
|
+
* @param {object} $form - form instance record (`instance.$forms[id]` shape: `.rules`, `.target`)
|
|
14673
|
+
* @param {object} $el - control to wire (DOMObject)
|
|
14674
|
+
* @param {number} liveCheckTimer - shared debounce timer handle
|
|
14675
|
+
* @param {boolean} [isOtherTagAllowed=false] - admit non-input/textarea tags (selects, FACEs)
|
|
14676
|
+
*
|
|
14677
|
+
* @returns {undefined}
|
|
14678
|
+
* */
|
|
14339
14679
|
var addLiveForInput = function($form, $el, liveCheckTimer, isOtherTagAllowed) {
|
|
14340
14680
|
|
|
14341
14681
|
if (typeof(isOtherTagAllowed) == 'undefined' ) {
|
|
@@ -14408,6 +14748,23 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
14408
14748
|
eventsList[_e] = _evt;
|
|
14409
14749
|
++_e;
|
|
14410
14750
|
}
|
|
14751
|
+
// #B228 -- a RADIO also listens on the proxy-dispatched name: the
|
|
14752
|
+
// form-level change proxy dispatches `change.<id>` only when that
|
|
14753
|
+
// exact name is registered, and nothing else fires on a user pick
|
|
14754
|
+
// (the click proxy short-circuits into updateRadio, which never
|
|
14755
|
+
// dispatches; the bare-id relay has no live trigger) -- so the
|
|
14756
|
+
// `changed.<id>` registration above was consume-only dead wiring
|
|
14757
|
+
// on the pick path and the submit trigger kept its bind-time
|
|
14758
|
+
// state forever. The handler's radio arm has accepted
|
|
14759
|
+
// `change.`-typed events all along; checkboxes stay on their
|
|
14760
|
+
// working relay (change proxy -> updateCheckBox -> `changed.<id>`).
|
|
14761
|
+
if ( /^radio$/i.test($el.type) ) {
|
|
14762
|
+
_evt = 'change.'+$el.id;
|
|
14763
|
+
if ( typeof(gina.events[_evt]) == 'undefined' ) {
|
|
14764
|
+
eventsList[_e] = _evt;
|
|
14765
|
+
++_e;
|
|
14766
|
+
}
|
|
14767
|
+
}
|
|
14411
14768
|
}
|
|
14412
14769
|
|
|
14413
14770
|
if (eventsList.length > 0) {
|
|
@@ -17308,6 +17665,20 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17308
17665
|
$form.send(result['data']);
|
|
17309
17666
|
}
|
|
17310
17667
|
} else {
|
|
17668
|
+
// #B192 — release the submit latch. A rejected submit sends nothing, so it
|
|
17669
|
+
// never reaches the XHR settle (`xhr.onreadystatechange`), which was the only
|
|
17670
|
+
// other site clearing `isSubmitting`. Left latched, the live-check field
|
|
17671
|
+
// listener hard-returns on every subsequent keystroke, `updateSubmitTriggerState`
|
|
17672
|
+
// never runs again and the submit trigger keeps `aria-disabled="true"` +
|
|
17673
|
+
// `gina-form-submit-disabled` until the page is reloaded — and because the flag
|
|
17674
|
+
// lives on the `$forms[id]` object rather than a listener closure, it survives a
|
|
17675
|
+
// full unbind/rebind too. This branch IS the terminal no-send outcome; the valid
|
|
17676
|
+
// branch above deliberately keeps the latch until send() settles, which is what
|
|
17677
|
+
// keeps live-check quiet during a real in-flight submit.
|
|
17678
|
+
if ( instance.$forms[_id] ) {
|
|
17679
|
+
instance.$forms[_id].isSubmitting = false;
|
|
17680
|
+
}
|
|
17681
|
+
|
|
17311
17682
|
// #A11Y1 (slice 3) — failed submit: move focus to the first invalid field so
|
|
17312
17683
|
// assistive tech announces it (accessible name + aria-invalid + the
|
|
17313
17684
|
// aria-errormessage text). DOM order; hidden / unfocusable fields are skipped.
|
|
@@ -17597,6 +17968,18 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17597
17968
|
&& !/^(true|false)$/.test($target[i].value)
|
|
17598
17969
|
) {
|
|
17599
17970
|
fields[name] = false;
|
|
17971
|
+
} else if ( // #B221: same collection arm as getFormValidationInfos --
|
|
17972
|
+
// an unchecked non-boolean radio group with a truthy isRequired
|
|
17973
|
+
// is collected as an empty value so the submit-path validation
|
|
17974
|
+
// can adjudicate it (see the twin arm there for the rationale).
|
|
17975
|
+
$target[i].type == 'radio'
|
|
17976
|
+
&& rules
|
|
17977
|
+
&& typeof(rules[name]) != 'undefined'
|
|
17978
|
+
&& /^true$/i.test(rules[name].isRequired)
|
|
17979
|
+
&& typeof(rules[name].isBoolean) == 'undefined'
|
|
17980
|
+
&& typeof(fields[name]) == 'undefined'
|
|
17981
|
+
) {
|
|
17982
|
+
fields[name] = '';
|
|
17600
17983
|
}
|
|
17601
17984
|
|
|
17602
17985
|
} else {
|
|
@@ -17753,8 +18136,17 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17753
18136
|
/**
|
|
17754
18137
|
* getFormValidationInfos
|
|
17755
18138
|
*
|
|
18139
|
+
* Collects a form's named, non-disabled controls into a name->value map
|
|
18140
|
+
* (`fields`) plus a name->DOM-handle map (`$fields`). Radio groups: a
|
|
18141
|
+
* checked member's value is collected by the boolean/legacy arms; an
|
|
18142
|
+
* unchecked non-boolean group whose rule declares a truthy `isRequired`
|
|
18143
|
+
* is collected as an empty string (#B221) so the rule engine can
|
|
18144
|
+
* adjudicate it; any other unchecked group stays absent (native parity;
|
|
18145
|
+
* boolean-declared groups are owned by the force-false arm).
|
|
18146
|
+
*
|
|
17756
18147
|
* @param {object} $form - form target (DOMObject), not the instance
|
|
17757
18148
|
* @param {object} [rules]
|
|
18149
|
+
* @param {boolean} [isOnResetMode=false] - resets hidden/text values to their defaults while walking
|
|
17758
18150
|
*
|
|
17759
18151
|
* @returns {object} { .fields, .$fields, .rules }
|
|
17760
18152
|
*/
|
|
@@ -17910,6 +18302,28 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17910
18302
|
|
|
17911
18303
|
) {
|
|
17912
18304
|
fields[name] = false;
|
|
18305
|
+
} else if ( // #B221: an unchecked non-boolean radio group with a
|
|
18306
|
+
// declared truthy isRequired never entered `fields`, so no
|
|
18307
|
+
// rule (isRequired above all) could adjudicate it -- and a
|
|
18308
|
+
// radio-group-only form short-circuited the whole pass
|
|
18309
|
+
// (fields count == 0 reads as nothing-to-validate). Collect
|
|
18310
|
+
// it as an empty value so the engine's generic emptiness
|
|
18311
|
+
// test fires. A checked member is always collected by the
|
|
18312
|
+
// arms above; the already-collected guard keeps this arm
|
|
18313
|
+
// from resetting it when an unchecked member iterates after
|
|
18314
|
+
// the checked one. Groups with no rule, isRequired:false,
|
|
18315
|
+
// or an isBoolean declaration keep the legacy
|
|
18316
|
+
// absent-when-unchecked shape (boolean groups are owned by
|
|
18317
|
+
// the force-false arm above; optional groups bypass on
|
|
18318
|
+
// empty anyway, so their wire shape stays byte-identical).
|
|
18319
|
+
$form[i].type == 'radio'
|
|
18320
|
+
&& rules
|
|
18321
|
+
&& typeof(rules[name]) != 'undefined'
|
|
18322
|
+
&& /^true$/i.test(rules[name].isRequired)
|
|
18323
|
+
&& typeof(rules[name].isBoolean) == 'undefined'
|
|
18324
|
+
&& typeof(fields[name]) == 'undefined'
|
|
18325
|
+
) {
|
|
18326
|
+
fields[name] = '';
|
|
17913
18327
|
}
|
|
17914
18328
|
|
|
17915
18329
|
} else {
|
|
@@ -17933,6 +18347,26 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17933
18347
|
}
|
|
17934
18348
|
}
|
|
17935
18349
|
|
|
18350
|
+
/**
|
|
18351
|
+
* getCastedValue
|
|
18352
|
+
* Returns the value to use for `fieldName` — raw for the engine to
|
|
18353
|
+
* adjudicate, or cast/quoted for dynamised-rules substitution.
|
|
18354
|
+
*
|
|
18355
|
+
* Plain mode (`formatFields`): numeric-rule comma normalisation only;
|
|
18356
|
+
* real booleans pass through as-is and every other value stays RAW — the
|
|
18357
|
+
* engine's own rules cast on acceptance (#B236).
|
|
18358
|
+
* Dynamised mode (`getDynamisedRules`): values are spliced into a
|
|
18359
|
+
* stringified condition, so a boolean-ruled field casts to an unquoted
|
|
18360
|
+
* boolean operand, an empty value becomes a quoted empty string, and
|
|
18361
|
+
* other strings are quoted.
|
|
18362
|
+
*
|
|
18363
|
+
* @inner
|
|
18364
|
+
* @param {object} ruleObj - parsed rules (quoted booleans unquoted)
|
|
18365
|
+
* @param {object} fields - collected field values (MUTATED: comma normalisation)
|
|
18366
|
+
* @param {string} fieldName
|
|
18367
|
+
* @param {boolean|string} [isOnDynamisedRulesMode] - truthy/`'true'` in dynamised mode
|
|
18368
|
+
* @returns {*} the raw, cast, or quoted value
|
|
18369
|
+
*/
|
|
17936
18370
|
var getCastedValue = function(ruleObj, fields, fieldName, isOnDynamisedRulesMode) {
|
|
17937
18371
|
|
|
17938
18372
|
var isOnDynamisedRules = (
|
|
@@ -17977,7 +18411,16 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
17977
18411
|
|
|
17978
18412
|
if ( typeof(fields[fieldName]) == 'boolean') {
|
|
17979
18413
|
return fields[fieldName]
|
|
17980
|
-
|
|
18414
|
+
// #B236 — the boolean pre-cast survives ONLY in dynamised-rules mode, where a
|
|
18415
|
+
// referenced isBoolean field must splice into a stringified condition as an
|
|
18416
|
+
// unquoted boolean operand (`$flag === true`). On the PLAIN pass it funneled
|
|
18417
|
+
// every value not matching the case-insensitive literal `true` to `false`
|
|
18418
|
+
// BEFORE the engine ran, so junk (and the HTML checkbox default `on`, and
|
|
18419
|
+
// the number 1) validated clean and persisted as `false` on the server auto
|
|
18420
|
+
// path. The engine is the single adjudicator now — the same contract the
|
|
18421
|
+
// routing requirements surface always enforced.
|
|
18422
|
+
// was: `} else if (ruleObj[fieldName].isBoolean) {`
|
|
18423
|
+
} else if (isOnDynamisedRules && ruleObj[fieldName].isBoolean) {
|
|
17981
18424
|
return (/^true$/i.test(fields[fieldName])) ? true : false;
|
|
17982
18425
|
}
|
|
17983
18426
|
|
|
@@ -18049,7 +18492,18 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18049
18492
|
|
|
18050
18493
|
stringifiedRules = stringifiedRules.replace(re, fieldValue );
|
|
18051
18494
|
}
|
|
18052
|
-
|
|
18495
|
+
// #B234 — this second loop is a DOM FALLBACK: it re-derives each splice
|
|
18496
|
+
// value from the live element (`$fields[...].value` / `.checked`), and
|
|
18497
|
+
// the server auto path (`backendInit`) passes `$fields = null`, so ANY
|
|
18498
|
+
// `$` surviving loop 1 threw here — a regex end-anchor in an `is`
|
|
18499
|
+
// condition, or a `$` inside a human-readable message string. Loop 1
|
|
18500
|
+
// already replaces every KNOWN field's token, so what reaches loop 2 is
|
|
18501
|
+
// a leftover it structurally cannot match anyway: skipping when there is
|
|
18502
|
+
// no DOM matches what the client does when this re-scan no-ops, and
|
|
18503
|
+
// leaves every previously-working substitution byte-identical. Same
|
|
18504
|
+
// `$fields &&` guard shape as the #B127 precedent one function later.
|
|
18505
|
+
// was: `if ( /\$(.*)/.test(stringifiedRules) ) {`
|
|
18506
|
+
if ( $fields && /\$(.*)/.test(stringifiedRules) ) {
|
|
18053
18507
|
for (let i = 0, len = arrFields.length; i < len; i++) {
|
|
18054
18508
|
_field = arrFields[i].replace(/\-|\_|\@|\#|\.|\[|\]/g, '\\$&');
|
|
18055
18509
|
re = new RegExp('\\$'+_field, 'g');
|
|
@@ -18114,6 +18568,24 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18114
18568
|
|
|
18115
18569
|
|
|
18116
18570
|
var re = null, flags = null, args = null;
|
|
18571
|
+
/**
|
|
18572
|
+
* Apply every rule declared for one field to the FormValidator instance `d`.
|
|
18573
|
+
*
|
|
18574
|
+
* Array-form rules (`isInList: [...]`) get their FIRST argument scanned for
|
|
18575
|
+
* `$`-prefixed tokens; a token resolving to a real field (a `d` key with a
|
|
18576
|
+
* defined `.value`) is substituted with that value, anything else stays
|
|
18577
|
+
* LITERAL (#B239 — the blind deref crashed on unknown names and spliced
|
|
18578
|
+
* "undefined" on engine-method-name collisions). Later elements are never
|
|
18579
|
+
* scanned. Cross-field refs inside array rules are consumed upstream by
|
|
18580
|
+
* getDynamisedRules loop 1 (quoted — #B240), so in practice only leftover
|
|
18581
|
+
* non-field tokens reach the scan here.
|
|
18582
|
+
*
|
|
18583
|
+
* @inner
|
|
18584
|
+
* @param {string} field - field name (key into `rules`, `fields` and `d`)
|
|
18585
|
+
* @param {object} rules - parsed rule set for the whole form
|
|
18586
|
+
* @param {object} fields - collected field values
|
|
18587
|
+
* @returns {void} verdicts land on `d[field]` / `d.error`
|
|
18588
|
+
*/
|
|
18117
18589
|
var checkFieldAgainstRules = function(field, rules, fields) {
|
|
18118
18590
|
// ignore field if used as a _case_field
|
|
18119
18591
|
|
|
@@ -18212,7 +18684,25 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18212
18684
|
if ( /\$[\-\w\[\]]*/.test(args[0]) ) {
|
|
18213
18685
|
var foundVariables = args[0].match(/\$[\-\w\[\]]*/g);
|
|
18214
18686
|
for (var v = 0, vLen = foundVariables.length; v < vLen; ++v) {
|
|
18215
|
-
|
|
18687
|
+
// #B239 — the deref used to be blind, throwing
|
|
18688
|
+
// `TypeError: Cannot read properties of undefined` on
|
|
18689
|
+
// BOTH paths for any token naming no field (`d` is the
|
|
18690
|
+
// FormValidator field map on the client AND the server),
|
|
18691
|
+
// and splicing the string "undefined" for a token whose
|
|
18692
|
+
// name collides with an engine METHOD (isValid, toData —
|
|
18693
|
+
// defined keys with no `.value`). A token that does not
|
|
18694
|
+
// resolve to a real field now stays LITERAL, so strict
|
|
18695
|
+
// comparison applies. Cross-field refs inside array
|
|
18696
|
+
// rules remain owned by #B240 (upstream loop-1 quoting).
|
|
18697
|
+
// was: args[0] = args[0].replace( foundVariables[v], d[foundVariables[v].replace('$', '')].value )
|
|
18698
|
+
var _refName = foundVariables[v].replace('$', '');
|
|
18699
|
+
if (
|
|
18700
|
+
typeof(d[_refName]) == 'undefined'
|
|
18701
|
+
|| typeof(d[_refName].value) == 'undefined'
|
|
18702
|
+
) {
|
|
18703
|
+
continue;
|
|
18704
|
+
}
|
|
18705
|
+
args[0] = args[0].replace( foundVariables[v], d[_refName].value );
|
|
18216
18706
|
}
|
|
18217
18707
|
}
|
|
18218
18708
|
d[field][rule].apply(d[field], args);
|
|
@@ -18431,6 +18921,8 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18431
18921
|
var localRules = null, caseName = null;
|
|
18432
18922
|
var localRuleObj = null, skipTest = null;
|
|
18433
18923
|
var localFieldType = null;
|
|
18924
|
+
var caseValueBackup = null; // #B229 — see the `caseName == field` arm below
|
|
18925
|
+
var baseValueBackup = null; // #B230 — see the base-rule restore below
|
|
18434
18926
|
|
|
18435
18927
|
//console.debug('parsing ', fields, $fields, rules);
|
|
18436
18928
|
if ( typeof(rules) != 'undefined' ) {
|
|
@@ -18815,13 +19307,80 @@ function ValidatorPlugin(rules, data, formId, culture) {
|
|
|
18815
19307
|
}
|
|
18816
19308
|
}
|
|
18817
19309
|
|
|
18818
|
-
if (isInCase
|
|
19310
|
+
if (isInCase) continue;
|
|
19311
|
+
|
|
19312
|
+
// #B229 — a field that DRIVES a `_case_` still owns its BASE
|
|
19313
|
+
// rules. `caseName` is assigned inside the `_case_` scan loop
|
|
19314
|
+
// above, which runs in full on EVERY field iteration, so at this
|
|
19315
|
+
// point it always holds the LAST scanned `_case_` key's driver
|
|
19316
|
+
// name. The old combined tail therefore skipped the whole rest of
|
|
19317
|
+
// the iteration for that driver — base-rule check included — so a
|
|
19318
|
+
// rule shape { "group": { "isRequired": true }, "_case_group": {…} }
|
|
19319
|
+
// never adjudicated `group` on the bind pass, the live-check
|
|
19320
|
+
// global pass OR the submit pass: the form never gated and an
|
|
19321
|
+
// empty submit went out unvalidated (the #B221 silent-submit
|
|
19322
|
+
// class, resurfacing for the self-driving shape — downstream of
|
|
19323
|
+
// #B221's collection fix, which already admits the group as '').
|
|
19324
|
+
// The driver's `allFields` entry is restored around the call:
|
|
19325
|
+
// checkFieldAgainstRules ends every applied rule with
|
|
19326
|
+
// `delete fields[field]` on the object it is handed, and
|
|
19327
|
+
// `allFields[caseName]` is the case VALUE the scan block re-reads
|
|
19328
|
+
// on every later field iteration — a deleted entry re-seeds from
|
|
19329
|
+
// `$allFields[name].value`, which for a radio group is the FIRST
|
|
19330
|
+
// member's value regardless of `.checked` (#B230, pre-existing).
|
|
19331
|
+
// The direct-case block below stays skipped for the driver, so
|
|
19332
|
+
// WHICH conditions apply is unchanged (measured: that block is
|
|
19333
|
+
// never entered for a self-driving case, pre-fix or post-fix).
|
|
19334
|
+
// was:
|
|
19335
|
+
// if (isInCase || caseName == field) continue;
|
|
19336
|
+
if ( caseName == field ) {
|
|
19337
|
+
if ( typeof(rules[field]) != 'undefined' ) {
|
|
19338
|
+
caseValueBackup = allFields[field];
|
|
19339
|
+
checkFieldAgainstRules(field, rules, allFields);
|
|
19340
|
+
if (
|
|
19341
|
+
typeof(allFields[field]) == 'undefined'
|
|
19342
|
+
&& typeof(caseValueBackup) != 'undefined'
|
|
19343
|
+
) {
|
|
19344
|
+
allFields[field] = caseValueBackup;
|
|
19345
|
+
}
|
|
19346
|
+
}
|
|
19347
|
+
continue;
|
|
19348
|
+
}
|
|
18819
19349
|
|
|
19350
|
+
// #B230 — a `_case_` driver's entry in `allFields` IS the case
|
|
19351
|
+
// VALUE every later reader consumes: the scan block above
|
|
19352
|
+
// re-reads it on every subsequent field iteration (a missing
|
|
19353
|
+
// entry re-seeds from `$allFields[name].value` — a radio
|
|
19354
|
+
// group's FIRST member regardless of `.checked`), and the
|
|
19355
|
+
// direct-case block below reads it in THIS iteration. Site
|
|
19356
|
+
// 3/3's adjudication deletes it (checkFieldAgainstRules ends
|
|
19357
|
+
// every applied rule with `delete fields[field]` on the
|
|
19358
|
+
// object it is handed), so a non-last driver's conditions
|
|
19359
|
+
// matched a value the user never picked on later scans and
|
|
19360
|
+
// matched nothing (`undefined`) in its own direct-case pass.
|
|
19361
|
+
// Back the entry up and restore it after the check — gated
|
|
19362
|
+
// on the field driving a `_case_` in the live `rules` OR in
|
|
19363
|
+
// the pass-entry clone `allRules`: inside a direct-case
|
|
19364
|
+
// recursion `rules` is the condition's own rule set (no
|
|
19365
|
+
// `_case_` keys), so `hasCase` alone is blind there
|
|
19366
|
+
// (measured — the union is load-bearing). Non-driver fields
|
|
19367
|
+
// keep the delete untouched: the pull-in gate, the
|
|
19368
|
+
// direct-case exclude injection and the async-`query`
|
|
19369
|
+
// re-validation input all read those absences today.
|
|
19370
|
+
baseValueBackup = allFields[field];
|
|
18820
19371
|
// check each field against rule only if rule exists 3/3
|
|
18821
19372
|
if ( typeof(rules[field]) != 'undefined' ) {
|
|
18822
19373
|
//checkFieldAgainstRules(field, rules, fields);
|
|
18823
19374
|
checkFieldAgainstRules(field, rules, allFields);
|
|
18824
19375
|
}
|
|
19376
|
+
// #B230 restore — see the block comment above
|
|
19377
|
+
if (
|
|
19378
|
+
( hasCase || typeof(allRules['_case_' + field]) != 'undefined' )
|
|
19379
|
+
&& typeof(baseValueBackup) != 'undefined'
|
|
19380
|
+
&& typeof(allFields[field]) == 'undefined'
|
|
19381
|
+
) {
|
|
19382
|
+
allFields[field] = baseValueBackup;
|
|
19383
|
+
}
|
|
18825
19384
|
|
|
18826
19385
|
if (hasCase) {
|
|
18827
19386
|
++i; // add sub level
|
|
@@ -19812,6 +20371,13 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
19812
20371
|
* return true (handled — caller must NOT also load).
|
|
19813
20372
|
* - never warmed (undefined) -> return false so the caller loads itself.
|
|
19814
20373
|
*
|
|
20374
|
+
* Dev toolbar (#B225): both consume branches mirror the cold-click
|
|
20375
|
+
* loaded path's dev gate — GINA_ENV_IS_DEV sets the toolbar overlay
|
|
20376
|
+
* from the body right before the dispatch — so a warmed open surfaces
|
|
20377
|
+
* its rendered data exactly like a cold one. The set lives here and
|
|
20378
|
+
* NOT in handleLoadedBody: the cold path routes through the dispatcher
|
|
20379
|
+
* too, so a set there would double-fire the overlay.
|
|
20380
|
+
*
|
|
19815
20381
|
* @inner
|
|
19816
20382
|
* @param {string} url - the resolved popin URL.
|
|
19817
20383
|
* @param {object} $popin - the registered popin.
|
|
@@ -19843,6 +20409,7 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
19843
20409
|
// clear the (repopulated) slot: the completion writes the
|
|
19844
20410
|
// cache back even after this adoption consumed the body.
|
|
19845
20411
|
$popin._contentUrl = url;
|
|
20412
|
+
if (GINA_ENV_IS_DEV) { updateToolbar(body); }
|
|
19846
20413
|
handleLoadedBody(body, $popin, ensurePopinDialog($popin));
|
|
19847
20414
|
}
|
|
19848
20415
|
});
|
|
@@ -19855,6 +20422,7 @@ define('gina/popin', [ 'require', 'lib/domain', 'lib/merge', 'utils/events' ], f
|
|
|
19855
20422
|
// the NEXT open render this open's generation).
|
|
19856
20423
|
$popin._contentUrl = url;
|
|
19857
20424
|
var $el = ensurePopinDialog($popin);
|
|
20425
|
+
if (GINA_ENV_IS_DEV) { updateToolbar(body); }
|
|
19858
20426
|
handleLoadedBody(body, $popin, $el);
|
|
19859
20427
|
return true;
|
|
19860
20428
|
}
|
|
@@ -22545,6 +23113,783 @@ if ( ( typeof(module) !== 'undefined' ) && module.exports ) {
|
|
|
22545
23113
|
// Publish as AMD module
|
|
22546
23114
|
define('gina/storage', ['helpers/dateFormat', 'helpers/prototypes'],function() { return StoragePlugin })
|
|
22547
23115
|
};
|
|
23116
|
+
define('gina/nav', [ 'require', 'lib/merge', 'lib/uuid', 'utils/events' ], function (require) {
|
|
23117
|
+
|
|
23118
|
+
var merge = require('lib/merge');
|
|
23119
|
+
var uuid = require('lib/uuid');
|
|
23120
|
+
|
|
23121
|
+
require('utils/events'); // events
|
|
23122
|
+
|
|
23123
|
+
/**
|
|
23124
|
+
* Gina Navigation Handler (#SPA1 — Tier 1)
|
|
23125
|
+
*
|
|
23126
|
+
* Turns link clicks into fragment swaps on routes that opted into content
|
|
23127
|
+
* negotiation: the matched route must declare `negotiate: true` in
|
|
23128
|
+
* routing.json, and the page must carry a `data-gina-nav` swap region.
|
|
23129
|
+
*
|
|
23130
|
+
* Activation is OPT-IN per page/project: the first element carrying
|
|
23131
|
+
* `data-gina-nav` (with any value but `"false"` — that spelling is the
|
|
23132
|
+
* per-link opt-out) is BOTH the opt-in signal and the region whose content
|
|
23133
|
+
* each fetched fragment replaces. Without the marker the handler stays
|
|
23134
|
+
* inert, so upgrading the framework never changes navigation behaviour on
|
|
23135
|
+
* existing pages.
|
|
23136
|
+
*
|
|
23137
|
+
* What a navigation does:
|
|
23138
|
+
* 1. a delegated document-level click listener resolves the anchor and
|
|
23139
|
+
* defers to the link plugin (`data-gina-link*`) and to dialog/popin
|
|
23140
|
+
* triggers (`data-gina-dialog*` / `data-gina-popin-*`), skips modified
|
|
23141
|
+
* and non-left clicks, `target`/`download` links, cross-origin URLs,
|
|
23142
|
+
* in-page hash moves and `data-gina-nav="false"` links;
|
|
23143
|
+
* 2. the URL is matched client-side against the served routing table
|
|
23144
|
+
* (`gina.config.routing`) with the same semantics as the server scan —
|
|
23145
|
+
* first match in table order wins; interception happens only when that
|
|
23146
|
+
* route declares `negotiate: true` and accepts GET;
|
|
23147
|
+
* 3. the fragment is fetched over a FRESH XMLHttpRequest carrying
|
|
23148
|
+
* `X-Gina-Navigate: fragment` (the negotiation signal) AND
|
|
23149
|
+
* `X-Requested-With: XMLHttpRequest` (without it the render path
|
|
23150
|
+
* re-wraps a layoutless body into a full `<html>` shell);
|
|
23151
|
+
* 4. a genuine negotiated answer — 2xx, HTML, `Vary` advertising
|
|
23152
|
+
* `X-Gina-Navigate` — replaces the region's content, re-injects the
|
|
23153
|
+
* fragment's src-bearing scripts the document does not already have
|
|
23154
|
+
* (inline scripts are NOT executed — same contract as popin content),
|
|
23155
|
+
* rebinds id-bearing forms through the live validator, closes any open
|
|
23156
|
+
* popin (a full navigation would have unloaded it), pushes a history
|
|
23157
|
+
* entry, restores focus/scroll, and fires `success`;
|
|
23158
|
+
* 5. ANY other answer falls back to a full-page navigation: non-2xx,
|
|
23159
|
+
* timeout, network error, an un-negotiated 2xx (the `Vary` check —
|
|
23160
|
+
* a client/server matching disagreement degrades to a normal page
|
|
23161
|
+
* load), or a JSON `{location}` redirect (hard-followed, the
|
|
23162
|
+
* established XHR convention).
|
|
23163
|
+
*
|
|
23164
|
+
* Browser floor: `history.pushState` + `Element.closest` (feature-guarded).
|
|
23165
|
+
* The ActiveX/attachEvent branches other plugins carry are unreachable
|
|
23166
|
+
* behind that floor, so this module uses plain `XMLHttpRequest` and a raw
|
|
23167
|
+
* `window.addEventListener('popstate', …)` — `utils/events`' addListener
|
|
23168
|
+
* reads `element.getAttribute` at registration, which `window` lacks.
|
|
23169
|
+
*
|
|
23170
|
+
* Usage — declarative (boot shim constructs when the marker exists):
|
|
23171
|
+
* <main data-gina-nav>…server-rendered page content…</main>
|
|
23172
|
+
*
|
|
23173
|
+
* Usage — programmatic:
|
|
23174
|
+
* gina.nav.navigate('/section/item-1');
|
|
23175
|
+
*
|
|
23176
|
+
* Events: `ready`, `navigate` (before the fetch), `success` (after a
|
|
23177
|
+
* swap), `error` (before a fallback navigation).
|
|
23178
|
+
*
|
|
23179
|
+
* @param {object} [options]
|
|
23180
|
+
* @param {number} [options.timeout=10000] - fragment fetch budget in ms; a
|
|
23181
|
+
* timeout falls back to a full-page navigation
|
|
23182
|
+
* */
|
|
23183
|
+
function Nav(options) {
|
|
23184
|
+
|
|
23185
|
+
this.plugin = 'nav';
|
|
23186
|
+
|
|
23187
|
+
var events = ['init', 'ready', 'navigate', 'success', 'error'];
|
|
23188
|
+
registerEvents(this.plugin, events);
|
|
23189
|
+
|
|
23190
|
+
var self = { // local use only
|
|
23191
|
+
'options' : {
|
|
23192
|
+
// Fragment fetch budget (ms) — on expiry the navigation falls
|
|
23193
|
+
// back to a full page load of the same URL.
|
|
23194
|
+
'timeout': 10000
|
|
23195
|
+
}
|
|
23196
|
+
};
|
|
23197
|
+
|
|
23198
|
+
var instance = {
|
|
23199
|
+
plugin : this.plugin,
|
|
23200
|
+
id : 'gina-nav-' + uuid(),
|
|
23201
|
+
on : on,
|
|
23202
|
+
eventData : {},
|
|
23203
|
+
|
|
23204
|
+
target : document, // by default; the `data-gina-nav` region once activated
|
|
23205
|
+
isReady : false,
|
|
23206
|
+
initialized : false
|
|
23207
|
+
};
|
|
23208
|
+
|
|
23209
|
+
// Navigation sequence — a response is applied only when its sequence is
|
|
23210
|
+
// still current, so an aborted/superseded XHR can never swap stale
|
|
23211
|
+
// content (#B175: the module-scope shared-XHR shape is the defect class
|
|
23212
|
+
// this deliberately avoids — every navigation opens a FRESH XHR).
|
|
23213
|
+
var _navSeq = 0;
|
|
23214
|
+
var _xhr = null;
|
|
23215
|
+
// Per-rule compiled matchers + the routing table object they were
|
|
23216
|
+
// compiled from. The table is read LAZILY at each navigation: it
|
|
23217
|
+
// arrives from an async fetch and can land after `isFrameworkLoaded`.
|
|
23218
|
+
var _compiled = null;
|
|
23219
|
+
var _compiledFor = null;
|
|
23220
|
+
// Scripts present at activation + scripts nav injected across swaps
|
|
23221
|
+
// (the popin `parentScripts` model): a fragment's src-bearing script is
|
|
23222
|
+
// injected once, never re-executed on later swaps.
|
|
23223
|
+
var _parentScripts = [];
|
|
23224
|
+
var _injectedScripts = [];
|
|
23225
|
+
// pathname+search last rendered — popstate events that do not change it
|
|
23226
|
+
// are hash-only moves and are left to the browser.
|
|
23227
|
+
var _currentUrl = null;
|
|
23228
|
+
// Delegated listeners are installed once per instance lifecycle.
|
|
23229
|
+
var _listenersInstalled = false;
|
|
23230
|
+
|
|
23231
|
+
|
|
23232
|
+
/**
|
|
23233
|
+
* Safe decodeURI — mirrors the server's #B30 discipline (safeDecodeURI):
|
|
23234
|
+
* a malformed percent-sequence falls back to the raw input instead of
|
|
23235
|
+
* throwing, so a hand-typed `%` in a URL can never crash the matcher.
|
|
23236
|
+
*
|
|
23237
|
+
* @inner
|
|
23238
|
+
* @private
|
|
23239
|
+
* @param {string} str
|
|
23240
|
+
* @returns {string} decoded string, or `str` unchanged when malformed
|
|
23241
|
+
*/
|
|
23242
|
+
var safeDecode = function(str) {
|
|
23243
|
+
try {
|
|
23244
|
+
return decodeURI(str);
|
|
23245
|
+
} catch (decodeErr) {
|
|
23246
|
+
return str;
|
|
23247
|
+
}
|
|
23248
|
+
};
|
|
23249
|
+
|
|
23250
|
+
/**
|
|
23251
|
+
* Compiles one routing requirement value into a RegExp, mirroring the
|
|
23252
|
+
* server's fitsWithRequirements parsing verbatim: a `/body/flags` value
|
|
23253
|
+
* is split with the same greedy `match(/\/(.*)\//)` extraction (so both
|
|
23254
|
+
* sides accept identical values), a bare string feeds `new RegExp()`
|
|
23255
|
+
* directly. `validator::` values never reach the client (filtered out
|
|
23256
|
+
* of the served map).
|
|
23257
|
+
*
|
|
23258
|
+
* @inner
|
|
23259
|
+
* @private
|
|
23260
|
+
* @param {string} requirement
|
|
23261
|
+
* @returns {object|null} RegExp, or null when malformed — the variant
|
|
23262
|
+
* then becomes client-unmatchable (fail-open to a normal
|
|
23263
|
+
* browser navigation, where the server would 500 instead)
|
|
23264
|
+
*/
|
|
23265
|
+
var parseRequirement = function(requirement) {
|
|
23266
|
+
try {
|
|
23267
|
+
if ( /^\//.test(requirement) ) {
|
|
23268
|
+
var body = requirement.match(/\/(.*)\//).pop();
|
|
23269
|
+
var flags = requirement.replace('/' + body + '/', '');
|
|
23270
|
+
return new RegExp(body, flags);
|
|
23271
|
+
}
|
|
23272
|
+
return new RegExp(requirement);
|
|
23273
|
+
} catch (reErr) {
|
|
23274
|
+
return null;
|
|
23275
|
+
}
|
|
23276
|
+
};
|
|
23277
|
+
|
|
23278
|
+
/**
|
|
23279
|
+
* Compiles ONE url variant of a route into an array of segment
|
|
23280
|
+
* matchers, or null when the variant cannot be matched client-side.
|
|
23281
|
+
*
|
|
23282
|
+
* Mirrored server semantics (parseRouting + fitsWithRequirements):
|
|
23283
|
+
* literal segments compare strict-equal; a pure `:key` segment tests
|
|
23284
|
+
* its requirement when one is declared, otherwise it accepts any
|
|
23285
|
+
* NON-EMPTY segment only when the served `param` block declares the
|
|
23286
|
+
* key (fitsWithRequirements returns false otherwise). A mixed
|
|
23287
|
+
* literal+param segment (`page:number`) is matchable server-side but
|
|
23288
|
+
* deliberately UNMATCHABLE here in Tier 1 — no interception, normal
|
|
23289
|
+
* navigation (false-negative-safe).
|
|
23290
|
+
*
|
|
23291
|
+
* @inner
|
|
23292
|
+
* @private
|
|
23293
|
+
* @param {string} url - one variant (already comma-split)
|
|
23294
|
+
* @param {object} route - the served route object
|
|
23295
|
+
* @returns {array|null} segment matchers ({lit} | {key, re}) or null
|
|
23296
|
+
*/
|
|
23297
|
+
var compileVariant = function(url, route) {
|
|
23298
|
+
var segments = String(url).split(/\//);
|
|
23299
|
+
var out = [];
|
|
23300
|
+
for (var i = 0, len = segments.length; i < len; ++i) {
|
|
23301
|
+
var seg = segments[i];
|
|
23302
|
+
if ( seg.indexOf(':') < 0 ) {
|
|
23303
|
+
out.push({ 'lit': seg });
|
|
23304
|
+
continue;
|
|
23305
|
+
}
|
|
23306
|
+
if ( !/^\:[-_a-zA-Z0-9]+$/.test(seg) ) {
|
|
23307
|
+
return null;
|
|
23308
|
+
}
|
|
23309
|
+
var key = seg.substring(1);
|
|
23310
|
+
if ( route.requirements && typeof(route.requirements[key]) != 'undefined' ) {
|
|
23311
|
+
var re = parseRequirement(String(route.requirements[key]));
|
|
23312
|
+
if (!re) {
|
|
23313
|
+
return null;
|
|
23314
|
+
}
|
|
23315
|
+
out.push({ 'key': key, 're': re });
|
|
23316
|
+
continue;
|
|
23317
|
+
}
|
|
23318
|
+
if ( route.param && typeof(route.param[key]) != 'undefined' ) {
|
|
23319
|
+
out.push({ 'key': key, 're': null });
|
|
23320
|
+
continue;
|
|
23321
|
+
}
|
|
23322
|
+
return null;
|
|
23323
|
+
}
|
|
23324
|
+
return out;
|
|
23325
|
+
};
|
|
23326
|
+
|
|
23327
|
+
/**
|
|
23328
|
+
* Returns the compiled candidate list for the CURRENT routing table,
|
|
23329
|
+
* (re)compiling when the table object changed identity. Candidate
|
|
23330
|
+
* filtering mirrors the server scan: paramless routes are skipped,
|
|
23331
|
+
* foreign-bundle routes are skipped, and — for a GET navigation —
|
|
23332
|
+
* single-method routes survive only as GET or DELETE (the server's
|
|
23333
|
+
* GET→DELETE override keeps such a route as a BLOCKING candidate so
|
|
23334
|
+
* the client can never intercept across it), while multi-method routes
|
|
23335
|
+
* always reach URL comparison.
|
|
23336
|
+
*
|
|
23337
|
+
* @inner
|
|
23338
|
+
* @private
|
|
23339
|
+
* @returns {array|null} compiled candidates, or null when the routing
|
|
23340
|
+
* table has not been fetched yet
|
|
23341
|
+
*/
|
|
23342
|
+
var getCompiled = function() {
|
|
23343
|
+
var config = ( window.gina && window.gina.config ) ? window.gina.config : null;
|
|
23344
|
+
var routing = ( config && config.routing && typeof(config.routing) == 'object' ) ? config.routing : null;
|
|
23345
|
+
if ( !routing ) {
|
|
23346
|
+
return null;
|
|
23347
|
+
}
|
|
23348
|
+
if ( _compiledFor === routing && _compiled ) {
|
|
23349
|
+
return _compiled;
|
|
23350
|
+
}
|
|
23351
|
+
var bundle = config.bundle;
|
|
23352
|
+
var compiled = [];
|
|
23353
|
+
for (var rule in routing) {
|
|
23354
|
+
var route = routing[rule];
|
|
23355
|
+
if ( !route || typeof(route) != 'object' ) continue;
|
|
23356
|
+
if ( typeof(route.param) == 'undefined' ) continue;
|
|
23357
|
+
if ( route.bundle != bundle ) continue;
|
|
23358
|
+
var method = String(route.method || '');
|
|
23359
|
+
var hasComma = /\,/.test(method);
|
|
23360
|
+
var singleClean = method.replace(/\s+/g, '');
|
|
23361
|
+
if ( !hasComma && !/^(get|delete)$/i.test(singleClean) ) continue;
|
|
23362
|
+
var isGet = hasComma
|
|
23363
|
+
? /(^|,)\s*get\s*(,|$)/i.test(method)
|
|
23364
|
+
: /^get$/i.test(singleClean);
|
|
23365
|
+
var urls = String(route.url).split(/\,/g);
|
|
23366
|
+
var variants = [];
|
|
23367
|
+
for (var u = 0, uLen = urls.length; u < uLen; ++u) {
|
|
23368
|
+
variants.push( compileVariant(urls[u], route) );
|
|
23369
|
+
}
|
|
23370
|
+
compiled.push({
|
|
23371
|
+
'rule' : rule,
|
|
23372
|
+
'route' : route,
|
|
23373
|
+
'isGet' : isGet,
|
|
23374
|
+
'variants' : variants,
|
|
23375
|
+
'rawUrl' : String(route.url)
|
|
23376
|
+
});
|
|
23377
|
+
}
|
|
23378
|
+
_compiled = compiled;
|
|
23379
|
+
_compiledFor = routing;
|
|
23380
|
+
return compiled;
|
|
23381
|
+
};
|
|
23382
|
+
|
|
23383
|
+
/**
|
|
23384
|
+
* matchUrl
|
|
23385
|
+
*
|
|
23386
|
+
* Client-side URL→route matcher over the served routing table. First
|
|
23387
|
+
* match in table order wins — the server's own scan order, so both
|
|
23388
|
+
* sides resolve the same rule for the same pathname. The pathname is
|
|
23389
|
+
* matched decoded (safeDecode) with a raw exact-equality short-circuit
|
|
23390
|
+
* per route, both mirroring the server.
|
|
23391
|
+
*
|
|
23392
|
+
* A null return, or a match without `negotiate: true`, means the click
|
|
23393
|
+
* is left to the browser — the matcher is an interception FILTER, and
|
|
23394
|
+
* every uncertainty degrades to a normal navigation.
|
|
23395
|
+
*
|
|
23396
|
+
* @param {string} pathname - location pathname (no query string)
|
|
23397
|
+
* @returns {object|null} { rule, route, isGet } or null
|
|
23398
|
+
* */
|
|
23399
|
+
var matchUrl = function(pathname) {
|
|
23400
|
+
var compiled = getCompiled();
|
|
23401
|
+
if ( !compiled ) {
|
|
23402
|
+
return null;
|
|
23403
|
+
}
|
|
23404
|
+
var decoded = safeDecode(pathname);
|
|
23405
|
+
var segs = decoded.split(/\//);
|
|
23406
|
+
for (var i = 0, len = compiled.length; i < len; ++i) {
|
|
23407
|
+
var c = compiled[i];
|
|
23408
|
+
if ( pathname === c.rawUrl || decoded === c.rawUrl ) {
|
|
23409
|
+
return { 'rule': c.rule, 'route': c.route, 'isGet': c.isGet };
|
|
23410
|
+
}
|
|
23411
|
+
for (var v = 0, vLen = c.variants.length; v < vLen; ++v) {
|
|
23412
|
+
var m = c.variants[v];
|
|
23413
|
+
if ( !m || m.length !== segs.length ) continue;
|
|
23414
|
+
var ok = true;
|
|
23415
|
+
for (var s = 0, sLen = m.length; s < sLen; ++s) {
|
|
23416
|
+
if ( typeof(m[s].lit) != 'undefined' ) {
|
|
23417
|
+
if ( m[s].lit !== segs[s] ) { ok = false; break; }
|
|
23418
|
+
continue;
|
|
23419
|
+
}
|
|
23420
|
+
if ( !segs[s] ) { ok = false; break; }
|
|
23421
|
+
if ( m[s].re && !m[s].re.test(segs[s]) ) { ok = false; break; }
|
|
23422
|
+
}
|
|
23423
|
+
if (ok) {
|
|
23424
|
+
return { 'rule': c.rule, 'route': c.route, 'isGet': c.isGet };
|
|
23425
|
+
}
|
|
23426
|
+
}
|
|
23427
|
+
}
|
|
23428
|
+
return null;
|
|
23429
|
+
};
|
|
23430
|
+
|
|
23431
|
+
/**
|
|
23432
|
+
* Snapshots the src of every script present in the document at
|
|
23433
|
+
* activation — the popin `parentScripts` model. Scripts already loaded
|
|
23434
|
+
* with the page are never re-injected from a fragment.
|
|
23435
|
+
*
|
|
23436
|
+
* @inner
|
|
23437
|
+
* @private
|
|
23438
|
+
*/
|
|
23439
|
+
var snapshotParentScripts = function() {
|
|
23440
|
+
var scripts = document.getElementsByTagName('script');
|
|
23441
|
+
for (var i = 0, len = scripts.length; i < len; ++i) {
|
|
23442
|
+
if ( scripts[i].src ) {
|
|
23443
|
+
_parentScripts.push(scripts[i].src);
|
|
23444
|
+
}
|
|
23445
|
+
}
|
|
23446
|
+
};
|
|
23447
|
+
|
|
23448
|
+
/**
|
|
23449
|
+
* Re-injects the fragment's src-bearing scripts the document does not
|
|
23450
|
+
* already have (mirrors popinOpen's external-resource loading). Inline
|
|
23451
|
+
* scripts are NOT executed — innerHTML semantics, the same contract
|
|
23452
|
+
* popin content has always had. Injected scripts persist across later
|
|
23453
|
+
* swaps (a page never "closes"); the registry keeps them single-shot.
|
|
23454
|
+
*
|
|
23455
|
+
* @inner
|
|
23456
|
+
* @private
|
|
23457
|
+
* @param {object} $target - the swapped region
|
|
23458
|
+
*/
|
|
23459
|
+
var injectFragmentScripts = function($target) {
|
|
23460
|
+
var scripts = $target.getElementsByTagName('script');
|
|
23461
|
+
for (var i = 0, len = scripts.length; i < len; ++i) {
|
|
23462
|
+
var src = scripts[i].src; // resolved absolute URL
|
|
23463
|
+
if ( !src ) continue;
|
|
23464
|
+
if ( _parentScripts.indexOf(src) > -1 || _injectedScripts.indexOf(src) > -1 ) continue;
|
|
23465
|
+
var s = document.createElement('script');
|
|
23466
|
+
s.src = src;
|
|
23467
|
+
document.head.appendChild(s);
|
|
23468
|
+
_injectedScripts.push(src);
|
|
23469
|
+
}
|
|
23470
|
+
};
|
|
23471
|
+
|
|
23472
|
+
/**
|
|
23473
|
+
* Rebinds id-bearing forms of the swapped region through the live
|
|
23474
|
+
* validator (`gina.validator.validateFormById` — the popinBind model).
|
|
23475
|
+
* Id-less forms are skipped: validation rules are keyed by form id, so
|
|
23476
|
+
* no rule can target them. A missing/ruleless validator is a no-op.
|
|
23477
|
+
*
|
|
23478
|
+
* @inner
|
|
23479
|
+
* @private
|
|
23480
|
+
* @param {object} $target - the swapped region
|
|
23481
|
+
*/
|
|
23482
|
+
var rebindValidator = function($target) {
|
|
23483
|
+
try {
|
|
23484
|
+
if ( !gina.hasValidator || !gina.validator || typeof(gina.validator.validateFormById) != 'function' ) {
|
|
23485
|
+
return;
|
|
23486
|
+
}
|
|
23487
|
+
var $forms = $target.getElementsByTagName('form');
|
|
23488
|
+
for (var i = 0, len = $forms.length; i < len; ++i) {
|
|
23489
|
+
var _id = $forms[i].getAttribute('id');
|
|
23490
|
+
if ( !_id ) continue;
|
|
23491
|
+
try {
|
|
23492
|
+
gina.validator.validateFormById(_id);
|
|
23493
|
+
} catch (bindErr) {
|
|
23494
|
+
console.warn('[gina][nav] validator rebind skipped for `'+ _id +'`: '+ (bindErr.message || bindErr));
|
|
23495
|
+
}
|
|
23496
|
+
}
|
|
23497
|
+
} catch (validatorErr) {}
|
|
23498
|
+
};
|
|
23499
|
+
|
|
23500
|
+
/**
|
|
23501
|
+
* Closes the active popin when one is open: a full-page navigation
|
|
23502
|
+
* would have unloaded it, and after a fragment swap it would sit over
|
|
23503
|
+
* content it no longer belongs to.
|
|
23504
|
+
*
|
|
23505
|
+
* @inner
|
|
23506
|
+
* @private
|
|
23507
|
+
*/
|
|
23508
|
+
var closeActivePopin = function() {
|
|
23509
|
+
try {
|
|
23510
|
+
if ( gina.hasPopinHandler && gina.popin && typeof(gina.popin.getActivePopin) == 'function' ) {
|
|
23511
|
+
var $active = gina.popin.getActivePopin();
|
|
23512
|
+
if ( $active && $active.isOpen && typeof(gina.popin.close) == 'function' ) {
|
|
23513
|
+
gina.popin.close($active.name);
|
|
23514
|
+
}
|
|
23515
|
+
}
|
|
23516
|
+
} catch (popinCloseErr) {}
|
|
23517
|
+
};
|
|
23518
|
+
|
|
23519
|
+
/**
|
|
23520
|
+
* Stores the current scroll position onto the CURRENT history entry
|
|
23521
|
+
* (replaceState) so a later Back restores it. The entry keeps its
|
|
23522
|
+
* `ginaNav` stamp.
|
|
23523
|
+
*
|
|
23524
|
+
* @inner
|
|
23525
|
+
* @private
|
|
23526
|
+
*/
|
|
23527
|
+
var saveScrollOnCurrentEntry = function() {
|
|
23528
|
+
try {
|
|
23529
|
+
var st = window.history.state || {};
|
|
23530
|
+
st.ginaNav = true;
|
|
23531
|
+
st.scroll = [ window.pageXOffset || 0, window.pageYOffset || 0 ];
|
|
23532
|
+
window.history.replaceState(st, '', window.location.href);
|
|
23533
|
+
} catch (histErr) {}
|
|
23534
|
+
};
|
|
23535
|
+
|
|
23536
|
+
/**
|
|
23537
|
+
* Applies a fetched fragment: swaps the region content, re-injects
|
|
23538
|
+
* missing src scripts, applies the optional `[data-gina-nav-title]`
|
|
23539
|
+
* document title, pushes/updates history, restores scroll and focus,
|
|
23540
|
+
* closes any open popin, rebinds validator forms and fires `success`.
|
|
23541
|
+
*
|
|
23542
|
+
* @inner
|
|
23543
|
+
* @private
|
|
23544
|
+
* @param {string} html - the layoutless fragment body
|
|
23545
|
+
* @param {string} url - the navigated URL (pathname + search [+ hash])
|
|
23546
|
+
* @param {boolean} isPopState - popstate re-render (no history push)
|
|
23547
|
+
* @param {object} [navOptions] - { scroll: [x, y] } on popstate
|
|
23548
|
+
*/
|
|
23549
|
+
var applyFragment = function(html, url, isPopState, navOptions) {
|
|
23550
|
+
var $target = instance.target;
|
|
23551
|
+
$target.innerHTML = ( typeof(html) == 'string' ) ? html.trim() : '';
|
|
23552
|
+
|
|
23553
|
+
injectFragmentScripts($target);
|
|
23554
|
+
|
|
23555
|
+
// Optional per-page document title: the first element of the
|
|
23556
|
+
// fragment carrying `data-gina-nav-title` (the fragment is
|
|
23557
|
+
// layoutless, so it cannot carry a <title> of its own).
|
|
23558
|
+
var $titled = ( typeof($target.querySelector) == 'function' ) ? $target.querySelector('[data-gina-nav-title]') : null;
|
|
23559
|
+
if ( $titled ) {
|
|
23560
|
+
var _title = $titled.getAttribute('data-gina-nav-title');
|
|
23561
|
+
if (_title) {
|
|
23562
|
+
document.title = _title;
|
|
23563
|
+
}
|
|
23564
|
+
}
|
|
23565
|
+
|
|
23566
|
+
if ( !isPopState ) {
|
|
23567
|
+
// Store the leaving entry's scroll, then push the new one.
|
|
23568
|
+
saveScrollOnCurrentEntry();
|
|
23569
|
+
try {
|
|
23570
|
+
window.history.pushState({ 'ginaNav': true }, '', url);
|
|
23571
|
+
} catch (pushErr) {}
|
|
23572
|
+
}
|
|
23573
|
+
_currentUrl = window.location.pathname + window.location.search;
|
|
23574
|
+
|
|
23575
|
+
// Focus first (preventScroll where supported), then the explicit
|
|
23576
|
+
// scroll decision wins: restored position on popstate, `#hash`
|
|
23577
|
+
// target or top on a forward navigation.
|
|
23578
|
+
try {
|
|
23579
|
+
if ( !$target.getAttribute('tabindex') ) {
|
|
23580
|
+
$target.setAttribute('tabindex', '-1');
|
|
23581
|
+
}
|
|
23582
|
+
$target.focus({ 'preventScroll': true });
|
|
23583
|
+
} catch (focusErr) {
|
|
23584
|
+
try { $target.focus(); } catch (focusRetryErr) {}
|
|
23585
|
+
}
|
|
23586
|
+
var _scroll = ( isPopState && navOptions && navOptions.scroll ) ? navOptions.scroll : null;
|
|
23587
|
+
if ( _scroll ) {
|
|
23588
|
+
window.scrollTo(_scroll[0] || 0, _scroll[1] || 0);
|
|
23589
|
+
} else {
|
|
23590
|
+
var _hash = ( url.indexOf('#') > -1 ) ? url.substring(url.indexOf('#') + 1) : null;
|
|
23591
|
+
var $anchor = ( _hash ) ? document.getElementById(_hash) : null;
|
|
23592
|
+
if ( $anchor && typeof($anchor.scrollIntoView) == 'function' ) {
|
|
23593
|
+
$anchor.scrollIntoView();
|
|
23594
|
+
} else {
|
|
23595
|
+
window.scrollTo(0, 0);
|
|
23596
|
+
}
|
|
23597
|
+
}
|
|
23598
|
+
|
|
23599
|
+
closeActivePopin();
|
|
23600
|
+
rebindValidator($target);
|
|
23601
|
+
|
|
23602
|
+
instance.eventData.success = { 'url': url, 'target': $target, 'isPopState': isPopState };
|
|
23603
|
+
triggerEvent(gina, instance.target, 'success.' + instance.id, instance.eventData.success);
|
|
23604
|
+
};
|
|
23605
|
+
|
|
23606
|
+
/**
|
|
23607
|
+
* Falls back to a full-page navigation, firing `error` first so
|
|
23608
|
+
* consumers can observe/log. On a popstate the address bar already
|
|
23609
|
+
* shows the target, so the fallback is a reload.
|
|
23610
|
+
*
|
|
23611
|
+
* @inner
|
|
23612
|
+
* @private
|
|
23613
|
+
* @param {string} url
|
|
23614
|
+
* @param {boolean} isPopState
|
|
23615
|
+
* @param {object} errorData - { status, error }
|
|
23616
|
+
*/
|
|
23617
|
+
var fallback = function(url, isPopState, errorData) {
|
|
23618
|
+
instance.eventData.error = errorData || {};
|
|
23619
|
+
triggerEvent(gina, instance.target, 'error.' + instance.id, instance.eventData.error);
|
|
23620
|
+
if ( isPopState ) {
|
|
23621
|
+
window.location.reload();
|
|
23622
|
+
} else {
|
|
23623
|
+
window.location.href = url;
|
|
23624
|
+
}
|
|
23625
|
+
};
|
|
23626
|
+
|
|
23627
|
+
/**
|
|
23628
|
+
* Handles a completed fragment XHR. Discrimination is protocol-level:
|
|
23629
|
+
* a genuine negotiated answer always advertises `Vary: X-Gina-Navigate`
|
|
23630
|
+
* (the #SPA1 controller contract) — a 2xx WITHOUT it means the server
|
|
23631
|
+
* dispatched a route the client matched differently, and the honest
|
|
23632
|
+
* recovery is a normal page load. A JSON `{location}` body is the
|
|
23633
|
+
* established XHR redirect protocol and is hard-followed.
|
|
23634
|
+
*
|
|
23635
|
+
* @inner
|
|
23636
|
+
* @private
|
|
23637
|
+
* @param {object} xhr
|
|
23638
|
+
* @param {string} url
|
|
23639
|
+
* @param {boolean} isPopState
|
|
23640
|
+
* @param {object} [navOptions]
|
|
23641
|
+
*/
|
|
23642
|
+
var onNavResponse = function(xhr, url, isPopState, navOptions) {
|
|
23643
|
+
var status = xhr.status;
|
|
23644
|
+
if ( /^2/.test(String(status)) ) {
|
|
23645
|
+
var contentType = xhr.getResponseHeader('Content-Type') || '';
|
|
23646
|
+
if ( /application\/json/.test(contentType) ) {
|
|
23647
|
+
var result = null;
|
|
23648
|
+
try {
|
|
23649
|
+
result = JSON.parse(xhr.responseText);
|
|
23650
|
+
} catch (parseErr) {}
|
|
23651
|
+
if ( result && typeof(result.location) != 'undefined' && result.location ) {
|
|
23652
|
+
window.location.href = result.location;
|
|
23653
|
+
return;
|
|
23654
|
+
}
|
|
23655
|
+
return fallback(url, isPopState, { 'status': status, 'error': 'unexpected JSON answer to a fragment request' });
|
|
23656
|
+
}
|
|
23657
|
+
var vary = xhr.getResponseHeader('Vary') || '';
|
|
23658
|
+
if ( !/x-gina-navigate/i.test(vary) ) {
|
|
23659
|
+
return fallback(url, isPopState, { 'status': status, 'error': 'response is not negotiated (no `Vary: X-Gina-Navigate`)' });
|
|
23660
|
+
}
|
|
23661
|
+
return applyFragment(xhr.responseText, url, isPopState, navOptions);
|
|
23662
|
+
}
|
|
23663
|
+
fallback(url, isPopState, { 'status': status || 0, 'error': xhr.statusText || 'network error or timeout' });
|
|
23664
|
+
};
|
|
23665
|
+
|
|
23666
|
+
/**
|
|
23667
|
+
* navigate
|
|
23668
|
+
*
|
|
23669
|
+
* Fetches the URL's negotiated fragment and swaps it into the
|
|
23670
|
+
* `data-gina-nav` region. Every uncertainty (non-2xx, timeout, network
|
|
23671
|
+
* error, un-negotiated answer, JSON redirect) degrades to a full-page
|
|
23672
|
+
* navigation of the same URL, so a programmatic call on a
|
|
23673
|
+
* non-negotiable route behaves like `window.location.href = url`.
|
|
23674
|
+
*
|
|
23675
|
+
* A FRESH XMLHttpRequest is opened per navigation and any in-flight
|
|
23676
|
+
* one is aborted; its handlers observe a stale sequence and drop out,
|
|
23677
|
+
* so two rapid navigations can never interleave content.
|
|
23678
|
+
*
|
|
23679
|
+
* @param {string} url - same-origin URL (pathname + search [+ hash])
|
|
23680
|
+
* @param {object} [navOptions]
|
|
23681
|
+
* @param {boolean} [navOptions.isPopState=false] - popstate re-render
|
|
23682
|
+
* @param {array} [navOptions.scroll] - [x, y] to restore on popstate
|
|
23683
|
+
* */
|
|
23684
|
+
var navigate = function(url, navOptions) {
|
|
23685
|
+
if ( !url || typeof(url) != 'string' ) {
|
|
23686
|
+
return;
|
|
23687
|
+
}
|
|
23688
|
+
if ( !instance.isReady || instance.target === document ) {
|
|
23689
|
+
// Not activated (no marker) — behave like a plain navigation.
|
|
23690
|
+
window.location.href = url;
|
|
23691
|
+
return;
|
|
23692
|
+
}
|
|
23693
|
+
var isPopState = ( navOptions && navOptions.isPopState ) ? true : false;
|
|
23694
|
+
var seq = ++_navSeq;
|
|
23695
|
+
if ( _xhr && _xhr.readyState !== 4 ) {
|
|
23696
|
+
try {
|
|
23697
|
+
_xhr.abort();
|
|
23698
|
+
} catch (abortErr) {}
|
|
23699
|
+
}
|
|
23700
|
+
|
|
23701
|
+
instance.eventData.navigate = { 'url': url, 'isPopState': isPopState };
|
|
23702
|
+
triggerEvent(gina, instance.target, 'navigate.' + instance.id, instance.eventData.navigate);
|
|
23703
|
+
|
|
23704
|
+
// Fresh XHR per navigation — prevents concurrent navigations from
|
|
23705
|
+
// sharing state (#B175).
|
|
23706
|
+
var xhr = new XMLHttpRequest();
|
|
23707
|
+
_xhr = xhr;
|
|
23708
|
+
xhr.open('GET', url);
|
|
23709
|
+
// Both headers, deliberately:
|
|
23710
|
+
// - `X-Gina-Navigate` is the #SPA1 negotiation signal (the
|
|
23711
|
+
// controller resolves the layoutless shape and advertises Vary
|
|
23712
|
+
// on negotiable routes);
|
|
23713
|
+
// - `X-Requested-With` keeps the request on the established XHR
|
|
23714
|
+
// paths — without it the render path re-wraps the layoutless
|
|
23715
|
+
// body into a full `<html>` shell (render-swig iframe case),
|
|
23716
|
+
// and redirects/errors leave the proven JSON protocol.
|
|
23717
|
+
xhr.setRequestHeader('X-Gina-Navigate', 'fragment');
|
|
23718
|
+
xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
|
|
23719
|
+
xhr.timeout = self.options.timeout;
|
|
23720
|
+
xhr.onreadystatechange = function() {
|
|
23721
|
+
if ( xhr.readyState !== 4 ) {
|
|
23722
|
+
return;
|
|
23723
|
+
}
|
|
23724
|
+
if ( seq !== _navSeq ) {
|
|
23725
|
+
return; // superseded — a newer navigation owns the page
|
|
23726
|
+
}
|
|
23727
|
+
// status 0 with a CURRENT sequence is a network failure or the
|
|
23728
|
+
// timeout's internal abort (a supersede-abort is always stale
|
|
23729
|
+
// by construction: the sequence increments before the abort).
|
|
23730
|
+
onNavResponse(xhr, url, isPopState, navOptions);
|
|
23731
|
+
};
|
|
23732
|
+
xhr.send();
|
|
23733
|
+
};
|
|
23734
|
+
|
|
23735
|
+
/**
|
|
23736
|
+
* The delegated document-level click handler — the popin
|
|
23737
|
+
* bindDelegatedOpen model, so links inside swapped fragments are
|
|
23738
|
+
* covered with no rebinding. Every skip rule below defers to an
|
|
23739
|
+
* existing owner or to the browser; interception happens only for a
|
|
23740
|
+
* same-origin left-click resolving to a first-match route that
|
|
23741
|
+
* declares `negotiate: true` and accepts GET.
|
|
23742
|
+
*
|
|
23743
|
+
* @inner
|
|
23744
|
+
* @private
|
|
23745
|
+
* @param {object} event - the click event
|
|
23746
|
+
*/
|
|
23747
|
+
var onDocumentClick = function(event) {
|
|
23748
|
+
if ( event.defaultPrevented ) return;
|
|
23749
|
+
if ( typeof(event.button) == 'number' && event.button !== 0 ) return;
|
|
23750
|
+
if ( event.ctrlKey || event.metaKey || event.shiftKey || event.altKey ) return;
|
|
23751
|
+
var $a = ( event.target && typeof(event.target.closest) == 'function' )
|
|
23752
|
+
? event.target.closest('a[href]')
|
|
23753
|
+
: null;
|
|
23754
|
+
if ( !$a ) return;
|
|
23755
|
+
// Ownership deference — the link plugin and the dialog/popin
|
|
23756
|
+
// triggers keep their own handlers.
|
|
23757
|
+
if ( $a.getAttribute('data-gina-link') != null || $a.getAttribute('data-gina-link-url') != null ) return;
|
|
23758
|
+
if ( $a.getAttribute('data-gina-dialog') != null || $a.getAttribute('data-gina-dialog-src') != null ) return;
|
|
23759
|
+
if ( $a.getAttribute('data-gina-popin-name') != null || $a.getAttribute('data-gina-popin-url') != null ) return;
|
|
23760
|
+
// Per-link opt-out.
|
|
23761
|
+
if ( /^false$/i.test($a.getAttribute('data-gina-nav')) ) return;
|
|
23762
|
+
var targetAttr = $a.getAttribute('target');
|
|
23763
|
+
if ( targetAttr && !/^_self$/i.test(targetAttr) ) return;
|
|
23764
|
+
if ( $a.getAttribute('download') != null ) return;
|
|
23765
|
+
var href = $a.getAttribute('href');
|
|
23766
|
+
if ( !href || /^#/.test(href) ) return;
|
|
23767
|
+
// Same-origin only — the anchor element is the URL parser.
|
|
23768
|
+
if ( $a.protocol !== window.location.protocol || $a.host !== window.location.host ) return;
|
|
23769
|
+
// In-page hash move on the same document — the browser handles it.
|
|
23770
|
+
if ( $a.pathname === window.location.pathname && $a.search === window.location.search && $a.hash ) return;
|
|
23771
|
+
|
|
23772
|
+
var matched = matchUrl($a.pathname);
|
|
23773
|
+
if ( !matched || matched.route.negotiate !== true || !matched.isGet ) return;
|
|
23774
|
+
|
|
23775
|
+
cancelEvent(event);
|
|
23776
|
+
navigate($a.pathname + $a.search + $a.hash);
|
|
23777
|
+
};
|
|
23778
|
+
|
|
23779
|
+
/**
|
|
23780
|
+
* Installs the delegated click listener and the popstate handler —
|
|
23781
|
+
* once per instance lifecycle.
|
|
23782
|
+
*
|
|
23783
|
+
* @inner
|
|
23784
|
+
* @private
|
|
23785
|
+
*/
|
|
23786
|
+
var installListeners = function() {
|
|
23787
|
+
if ( _listenersInstalled ) {
|
|
23788
|
+
return;
|
|
23789
|
+
}
|
|
23790
|
+
_listenersInstalled = true;
|
|
23791
|
+
|
|
23792
|
+
addListener(gina, document, 'click', function(event) {
|
|
23793
|
+
try {
|
|
23794
|
+
onDocumentClick(event);
|
|
23795
|
+
} catch (navClickErr) {
|
|
23796
|
+
// An interception error must never eat the click — the
|
|
23797
|
+
// browser keeps handling it.
|
|
23798
|
+
console.warn('[gina][nav] click interception skipped: '+ (navClickErr.message || navClickErr));
|
|
23799
|
+
}
|
|
23800
|
+
});
|
|
23801
|
+
|
|
23802
|
+
// Raw addEventListener: utils/events' addListener reads
|
|
23803
|
+
// `element.getAttribute` at registration and `window` has neither
|
|
23804
|
+
// `id` nor `getAttribute`.
|
|
23805
|
+
window.addEventListener('popstate', function(event) {
|
|
23806
|
+
try {
|
|
23807
|
+
var _url = window.location.pathname + window.location.search;
|
|
23808
|
+
if ( _url === _currentUrl ) {
|
|
23809
|
+
return; // hash-only move on the same document
|
|
23810
|
+
}
|
|
23811
|
+
var st = event.state;
|
|
23812
|
+
if ( st && st.ginaNav ) {
|
|
23813
|
+
navigate(_url + window.location.hash, { 'isPopState': true, 'scroll': st.scroll || null });
|
|
23814
|
+
return;
|
|
23815
|
+
}
|
|
23816
|
+
// A history entry nav did not stamp (external history
|
|
23817
|
+
// manipulation) — the only honest recovery is a full load
|
|
23818
|
+
// of what the address bar shows.
|
|
23819
|
+
window.location.reload();
|
|
23820
|
+
} catch (popErr) {
|
|
23821
|
+
window.location.reload();
|
|
23822
|
+
}
|
|
23823
|
+
});
|
|
23824
|
+
};
|
|
23825
|
+
|
|
23826
|
+
var init = function(options) {
|
|
23827
|
+
|
|
23828
|
+
setupInstanceProto();
|
|
23829
|
+
instance.on('init', function(event) {
|
|
23830
|
+
|
|
23831
|
+
self.options = merge(options || {}, self.options);
|
|
23832
|
+
|
|
23833
|
+
// Swap-target + page opt-in in one marker. `"false"` is the
|
|
23834
|
+
// per-LINK opt-out spelling and must not opt a page in.
|
|
23835
|
+
var $marker = null;
|
|
23836
|
+
try {
|
|
23837
|
+
$marker = document.querySelector('[data-gina-nav]:not([data-gina-nav="false"])');
|
|
23838
|
+
} catch (qsErr) {}
|
|
23839
|
+
|
|
23840
|
+
if ( !$marker ) {
|
|
23841
|
+
// Explicit construction on a page without the marker: warn
|
|
23842
|
+
// and stay inert — no listeners, no publish, no behaviour
|
|
23843
|
+
// change (the boot shim never constructs in this state).
|
|
23844
|
+
console.warn('[gina][nav] no [data-gina-nav] region found — navigation interception stays off');
|
|
23845
|
+
instance.isReady = true;
|
|
23846
|
+
triggerEvent(gina, instance.target, 'ready.' + instance.id, instance);
|
|
23847
|
+
return;
|
|
23848
|
+
}
|
|
23849
|
+
|
|
23850
|
+
instance.target = $marker;
|
|
23851
|
+
_currentUrl = window.location.pathname + window.location.search;
|
|
23852
|
+
snapshotParentScripts();
|
|
23853
|
+
try {
|
|
23854
|
+
if ( window.history && 'scrollRestoration' in window.history ) {
|
|
23855
|
+
window.history.scrollRestoration = 'manual';
|
|
23856
|
+
}
|
|
23857
|
+
// Stamp the entry page so a Back onto it is recognised as
|
|
23858
|
+
// nav-owned and re-rendered as a fragment.
|
|
23859
|
+
var _st = window.history.state || {};
|
|
23860
|
+
_st.ginaNav = true;
|
|
23861
|
+
window.history.replaceState(_st, '', window.location.href);
|
|
23862
|
+
} catch (histErr) {}
|
|
23863
|
+
|
|
23864
|
+
installListeners();
|
|
23865
|
+
|
|
23866
|
+
instance.isReady = true;
|
|
23867
|
+
gina.hasNavHandler = true;
|
|
23868
|
+
// #B90 — publish ONCE: `gina.nav` IS the first activated
|
|
23869
|
+
// instance (a LIVE object); later constructions have nothing
|
|
23870
|
+
// to publish, and re-merging would freeze accessors/state.
|
|
23871
|
+
if ( typeof(gina.nav) == 'undefined' || !gina.nav ) {
|
|
23872
|
+
gina.nav = instance;
|
|
23873
|
+
}
|
|
23874
|
+
triggerEvent(gina, instance.target, 'ready.' + instance.id, instance);
|
|
23875
|
+
});
|
|
23876
|
+
|
|
23877
|
+
instance.initialized = true;
|
|
23878
|
+
|
|
23879
|
+
return instance;
|
|
23880
|
+
};
|
|
23881
|
+
|
|
23882
|
+
var setupInstanceProto = function() {
|
|
23883
|
+
instance.navigate = navigate;
|
|
23884
|
+
instance.matchUrl = matchUrl;
|
|
23885
|
+
};
|
|
23886
|
+
|
|
23887
|
+
return init(options);
|
|
23888
|
+
}
|
|
23889
|
+
|
|
23890
|
+
return Nav;
|
|
23891
|
+
});
|
|
23892
|
+
|
|
22548
23893
|
/**
|
|
22549
23894
|
* Object.assign
|
|
22550
23895
|
* Ref.: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
|
|
@@ -24581,6 +25926,7 @@ require([
|
|
|
24581
25926
|
"gina/validator",
|
|
24582
25927
|
"gina/popin",
|
|
24583
25928
|
"gina/storage",
|
|
25929
|
+
"gina/nav",
|
|
24584
25930
|
|
|
24585
25931
|
// lib
|
|
24586
25932
|
"utils/dom",
|
|
@@ -24672,6 +26018,49 @@ require([
|
|
|
24672
26018
|
}
|
|
24673
26019
|
};
|
|
24674
26020
|
bootValidator();
|
|
26021
|
+
|
|
26022
|
+
// Boot the navigation handler (#SPA1 — Tier 1) so the declarative
|
|
26023
|
+
// `data-gina-nav` API is active WITHOUT bundle code calling
|
|
26024
|
+
// `new gina.nav()` — the sibling of the popin/validator boots above,
|
|
26025
|
+
// with one deliberate difference: navigation is OPT-IN PER PROJECT
|
|
26026
|
+
// (SPA design decision 3 — upgrading gina must not change navigation
|
|
26027
|
+
// behaviour on existing pages). The shim therefore constructs ONLY when
|
|
26028
|
+
// the page carries a `data-gina-nav` swap-region marker; the `"false"`
|
|
26029
|
+
// value is the per-LINK opt-out spelling and does not opt a page in.
|
|
26030
|
+
// Pages without the marker stay byte-identical: no listener, no
|
|
26031
|
+
// `gina.nav` publish, no history/scroll changes. Gated on
|
|
26032
|
+
// `isFrameworkLoaded` like its siblings — by then the DOM is ready
|
|
26033
|
+
// (onGinaLoaded runs from the DOMContentLoaded-driven scheduler), so the
|
|
26034
|
+
// marker query observes the rendered page.
|
|
26035
|
+
var _navBootTries = 0;
|
|
26036
|
+
var bootNav = function () {
|
|
26037
|
+
try {
|
|
26038
|
+
if ( !window['gina'] || !window['gina']['isFrameworkLoaded'] ) {
|
|
26039
|
+
if ( _navBootTries++ < 100 ) {
|
|
26040
|
+
(window['setTimeout'] || function (fn) { fn(); })(bootNav, 50);
|
|
26041
|
+
}
|
|
26042
|
+
return;
|
|
26043
|
+
}
|
|
26044
|
+
if ( window['gina']['hasNavHandler'] ) {
|
|
26045
|
+
return;
|
|
26046
|
+
}
|
|
26047
|
+
if (
|
|
26048
|
+
typeof(document.querySelector) != 'function'
|
|
26049
|
+
|| !document.querySelector('[data-gina-nav]:not([data-gina-nav="false"])')
|
|
26050
|
+
) {
|
|
26051
|
+
return;
|
|
26052
|
+
}
|
|
26053
|
+
var Nav = require('gina/nav');
|
|
26054
|
+
if ( typeof(Nav) == 'function' ) {
|
|
26055
|
+
new Nav({}).on('ready', function () {});
|
|
26056
|
+
}
|
|
26057
|
+
} catch (navBootErr) {
|
|
26058
|
+
if ( typeof(console) != 'undefined' && console.error ) {
|
|
26059
|
+
console.error('[gina] nav boot failed', navBootErr.stack || navBootErr);
|
|
26060
|
+
}
|
|
26061
|
+
}
|
|
26062
|
+
};
|
|
26063
|
+
bootNav();
|
|
24675
26064
|
});
|
|
24676
26065
|
|
|
24677
26066
|
function getDependencies(gina, cb) {
|
|
@@ -24689,6 +26078,16 @@ function getDependencies(gina, cb) {
|
|
|
24689
26078
|
|
|
24690
26079
|
try {
|
|
24691
26080
|
response = await fetch(filenameOrUrl);
|
|
26081
|
+
// #B213 — `fetch` resolves on HTTP error statuses (it only rejects on
|
|
26082
|
+
// network failure), and the framework's own 404 page is valid JSON —
|
|
26083
|
+
// so without this guard a 404/5xx body (an engine missing the asset,
|
|
26084
|
+
// a restart window) was silently installed AS the routing table and
|
|
26085
|
+
// every client-side getRoute/toUrl failed from there. Throwing here
|
|
26086
|
+
// routes the failure into the existing catch, which dispatches the
|
|
26087
|
+
// deps.loaded error path instead of poisoning gina.config.
|
|
26088
|
+
if ( !response.ok ) {
|
|
26089
|
+
throw new Error('[ROUTING] HTTP '+ response.status +' fetching '+ filenameOrUrl);
|
|
26090
|
+
}
|
|
24692
26091
|
result = await response.text();
|
|
24693
26092
|
if ( typeof(gina) == 'undefined' ) {
|
|
24694
26093
|
gina = {}
|