diff --git a/.env b/.env new file mode 100644 index 0000000..7bfe671 --- /dev/null +++ b/.env @@ -0,0 +1,47 @@ +# In all environments, the following files are loaded if they exist, +# the latter taking precedence over the former: +# +# * .env contains default values for the environment variables needed by the app +# * .env.local uncommitted file with local overrides +# * .env.$APP_ENV committed environment-specific defaults +# * .env.$APP_ENV.local uncommitted environment-specific overrides +# +# Real environment variables win over .env files. +# +# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES. +# https://symfony.com/doc/current/configuration/secrets.html +# +# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2). +# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration + +###> symfony/framework-bundle ### +APP_ENV=dev +APP_SECRET=abcd13223131_CHANGE_THIS_BEARER_TOKEN +###< symfony/framework-bundle ### + +###> doctrine/doctrine-bundle ### +# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url +# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml +# +# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data_%kernel.environment%.db" +# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=8.0.32&charset=utf8mb4" +# DATABASE_URL="mysql://app:!ChangeMe!@127.0.0.1:3306/app?serverVersion=10.11.2-MariaDB&charset=utf8mb4" +DATABASE_URL="postgresql://app:!ChangeMe!@127.0.0.1:5432/app?serverVersion=16&charset=utf8" +###< doctrine/doctrine-bundle ### + +###> symfony/messenger ### +# Choose one of the transports below +# MESSENGER_TRANSPORT_DSN=amqp://guest:guest@localhost:5672/%2f/messages +# MESSENGER_TRANSPORT_DSN=redis://localhost:6379/messages +MESSENGER_TRANSPORT_DSN=doctrine://default?auto_setup=0 +###< symfony/messenger ### + +###> symfony/mailer ### +MAILER_DSN=null://null +###< symfony/mailer ### +#DEBUG=0 + +APP_OSM_BEARER=CHANGE_IT +MAPBOX_TOKEN= +MAPTILER_TOKEN= +USE_PLACES_WITHOUT_EMAIL_TO_REFERENCE=false diff --git a/.env.dev b/.env.dev new file mode 100644 index 0000000..e69de29 diff --git a/.env.test b/.env.test new file mode 100644 index 0000000..9e7162f --- /dev/null +++ b/.env.test @@ -0,0 +1,6 @@ +# define your env variables for the test env here +KERNEL_CLASS='App\Kernel' +APP_SECRET='$ecretf0rt3st' +SYMFONY_DEPRECATIONS_HELPER=999999 +PANTHER_APP_ENV=panther +PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a8bb69 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ + +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/prod/prod.decrypt.private.php +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### + +###> phpunit/phpunit ### +/phpunit.xml +.phpunit.result.cache +###< phpunit/phpunit ### + +###> symfony/phpunit-bridge ### +.phpunit.result.cache +/phpunit.xml +###< symfony/phpunit-bridge ### + +###> symfony/webpack-encore-bundle ### +/node_modules/ +/public/build/ +npm-debug.log +yarn-error.log +###< symfony/webpack-encore-bundle ### +venv + +wiki_compare/.env +wiki_compare/*.png +wiki_compare/*.json +public/*.json diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 0000000..13566b8 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/commandlinetools/Symfony_01_09_2025_18_12.xml b/.idea/commandlinetools/Symfony_01_09_2025_18_12.xml new file mode 100644 index 0000000..2bfa039 --- /dev/null +++ b/.idea/commandlinetools/Symfony_01_09_2025_18_12.xml @@ -0,0 +1,5596 @@ + + + + + _complete +
Options:
--shell(-s)The shell type ("bash", "fish", "zsh")
--input(-i)An array of input tokens (e.g. COMP_WORDS or argv)
--current(-c)The index of the "input" array that the cursor is in (e.g. COMP_CWORD)
--api-version(-a)The API version of the completion script
--symfony(-S)deprecated
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + + +
+ + about + about command displays information about the current Symfony project.

The PHP section displays important configuration that could affect your application. The values might
be different between web and CLI.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + completion + completion command dumps the shell completion script required
to use shell autocompletion (currently, bash, fish, zsh completion are supported).

Static installation
-------------------

Dump the script to a global completion file and restart your shell:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console completion zsh | sudo tee $fpath[1]/_console

Or dump the script to a local file and source it:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console completion zsh > completion.sh

# source the file whenever you use the project
source completion.sh

# or add this line at the end of your "~/.zshrc" file:
source /path/to/completion.sh

Dynamic installation
--------------------

Add this to the end of your shell configuration file (e.g. "~/.zshrc"):

eval "$(/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console completion zsh)"

Options:
--debugTail the completion debug log
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ shell[=null] + + + command]]> + + + + + + + + + + + + +
+ + help + help command displays help for a given command:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console help list

You can also output the help in other formats by using the --format option:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console help --format=xml list

To display the list of available commands, please use the list command.

Options:
--formatThe output format (txt, xml, json, or md)
--rawTo output raw command help
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]> + command_name[=null] + + + +
command]]> + + + + + + + + + + + + + + + list + list command lists all commands:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console list

You can also display the commands for a specific namespace:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console list test

You can also output the information in other formats by using the --format option:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console list --format=xml

It's also possible to get raw list of commands (useful for embedding command runner):

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console list --raw

Options:
--rawTo output raw command list
--formatThe output format (txt, xml, json, or md)
--shortTo skip describing commands' arguments
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ namespace[=null] + + + + + + + + + + + + + + + + +
+ + asset-map:compile + asset-map:compile command compiles and dumps all the assets in
the asset mapper into the final public directory (usually public/assets).

This command is meant to be run during deployment.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + assets:compress + assets:compress command compresses the given file in Brotli, Zstandard and gzip formats.
This is especially useful to serve pre-compressed files through a web server.

The existing file will be kept. The compressed files will be created in the same directory.
The extension of the compression format will be appended to the original file name.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ paths + + + + + + + + + + + + + +
+ + assets:install + assets:install command installs bundle assets into a given
directory (e.g. the public directory).

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console assets:install public

A "bundles" directory will be created inside the target directory and the
"Resources/public" directory of each bundle will be copied into it.

To create a symlink to each bundle instead of copying its assets, use the
--symlink option (will fall back to hard copies when symbolic links aren't possible:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console assets:install public --symlink

To make symlink relative, add the --relative option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console assets:install public --symlink --relative


Options:
--symlinkSymlink the assets instead of copying them
--relativeMake relative symlinks
--no-cleanupDo not remove the assets of the bundles that no longer exist
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ target[=null] + + + + + + + + + + + + + + + + +
+ + cache:clear + cache:clear command clears and warms up the application cache for a given environment
and debug mode:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:clear --env=dev
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:clear --env=prod --no-debug

Options:
--no-warmupDo not warm up the cache
--no-optional-warmersSkip optional cache warmers (faster)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + cache:pool:clear + cache:pool:clear command clears the given cache pools or cache pool clearers.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:pool:clear [...]

Options:
--allClear all cache pools
--excludeA list of cache pools or cache pool clearers to exclude
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ pools[=null] + + + + + + + + + + + + + + + +
+ + cache:pool:delete + cache:pool:delete deletes an item from a given cache pool.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:pool:delete

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ pool key + + + + + + + + + + + + + +
+ + cache:pool:invalidate-tags + cache:pool:invalidate-tags command invalidates tags from taggable pools. By default, all pools
have the passed tags invalidated. Pass --pool=my_pool to invalidate tags on a specific pool.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:pool:invalidate-tags tag1 tag2
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:pool:invalidate-tags tag1 tag2 --pool=cache2 --pool=cache1

Options:
--pool(-p)The pools to invalidate on
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ tags + + + + + + + + + + + + + + +
+ + cache:pool:list + cache:pool:list command lists all available cache pools.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + cache:pool:prune + cache:pool:prune command deletes all expired items from all pruneable pools.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console cache:pool:prune

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + cache:warmup + cache:warmup command warms up the cache.

Before running this command, the cache must be empty.


Options:
--no-optional-warmersSkip optional cache warmers (faster)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + config:dump-reference + config:dump-reference command dumps the default configuration for an
extension/bundle.

Either the extension alias or bundle name can be used:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console config:dump-reference framework
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console config:dump-reference FrameworkBundle

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console config:dump-reference FrameworkBundle --format=json

For dumping a specific option, add its path as second argument (only available for the yaml format):

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console config:dump-reference framework http_client.default_options


Options:
--formatThe output format ("yaml", "xml")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] path[=null] + + + + + + + + + + + + + + +
+ + dbal:run-sql + dbal:run-sql command executes the given SQL query and
outputs the results:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console dbal:run-sql "SELECT * FROM users"

Options:
--connectionThe named database connection
--depthDumping depth of result set (deprecated).
--force-fetchForces fetching the result.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ sql + + + + + + + + + + + + + + + + +
+ + debug:asset-map + debug:asset-map command displays information about the Asset
Mapper for debugging purposes.

To list all configured paths (with local paths and their namespace prefixes) and
all mapped assets (with their logical path and filesystem path), run:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map

You can filter the results by providing a name to search for in the asset name
or path:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map bootstrap.js
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map style/

To filter the assets by extension, use the --ext option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map --ext=css

To show only assets from vendor packages, use the --vendor option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map --vendor

To exclude assets from vendor packages, use the --no-vendor option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map --no-vendor

To see the full paths, use the --full option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:asset-map --full


Options:
--extFilter assets by extension (e.g. "css")
--fullWhether to show the full paths
--vendorOnly show assets from vendor packages
--no-vendorNegate the "--vendor" option
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + + + +
+ + debug:autowiring + debug:autowiring command displays the classes and interfaces that
you can use as type-hints for autowiring:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:autowiring

You can also pass a search term to filter the list:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:autowiring log


Options:
--allShow also services that are not aliased
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ search[=null] + + + + + + + + + + + + + + +
+ + debug:config + debug:config command dumps the current configuration for an
extension/bundle.

Either the extension alias or bundle name can be used:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:config framework
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:config FrameworkBundle

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:config framework --format=json

For dumping a specific option, add its path as second argument:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:config framework serializer.enabled


Options:
--resolve-envDisplay resolved environment variable values instead of placeholders
--formatThe output format ("txt", "yaml", "json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] path[=null] + + + + + + + + + + + + + + + +
+ + debug:container + debug:container command displays all configured public services:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container

To see deprecations generated during container compilation and cache warmup, use the --deprecations option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --deprecations

To get specific information about a service, specify its name:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container validator

To get specific information about a service including all its arguments, use the --show-arguments flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container validator --show-arguments

To see available types that can be used for autowiring, use the --types flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --types

To see environment variables used by the container, use the --env-vars flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --env-vars

Display a specific environment variable by specifying its name with the --env-var option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --env-var=APP_ENV

Use the --tags option to display tagged public services grouped by tag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --tags

Find all services with a specific tag by specifying the tag name with the --tag option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --tag=form.type

Use the --parameters option to display all parameters:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --parameters

Display a specific parameter by specifying its name with the --parameter option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --parameter=kernel.debug

By default, internal services are hidden. You can display them
using the --show-hidden flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --show-hidden

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:container --format=json

Options:
--show-argumentsShow arguments in services
--show-hiddenShow hidden (internal) services
--tagShow all services with a specific tag
--tagsDisplay tagged services for an application
--parameterDisplay a specific parameter for an application
--parametersDisplay parameters for an application
--typesDisplay types (classes/interfaces) available in the container
--env-varDisplay a specific environment variable used in the container
--env-varsDisplay environment variables used in the container
--formatThe output format ("txt", "xml", "json", "md")
--rawTo output raw description
--deprecationsDisplay deprecations generated when compiling and warming up the container
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + debug:dotenv + /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:dotenv command displays all the environment variables configured by dotenv:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:dotenv

To get specific variables, specify its full or partial name:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:dotenv FOO_BAR


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ filter[=null] + + + + + + + + + + + + + +
+ + debug:event-dispatcher + debug:event-dispatcher command displays all configured listeners:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:event-dispatcher

To get specific listeners for an event, specify its name:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:event-dispatcher kernel.request

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:event-dispatcher --format=json

Options:
--dispatcherTo view events of a specific event dispatcher
--formatThe output format ("txt", "xml", "json", "md")
--rawTo output raw description
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ event[=null] + + + + + + + + + + + + + + + + +
+ + debug:firewall + debug:firewall command displays the firewalls that are configured
in your application:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:firewall

You can pass a firewall name to display more detailed information about
a specific firewall:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:firewall main

To include all events and event listeners for a specific firewall, use the
events option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:firewall --events main


Options:
--eventsInclude a list of event listeners (only available in combination with the "name" argument)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + +
+ + debug:form + debug:form command displays information about form types.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form

The command lists all built-in types, services types, type extensions and
guessers currently available.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form Symfony\Component\Form\Extension\Core\Type\ChoiceType
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form ChoiceType

The command lists all defined options that contains the given form type,
as well as their parents and type extensions.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form ChoiceType choice_value

Use the --show-deprecated option to display form types with
deprecated options or the deprecated options of the given form type:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form --show-deprecated
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form ChoiceType --show-deprecated

The command displays the definition of the given option name.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:form --format=json

The command lists everything in a machine readable json format.

Options:
--show-deprecatedDisplay deprecated options in form types
--formatThe output format ("txt", "json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ class[=null] option[=null] + + + + + + + + + + + + + + + +
+ + debug:messenger + debug:messenger command displays all messages that can be
dispatched using the message buses:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:messenger

Or for a specific bus only:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:messenger command_bus


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ bus[=null] + + + + + + + + + + + + + +
+ + debug:router + debug:router displays the configured routes:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:router

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:router --format=json

Options:
--show-controllersShow assigned controllers in overview
--show-aliasesShow aliases in overview
--formatThe output format ("txt", "xml", "json", "md")
--rawTo output raw route(s)
--methodFilter by HTTP method
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + + + + +
+ + debug:serializer + debug:serializer 'App\Entity\Dummy' command dumps the serializer groups for the dummy class.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ class + + + + + + + + + + + + + +
+ + debug:translation + debug:translation command helps finding unused or missing translation
messages and comparing them with the fallback ones by inspecting the
templates and translation files of a given bundle or the default translations directory.

You can display information about bundle translations in a specific locale:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation en AcmeDemoBundle

You can also specify a translation domain for the search:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation --domain=messages en AcmeDemoBundle

You can only display missing messages:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation --only-missing en AcmeDemoBundle

You can only display unused messages:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation --only-unused en AcmeDemoBundle

You can display information about application translations in a specific locale:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation en

You can display information about translations in all registered bundles in a specific locale:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:translation --all en


Options:
--domainThe messages domain
--only-missingDisplay only missing messages
--only-unusedDisplay only unused messages
--allLoad messages from all registered bundles
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ locale bundle[=null] + + + + + + + + + + + + + + + + + +
+ + debug:twig + debug:twig command outputs a list of twig functions,
filters, globals and tests.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:twig

The command lists all functions, filters, etc.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:twig @Twig/Exception/error.html.twig

The command lists all paths that match the given template name.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:twig --filter=date

The command lists everything that contains the word date.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console debug:twig --format=json

The command lists everything in a machine readable json format.

Options:
--filterShow details for all entries matching this filter
--formatThe output format ("txt", "json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + +
+ + debug:validator + debug:validator 'App\Entity\Dummy' command dumps the validators for the dummy class.

The debug:validator src/ command dumps the validators for the `src` directory.

Options:
--show-allShow all classes even if they have no validation constraints
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ class + + + + + + + + + + + + + + +
+ + doctrine:cache:clear-collection-region + doctrine:cache:clear-collection-region command is meant to clear a second-level cache collection regions for an associated Entity Manager.
It is possible to delete/invalidate all collection region, a specific collection region or flushes the cache provider.

The execution type differ on how you execute the command.
If you want to invalidate all entries for an collection region this command would do the work:

doctrine:cache:clear-collection-region 'Entities\MyEntity' 'collectionName'

To invalidate a specific entry you should use :

doctrine:cache:clear-collection-region 'Entities\MyEntity' 'collectionName' 1

If you want to invalidate all entries for the all collection regions:

doctrine:cache:clear-collection-region --all

Alternatively, if you want to flush the configured cache provider for an collection region use this command:

doctrine:cache:clear-collection-region 'Entities\MyEntity' 'collectionName' --flush

Finally, be aware that if --flush option is passed,
not all cache providers are able to flush entries, because of a limitation of its execution nature.

Options:
--emName of the entity manager to operate on
--allIf defined, all entity regions will be deleted/invalidated.
--flushIf defined, all cache entries will be flushed.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ owner-class[=null] association[=null] owner-id[=null] + + + + + + + + + + + + + + + + +
+ + doctrine:cache:clear-entity-region + doctrine:cache:clear-entity-region command is meant to clear a second-level cache entity region for an associated Entity Manager.
It is possible to delete/invalidate all entity region, a specific entity region or flushes the cache provider.

The execution type differ on how you execute the command.
If you want to invalidate all entries for an entity region this command would do the work:

doctrine:cache:clear-entity-region 'Entities\MyEntity'

To invalidate a specific entry you should use :

doctrine:cache:clear-entity-region 'Entities\MyEntity' 1

If you want to invalidate all entries for the all entity regions:

doctrine:cache:clear-entity-region --all

Alternatively, if you want to flush the configured cache provider for an entity region use this command:

doctrine:cache:clear-entity-region 'Entities\MyEntity' --flush

Finally, be aware that if --flush option is passed,
not all cache providers are able to flush entries, because of a limitation of its execution nature.

Options:
--emName of the entity manager to operate on
--allIf defined, all entity regions will be deleted/invalidated.
--flushIf defined, all cache entries will be flushed.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ entity-class[=null] entity-id[=null] + + + + + + + + + + + + + + + + +
+ + doctrine:cache:clear-metadata + doctrine:cache:clear-metadata command is meant to clear the metadata cache of associated Entity Manager.

Options:
--emName of the entity manager to operate on
--flushIf defined, cache entries will be flushed instead of deleted/invalidated.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + doctrine:cache:clear-query + doctrine:cache:clear-query command is meant to clear the query cache of associated Entity Manager.

Options:
--emName of the entity manager to operate on
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + doctrine:cache:clear-query-region + doctrine:cache:clear-query-region command is meant to clear a second-level cache query region for an associated Entity Manager.
It is possible to delete/invalidate all query region, a specific query region or flushes the cache provider.

The execution type differ on how you execute the command.
If you want to invalidate all entries for the default query region this command would do the work:

doctrine:cache:clear-query-region

To invalidate entries for a specific query region you should use :

doctrine:cache:clear-query-region my_region_name

If you want to invalidate all entries for the all query region:

doctrine:cache:clear-query-region --all

Alternatively, if you want to flush the configured cache provider use this command:

doctrine:cache:clear-query-region my_region_name --flush

Finally, be aware that if --flush option is passed,
not all cache providers are able to flush entries, because of a limitation of its execution nature.

Options:
--emName of the entity manager to operate on
--allIf defined, all query regions will be deleted/invalidated.
--flushIf defined, all cache entries will be flushed.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ region-name[=null] + + + + + + + + + + + + + + + + +
+ + doctrine:cache:clear-result + doctrine:cache:clear-result command is meant to clear the result cache of associated Entity Manager.
It is possible to invalidate all cache entries at once - called delete -, or flushes the cache provider
instance completely.

The execution type differ on how you execute the command.
If you want to invalidate the entries (and not delete from cache instance), this command would do the work:

doctrine:cache:clear-result

Alternatively, if you want to flush the cache provider using this command:

doctrine:cache:clear-result --flush

Finally, be aware that if --flush option is passed, not all cache providers are able to flush entries,
because of a limitation of its execution nature.

Options:
--emName of the entity manager to operate on
--flushIf defined, cache entries will be flushed instead of deleted/invalidated.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + doctrine:database:create + doctrine:database:create command creates the default connections database:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:database:create

You can also optionally specify the name of a connection to create the database for:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:database:create --connection=default

Options:
--connection(-c)The connection to use for this command
--if-not-existsDon't trigger an error, when the database already exists
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + doctrine:database:drop + doctrine:database:drop command drops the default connections database:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:database:drop

The --force parameter has to be used to actually drop the database.

You can also optionally specify the name of a connection to drop the database for:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:database:drop --connection=default

Be careful: All data in a given database will be lost when executing this command.

Options:
--connection(-c)The connection to use for this command
--if-existsDon't trigger an error, when the database doesn't exist
--force(-f)Set this parameter to execute this action
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:mapping:info + doctrine:mapping:info shows basic information about which
entities exist and possibly if their mapping information contains errors or
not.

Options:
--emName of the entity manager to operate on
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + doctrine:migrations:current +
Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:diff + doctrine:migrations:diff command generates a migration by comparing your current database to your mapping information:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:diff


Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--namespaceThe namespace to use for the migration (must be in the list of configured namespaces)
--filter-expressionTables which are filtered by Regular Expression.
--formattedFormat the generated SQL.
--nowdocOutput the generated SQL as a nowdoc string (enabled by default for formatted queries).
--no-nowdocNegate the "--nowdoc" option
--line-lengthMax line length of unformatted lines.
--check-database-platformCheck Database Platform to the generated code.
--allow-empty-diffDo not throw an exception when no changes are detected.
--from-empty-schemaGenerate a full migration as if the current database was empty.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:dump-schema + doctrine:migrations:dump-schema command dumps the schema for your database to a migration:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:dump-schema

After dumping your schema to a migration, you can rollup your migrations using the migrations:rollup command.

Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--formattedFormat the generated SQL.
--nowdocOutput the generated SQL as a nowdoc string (enabled by default for formatted queries).
--no-nowdocNegate the "--nowdoc" option
--namespaceNamespace to use for the generated migrations (defaults to the first namespace definition).
--filter-tablesFilter the tables to dump via Regex.
--line-lengthMax line length of unformatted lines.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:execute + doctrine:migrations:execute command executes migration versions up or down manually:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN

You can show more information about the process by increasing the verbosity level. To see the
executed queries, set the level to debug with -vv:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN -vv

If no --up or --down option is specified it defaults to up:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN --down

You can also execute the migration as a --dry-run:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN --dry-run

You can output the prepared SQL statements to a file with --write-sql:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN --write-sql

Or you can also execute the migration without a warning message which you need to interact with:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN --no-interaction

All the previous commands accept multiple migration versions, allowing you run execute more than
one migration at once:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:execute FQCN-1 FQCN-2 ...FQCN-n


Options:
--write-sqlThe path to output the migration SQL file. Defaults to current working directory.
--dry-runExecute the migration as a dry run.
--upExecute the migration up.
--downExecute the migration down.
--query-timeTime all the queries individually.
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ versions + + + + + + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:generate + doctrine:migrations:generate command generates a blank migration class:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:generate


Options:
--namespaceThe namespace to use for the migration (must be in the list of configured namespaces)
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:latest +
Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:list + doctrine:migrations:list command outputs a list of all available migrations and their status:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:list

Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:migrate + doctrine:migrations:migrate command executes a migration to a specified version or the latest available version:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate

You can show more information about the process by increasing the verbosity level. To see the
executed queries, set the level to debug with -vv:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate -vv

You can optionally manually specify the version you wish to migrate to:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate FQCN

You can specify the version you wish to migrate to using an alias:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate prev
These alias are defined: first, latest, prev, current and next

You can specify the version you wish to migrate to using a number against the current version:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate current+3

You can also execute the migration as a --dry-run:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate FQCN --dry-run

You can output the prepared SQL statements to a file with --write-sql:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate FQCN --write-sql

Or you can also execute the migration without a warning message which you need to interact with --no-interaction:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate --no-interaction

You can also time all the different queries if you want to know which one is taking so long with --query-time:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate --query-time

You can skip throwing an exception if no migration is available with --allow-no-migration:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate --allow-no-migration

You can wrap the entire migration in a transaction with --all-or-nothing:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:migrate --all-or-nothing


Options:
--write-sqlThe path to output the migration SQL file. Defaults to current working directory.
--dry-runExecute the migration as a dry run.
--query-timeTime all the queries individually.
--allow-no-migrationDo not throw an exception if no migration is available.
--all-or-nothingWrap the entire migration in a transaction.
--no-all-or-nothingDisable wrapping the entire migration in a transaction.
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ version[=null] + + + + + + + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:rollup + doctrine:migrations:rollup command rolls up migrations by deleting all tracked versions and
inserts the one version that exists that was created with the migrations:dump-schema command.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:rollup

To dump your schema to a migration version you can use the migrations:dump-schema command.

Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:status + doctrine:migrations:status command outputs the status of a set of migrations:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:status

Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:sync-metadata-storage + The doctrine:migrations:sync-metadata-storage command updates metadata storage to the latest version,
ensuring it is ready to receive migrations generated by the current version of Doctrine Migrations.


/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:sync-metadata-storage

Options:
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + doctrine:migrations:up-to-date + doctrine:migrations:up-to-date command tells you if your schema is up-to-date:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:up-to-date

Options:
--fail-on-unregistered(-u)Whether to fail when there are unregistered extra migrations found
--list-migrations(-l)Show a list of missing or not migrated versions.
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + + +
+ + doctrine:migrations:version + doctrine:migrations:version command allows you to manually add, delete or synchronize migration versions from the version table:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version MIGRATION-FQCN --add

If you want to delete a version you can use the --delete option:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version MIGRATION-FQCN --delete

If you want to synchronize by adding or deleting all migration versions available in the version table you can use the --all option:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version --add --all
/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version --delete --all

If you want to synchronize by adding or deleting some range of migration versions available in the version table you can use the --range-from/--range-to option:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version --add --range-from=MIGRATION-FQCN --range-to=MIGRATION-FQCN
/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version --delete --range-from=MIGRATION-FQCN --range-to=MIGRATION-FQCN

You can also execute this command without a warning message which you need to interact with:

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:migrations:version --no-interaction

Options:
--addAdd the specified version.
--deleteDelete the specified version.
--allApply to all the versions.
--range-fromApply from specified version.
--range-toApply to specified version.
--configurationThe path to a migrations configuration file. [default: any of migrations.{php,xml,json,yml,yaml}]
--emThe name of the entity manager to use.
--connThe name of the connection to use.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ version[=null] + + + + + + + + + + + + + + + + + + + + + +
+ + doctrine:query:dql + doctrine:query:dql command executes the given DQL query and
outputs the results:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:query:dql "SELECT u FROM App\Entity\User u"

You can also optionally specify some additional options like what type of
hydration to use when executing the query:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:query:dql "SELECT u FROM App\Entity\User u" --hydrate=array

Additionally you can specify the first result and maximum amount of results to
show:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:query:dql "SELECT u FROM App\Entity\User u" --first-result=0 --max-result=30

Options:
--emName of the entity manager to operate on
--hydrateHydration mode of result set. Should be either: object, array, scalar or single-scalar.
--first-resultThe first result in the result set.
--max-resultThe maximum number of results in the result set.
--depthDumping depth of Entity graph.
--show-sqlDump generated SQL instead of executing query
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ dql + + + + + + + + + + + + + + + + + + + +
+ + doctrine:query:sql + doctrine:query:sql command executes the given SQL query and
outputs the results:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console doctrine:query:sql "SELECT * FROM users"

Options:
--connectionThe named database connection
--depthDumping depth of result set (deprecated).
--force-fetchForces fetching the result.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ sql + + + + + + + + + + + + + + + + +
+ + doctrine:schema:create +
Hint: If you have a database with tables that should not be managed
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:

$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}

return !str_starts_with($assetName, 'audit_');
});

Options:
--emName of the entity manager to operate on
--dump-sqlInstead of trying to apply generated SQLs into EntityManager Storage Connection, output them.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + doctrine:schema:drop + Beware that the complete database is dropped by this command, even tables that are not relevant to your metadata model.

Hint: If you have a database with tables that should not be managed
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:

$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}

return !str_starts_with($assetName, 'audit_');
});

Options:
--emName of the entity manager to operate on
--dump-sqlInstead of trying to apply generated SQLs into EntityManager Storage Connection, output them.
--force(-f)Don't ask for the deletion of the database, but force the operation to run.
--full-databaseInstead of using the Class Metadata to detect the database table schema, drop ALL assets that the database contains.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + +
+ + doctrine:schema:update + doctrine:schema:update command generates the SQL needed to
synchronize the database schema with the current mapping metadata of the
default entity manager.

For example, if you add metadata for a new column to an entity, this command
would generate and output the SQL needed to add the new column to the database:

doctrine:schema:update --dump-sql

Alternatively, you can execute the generated queries:

doctrine:schema:update --force

If both options are specified, the queries are output and then executed:

doctrine:schema:update --dump-sql --force

Finally, be aware that this task will drop all database assets (e.g. tables,
etc) that are *not* described by the current metadata. In other words, without
this option, this task leaves untouched any "extra" tables that exist in the
database, but which aren't described by any metadata.

Hint: If you have a database with tables that should not be managed
by the ORM, you can use a DBAL functionality to filter the tables and sequences down
on a global level:

$config->setSchemaAssetsFilter(function (string|AbstractAsset $assetName): bool {
if ($assetName instanceof AbstractAsset) {
$assetName = $assetName->getName();
}

return !str_starts_with($assetName, 'audit_');
});

Options:
--emName of the entity manager to operate on
--completeThis option is a no-op, is deprecated and will be removed in 4.0
--dump-sqlDumps the generated SQL statements to the screen (does not execute them).
--force(-f)Causes the generated SQL statements to be physically executed against your database.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + +
+ + doctrine:schema:validate +
Options:
--emName of the entity manager to operate on
--skip-mappingSkip the mapping validation check
--skip-syncSkip checking if the mapping is in sync with the database
--skip-property-typesSkip checking if property types match the Doctrine types
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + +
+ + error:dump +
Options:
--force(-f)Force directory removal before dumping new error pages
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ path status-codes[=null] + + + + + + + + + + + + + + +
+ + importmap:audit + --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:audit --format=json

Options:
--formatThe output format ("txt, json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + importmap:install +
Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + importmap:outdated + importmap:outdated command will list the latest updates available for the 3rd party packages in importmap.php.
Versions showing in red are semver compatible versions and you should upgrading.
Versions showing in yellow are major updates that include backward compatibility breaks according to semver.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:outdated

Or specific packages only:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:outdated

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:outdated --format=json

Options:
--formatThe output format ("txt, json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ packages[=null] + + + + + + + + + + + + + + +
+ + importmap:remove + importmap:remove command removes packages from the importmap.php.
If a package was downloaded into your app, the downloaded file will also be removed.

For example:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:remove lodash

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ packages + + + + + + + + + + + + + +
+ + importmap:require + importmap:require command adds packages to importmap.php usually
by finding a CDN URL for the given package and version.

For example:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require lodash
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "lodash@^4.15"

You can also require specific paths of a package:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "chart.js/auto"

Or require one package/file, but alias its name in your import map:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "vue/dist/vue.esm-bundler.js=vue"

Sometimes, a package may require other packages and multiple new items may be added
to the import map.

You can also require multiple packages at once:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "lodash@^4.15" "@hotwired/stimulus"

To add an importmap entry pointing to a local file, use the path option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "any_module_name" --path=./assets/some_file.js

To simulate the installation, use the --dry-run option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:require "any_module_name" --dry-run -v

When this option is enabled, this command does not perform any write operations to the filesystem.

Options:
--entrypointMake the packages an entrypoint?
--pathThe local path where the package lives relative to the project root
--dry-runSimulate the installation of the packages
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ packages + + + + + + + + + + + + + + + + +
+ + importmap:update + importmap:update command will update all from the 3rd part packages
in importmap.php to their latest version, including downloaded packages.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:update

Or specific packages only:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console importmap:update

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ packages[=null] + + + + + + + + + + + + + +
+ + lint:container +
Options:
--resolve-env-varsResolve environment variables and fail if one is missing.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + lint:translations + lint:translations command lint translations.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:translations

Options:
--localeSpecify the locales to lint.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + command]]> + + + + + + + + + + + + +
+ + lint:twig + lint:twig command lints a template and outputs to STDOUT
the first encountered syntax error.

You can validate the syntax of contents passed from STDIN:

cat filename | php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:twig -

Or the syntax of a file:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:twig filename

Or of a whole directory:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:twig dirname

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:twig dirname --format=json
Or all template files in a bundle:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:twig @AcmeDemoBundle


Options:
--formatThe output format ("txt", "json", "github")
--show-deprecationsShow deprecations as errors
--excludesExcluded directories
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ filename[=null] + + + + + + + + + + + + + + + + +
+ + lint:xliff + lint:xliff command lints an XLIFF file and outputs to STDOUT
the first encountered syntax error.

You can validates XLIFF contents passed from STDIN:

cat filename | php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:xliff -

You can also validate the syntax of a file:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:xliff filename

Or of a whole directory:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:xliff dirname

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:xliff dirname --format=json


Options:
--formatThe output format ("txt", "json", "github")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ filename[=null] + + + + + + + + + + + + + + +
+ + lint:yaml + lint:yaml command lints a YAML file and outputs to STDOUT
the first encountered syntax error.

You can validates YAML contents passed from STDIN:

cat filename | php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml -

You can also validate the syntax of a file:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml filename

Or of a whole directory:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml dirname

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml dirname --format=json

You can also exclude one or more specific files:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml dirname --exclude="dirname/foo.yaml" --exclude="dirname/bar.yaml"

Or find all files in a bundle:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console lint:yaml @AcmeDemoBundle


Options:
--formatThe output format ("txt", "json", "github")
--excludePath(s) to exclude
--parse-tagsParse custom tags
--no-parse-tagsNegate the "--parse-tags" option
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ filename[=null] + + + + + + + + + + + + + + + + + +
+ + mailer:test + mailer:test command tests a Mailer transport by sending a simple email message:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console mailer:test to@example.com

You can also specify a specific transport:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console mailer:test to@example.com --transport=transport_name

Note that this command bypasses the Messenger bus if configured.


Options:
--fromThe sender of the message
--subjectThe subject of the message
--bodyThe body of the message
--transportThe transport to be used
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ to + + + + + + + + + + + + + + + + + +
+ + make:auth + make:auth command generates various authentication systems,
by asking questions.

It can provide an empty authenticator, or a full login form authentication process.
In both cases it also updates your security.yaml.
For the login form, it also generates a controller and the Twig template.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:auth


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + make:command + make:command command generates a new command:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:command app:do-something

If the argument is missing, the command will ask for the command name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:controller + make:controller command generates a new controller class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:controller CoolStuffController

If the argument is missing, the command will ask for the controller class name interactively.

If you have the symfony/twig-bundle installed, a Twig template will also be
generated for the controller.

composer require symfony/twig-bundle

You can also generate the controller alone, without template with this option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:controller --no-template

To generate tailored PHPUnit tests, simply call:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:controller --with-tests

This will generate a unit test in tests/ for you to review then use
to test the new functionality of your app.


Options:
--no-templateUse this option to disable template generation
--invokable(-i)Use this option to create an invokable controller
--with-testsGenerate PHPUnit Tests
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ controller-class[=null] + + + + + + + + + + + + + + + + +
+ + make:crud + make:crud command generates crud controller with templates for selected entity.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:crud BlogPost

If the argument is missing, the command will ask for the entity class name interactively.
To generate tailored PHPUnit tests, simply call:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:crud --with-tests

This will generate a unit test in tests/ for you to review then use
to test the new functionality of your app.


Options:
--with-testsGenerate PHPUnit Tests
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ entity-class[=null] + + + + + + + + + + + + + + +
+ + make:docker:database + make:docker:database command generates or updates databases services in compose.yaml

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:docker:database

Supports MySQL, MariaDB and PostgreSQL


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + make:entity + make:entity command creates or updates an entity and repository class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity BlogPost

If the argument is missing, the command will ask for the entity class name interactively.

You can also mark this class as an API Platform resource. A hypermedia CRUD API will
automatically be available for this entity class:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --api-resource

Symfony can also broadcast all changes made to the entity to the client using Symfony
UX Turbo.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --broadcast

You can also generate all the getter/setter/adder/remover methods
for the properties of existing entities:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --regenerate

You can also *overwrite* any existing methods:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --regenerate --overwrite

Instead of using the default "int" type for the entity's "id", you can use the
UUID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-uuids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --with-uuid

Or you can use the ULID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-ulids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:entity --with-ulid


Options:
--api-resource(-a)Mark this class as an API Platform resource (expose a CRUD API for it)
--broadcast(-b)Add the ability to broadcast entity updates using Symfony UX Turbo?
--regenerateInstead of adding new fields, simply generate the methods (e.g. getter/setter) for existing fields
--overwriteOverwrite any existing getter/setter methods
--with-uuidUse UUID for entity "id"
--with-ulidUse ULID for entity "id"
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + + + + + +
+ + make:fixtures + make:fixtures command generates a new Doctrine fixtures class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:fixtures AppFixtures

If the argument is missing, the command will ask for a class interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ fixtures-class[=null] + + + + + + + + + + + + + +
+ + make:form + make:form command generates a new form class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:form UserType

If the argument is missing, the command will ask for the form class interactively.

You can optionally specify the bound class in a second argument.
This can be the name of an entity like User

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:form UserType User

You can also specify a fully qualified name to another class like \App\Dto\UserData.
Slashes must be escaped in the argument.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:form UserType \\App\\Dto\\UserData



Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] bound-class[=null] + + + + + + + + + + + + + +
+ + make:listener + make:listener command generates a new event subscriber class or a new event listener class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:listener ExceptionListener

If the argument is missing, the command will ask for the class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] event[=null] + + + + + + + + + + + + + +
+ + make:message + make:message command generates a new message class & handler.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:message EmailMessage

If the argument is missing, the command will ask for the message class interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:messenger-middleware + make:messenger-middleware command generates a new message class & handler.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:messenger-middleware EmailMessage

If the argument is missing, the command will ask for the message class interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:migration + make:migration command generates a new migration:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:migration

You can also generate a formatted migration with this option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:migration --formatted


Options:
--formattedFormat the generated SQL
--configurationThe path of doctrine configuration file
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + make:registration-form + make:registration-form command generates a complete registration form, controller & template.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:registration-form

The command will ask for several pieces of information to build your form.

To generate tailored PHPUnit tests, simply call:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:registration-form --with-tests

This will generate a unit test in tests/ for you to review then use
to test the new functionality of your app.


Options:
--with-testsGenerate PHPUnit Tests
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + make:reset-password + make:reset-password command generates all the files needed to implement
a fully-functional & secure password reset system.

The SymfonycastsResetPasswordBundle is required and can be added using composer:
composer require symfonycasts/reset-password-bundle

For more information on the reset-password-bundle check out:
https://github.com/symfonycasts/reset-password-bundle

make:reset-password requires a user entity with an email property,
email getter method, and a password setter method. Maker will ask for these
interactively if they cannot be guessed.

Maker will also update your reset-password.yaml configuration file
if one exists. If you have customized the configuration file, maker will attempt
to modify it accordingly but preserve your customizations.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:reset-password

Instead of using the default "int" type for the entity's "id", you can use the
UUID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-uuids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:reset-password --with-uuid

Or you can use the ULID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-ulids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:reset-password --with-ulid

To generate tailored PHPUnit tests, simply call:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:reset-password --with-tests

This will generate a unit test in tests/ for you to review then use
to test the new functionality of your app.


Options:
--with-uuidUse UUID for entity "id"
--with-ulidUse ULID for entity "id"
--with-testsGenerate PHPUnit Tests
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + +
+ + make:schedule + make:schedule command generates a schedule to automate repeated
tasks using Symfony's Scheduler Component.

If the Scheduler Component is not installed, make:schedule will
install it automatically using composer. You can of course do this manually by
running composer require symfony/scheduler.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:schedule


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + make:security:custom + make:security:custom command generates a simple custom authenticator
class based off the example provided in:

https://symfony.com/doc/current/security/custom_authenticator.html

This will also update your security.yaml for the new custom authenticator.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:security:custom


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + make:security:form-login + make:security:form-login command generates a controller and Twig template
to allow users to login using the form_login authenticator.

The controller name, and logout ability can be customized by answering the
questions asked when running make:security:form-login.

This will also update your security.yaml for the new authenticator.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:security:form-login

To generate tailored PHPUnit tests, simply call:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:security:form-login --with-tests

This will generate a unit test in tests/ for you to review then use
to test the new functionality of your app.


Options:
--with-testsGenerate PHPUnit Tests
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + make:serializer:encoder + make:serializer:encoder command generates a new serializer encoder class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:serializer:encoder YamlEncoder

If the argument is missing, the command will ask for the class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] format[=null] + + + + + + + + + + + + + +
+ + make:serializer:normalizer + make:serializer:normalizer command generates a new serializer normalizer class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:serializer:normalizer UserNormalizer

If the argument is missing, the command will ask for the class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:stimulus-controller + make:stimulus-controller command generates a new Stimulus controller.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:stimulus-controller hello

If the argument is missing, the command will ask for the controller name interactively.

To generate a TypeScript file (instead of a JavaScript file) use the --typescript
(or --ts) option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:stimulus-controller hello --typescript

It will also interactively ask for values, targets, classes to add to the Stimulus
controller (optional).

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:stimulus-controller


Options:
--typescript(-ts)Create a TypeScript controller (default is JavaScript)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name + + + + + + + + + + + + + + +
+ + make:test + make:test command generates a new test class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:test TestCase BlogPostTest

If the first argument is missing, the command will ask for the test type interactively.

If the second argument is missing, the command will ask for the class name interactively.
* TestCase: basic PHPUnit tests
* KernelTestCase: basic tests that have access to Symfony services
* WebTestCase: to run browser-like scenarios, but that don't execute JavaScript code
* ApiTestCase: to run API-oriented scenarios
* PantherTestCase: to run e2e scenarios, using a real-browser or HTTP client and a real web server

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ type[=null] name[=null] + + + + + + + + + + + + + +
+ + make:twig-component +
Options:
--liveWhether to create a Live component (requires symfony/ux-live-component)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + +
+ + make:twig-extension + make:twig-extension command generates a new Twig extension with its runtime class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:twig-extension AppExtension

If the argument is missing, the command will ask for the class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:user + make:user command generates a new user class for security
and updates your security.yaml file for it. It will also generate a user provider
class if your situation needs a custom class.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:user User

If the argument is missing, the command will ask for the class name interactively.

Instead of using the default "int" type for the entity's "id", you can use the
UUID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-uuids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:user --with-uuid

Or you can use the ULID type from Symfony's Uid component.
https://symfony.com/doc/current/components/uid.html#storing-ulids-in-databases

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:user --with-ulid


Options:
--is-entityDo you want to store user data in the database (via Doctrine)?
--identity-property-nameEnter a property name that will be the unique "display" name for the user (e.g. email, username, uuid)
--with-passwordWill this app be responsible for checking the password? Choose No if the password is actually checked by some other system (e.g. a single sign-on server)
--with-uuidUse UUID for entity "id"
--with-ulidUse ULID for entity "id"
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + + + + + + +
+ + make:validator + make:validator command generates a new validation constraint.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:validator EnabledValidator

If the argument is missing, the command will ask for the constraint class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:voter + make:voter command generates a new security voter.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:voter BlogPostVoter

If the argument is missing, the command will ask for the class name interactively.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + make:webhook + make:webhook command creates a RequestParser, a WebhookHandler and adds the necessary configuration
for a new Webhook.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console make:webhook stripe

If the argument is missing, the command will ask for the webhook name interactively.

It will also interactively ask for the RequestMatchers to use for the RequestParser's getRequestMatcher function.


Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name[=null] + + + + + + + + + + + + + +
+ + messenger:consume + messenger:consume command consumes messages and dispatches them to the message bus.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume

To receive from multiple transports, pass each name:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume receiver1 receiver2

Use the --limit option to limit the number of messages received:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --limit=10

Use the --failure-limit option to stop the worker when the given number of failed messages is reached:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --failure-limit=2

Use the --memory-limit option to stop the worker if it exceeds a given memory usage limit. You can use shorthand byte values [K, M or G]:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --memory-limit=128M

Use the --time-limit option to stop the worker when the given time limit (in seconds) is reached.
If a message is being handled, the worker will stop after the processing is finished:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --time-limit=3600

Use the --bus option to specify the message bus to dispatch received messages
to instead of trying to determine it automatically. This is required if the
messages didn't originate from Messenger:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --bus=event_bus

Use the --queues option to limit a receiver to only certain queues (only supported by some receivers):

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --queues=fasttrack

Use the --no-reset option to prevent services resetting after each message (may lead to leaking services' state between messages):

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --no-reset

Use the --all option to consume from all receivers:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:consume --all

Options:
--limit(-l)Limit the number of received messages
--failure-limit(-f)The number of failed messages the worker can consume
--memory-limit(-m)The memory limit the worker can consume
--time-limit(-t)The time limit in seconds the worker can handle new messages
--sleepSeconds to sleep before asking for new messages after no messages were found
--bus(-b)Name of the bus to which received messages should be dispatched (if not passed, bus is determined automatically)
--queuesLimit receivers to only consume from the specified queues
--no-resetDo not reset container services after each message
--allConsume messages from all receivers
--keepaliveWhether to use the transport's keepalive mechanism if implemented
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ receivers[=null] + + + + + + + + + + + + + + + + + + + + + + + +
+ + messenger:failed:remove + messenger:failed:remove removes given messages that are pending in the failure transport.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:remove {id1} [{id2} ...]

The specific ids can be found via the messenger:failed:show command.

You can remove all failed messages from the failure transport by using the "--all" option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:remove --all

Options:
--allRemove all failed messages from the transport
--forceForce the operation without confirmation
--transportUse a specific failure transport
--show-messagesDisplay messages before removing it (if multiple ids are given)
--class-filterFilter by a specific class name
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ id[=null] + + + + + + + + + + + + + + + + + + +
+ + messenger:failed:retry + messenger:failed:retry retries message in the failure transport.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:retry

The command will interactively ask if each message should be retried,
discarded or skipped.

Some transports support retrying a specific message id, which comes
from the messenger:failed:show command.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:retry {id}

Or pass multiple ids at once to process multiple messages:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:retry {id1} {id2} {id3}


Options:
--forceForce action without confirmation
--transportUse a specific failure transport
--keepaliveWhether to use the transport's keepalive mechanism if implemented
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ id[=null] + + + + + + + + + + + + + + + + +
+ + messenger:failed:show + messenger:failed:show shows message that are pending in the failure transport.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:show

Or look at a specific message by its id:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:failed:show {id}

Options:
--maxMaximum number of messages to list
--transportUse a specific failure transport
--statsDisplay the message count by class
--class-filterFilter by a specific class name
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ id[=null] + + + + + + + + + + + + + + + + + +
+ + messenger:setup-transports + messenger:setup-transports command setups the transports:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:setup-transports

Or a specific transport only:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:setup-transports

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ transport[=null] + + + + + + + + + + + + + +
+ + messenger:stats + messenger:stats command counts the messages for all the transports:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:stats

Or specific transports only:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:stats

The --format option specifies the format of the command output:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:stats --format=json

Options:
--formatThe output format ("txt", "json")
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ transport_names[=null] + + + + + + + + + + + + + + +
+ + messenger:stop-workers + messenger:stop-workers command sends a signal to stop any messenger:consume processes that are running.

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console messenger:stop-workers

Each worker command will finish the message they are currently processing
and then exit. Worker commands are *not* automatically restarted: that
should be handled by a process control system.

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + router:match + router:match shows which routes match a given request and which don't and for what reason:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console router:match /foo

or

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console router:match /foo --method POST --scheme https --host symfony.com --verbose


Options:
--methodSet the HTTP method
--schemeSet the URI scheme (usually http or https)
--hostSet the URI host
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ path_info + + + + + + + + + + + + + + + + +
+ + secrets:decrypt-to-local + secrets:decrypt-to-local command decrypts all secrets and copies them in the local vault.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:decrypt-to-local

When the --force option is provided, secrets that already exist in the local vault are overridden.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:decrypt-to-local --force

Options:
--force(-f)Force overriding of secrets that already exist in the local vault
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + secrets:encrypt-from-local + secrets:encrypt-from-local command encrypts all locally overridden secrets to the vault.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:encrypt-from-local

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + +
+ + secrets:generate-keys + secrets:generate-keys command generates a new encryption key.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:generate-keys

If encryption keys already exist, the command must be called with
the --rotate option in order to override those keys and re-encrypt
existing secrets.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:generate-keys --rotate

Options:
--local(-l)Update the local vault.
--rotate(-r)Re-encrypt existing secrets with the newly generated keys.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + +
+ + secrets:list + secrets:list command list all stored secrets.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:list

When the option --reveal is provided, the decrypted secrets are also displayed.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:list --reveal

Options:
--reveal(-r)Display decrypted values alongside names
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + secrets:remove + secrets:remove command removes a secret from the vault.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:remove

Options:
--local(-l)Update the local vault.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name + + + + + + + + + + + + + + +
+ + secrets:reveal + secrets:reveal command reveals a stored secret.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:reveal

Options:
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name + + + + + + + + + + + + + +
+ + secrets:set + secrets:set command stores a secret in the vault.

/home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:set

To reference secrets in services.yaml or any other config
files, use "%env()%".

By default, the secret value should be entered interactively.
Alternatively, provide a file where to read the secret from:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:set filename

Use "-" as a file name to read from STDIN:

cat filename | php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console secrets:set -

Use --local to override secrets for local needs.

Options:
--local(-l)Update the local vault.
--random(-r)Generate a random value.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ name file[=null] + + + + + + + + + + + + + + + +
+ + security:hash-password + The security:hash-password command hashes passwords according to your
security configuration. This command is mainly used to generate passwords for
the in_memory user provider type and for changing passwords
in the database while developing the application.

Suppose that you have the following security configuration in your application:


# config/packages/security.yml
security:
password_hashers:
Symfony\Component\Security\Core\User\InMemoryUser: plaintext
App\Entity\User: auto


If you execute the command non-interactively, the first available configured
user class under the security.password_hashers key is used and a random salt is
generated to hash the password:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console security:hash-password --no-interaction [password]

Pass the full user class path as the second argument to hash passwords for
your own entities:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console security:hash-password --no-interaction [password] 'App\Entity\User'

Executing the command interactively allows you to generate a random salt for
hashing the password:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console security:hash-password [password] 'App\Entity\User'

In case your hasher doesn't require a salt, add the empty-salt option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console security:hash-password --empty-salt [password] 'App\Entity\User'


Options:
--empty-saltDo not generate a salt or let the hasher generate one.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ password[=null] user-class[=null] + + + + + + + + + + + + + + +
+ + server:dump + server:dump starts a dump server that collects and displays
dumps in a single place for debugging you application:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console server:dump

You can consult dumped data in HTML format in your browser by providing the --format=html option
and redirecting the output to a file:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console server:dump --format="html" > dump.html


Options:
--formatThe output format (cli, html)
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + +
+ + server:log + server:log starts a log server to display in real time the log
messages generated by your application:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console server:log

To filter the log messages using any ExpressionLanguage compatible expression, use the --filter option:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console server:log --filter="level > 200 or channel in ['app', 'doctrine']"

Options:
--hostThe server host
--formatThe line format
--date-formatThe date format
--filterAn expression to filter log. Example: "level > 200 or channel in ['app', 'doctrine']"
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ + + + + + + + + + + + + + + + + +
+ + translation:extract + translation:extract command extracts translation strings from templates
of a given bundle or the default translations directory. It can display them or merge
the new ones into the translation files.

When new translation strings are found it can automatically add a prefix to the translation
message. However, if the --no-fill option is used, the --prefix
option has no effect, since the translation values are left empty.

Example running against a Bundle (AcmeBundle)

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --dump-messages en AcmeBundle
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --force --prefix="new_" fr AcmeBundle

Example running against default messages directory

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --dump-messages en
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --force --prefix="new_" fr

You can sort the output with the --sort flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --dump-messages --sort=asc en AcmeBundle
php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --force --sort=desc fr

You can dump a tree-like structure using the yaml format with --as-tree flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:extract --force --format=yaml --as-tree=3 en AcmeBundle


Options:
--prefixOverride the default prefix
--no-fillExtract translation keys without filling in values
--formatOverride the default output format
--dump-messagesShould the messages be dumped in the console
--forceShould the extract be done
--cleanShould clean not found messages
--domainSpecify the domain to extract
--sortReturn list of messages sorted alphabetically
--as-treeDump the messages as a tree-like structure: The given value defines the level where to switch to inline YAML
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ locale bundle[=null] + + + + + + + + + + + + + + + + + + + + + + +
+ + translation:pull + translation:pull command pulls translations from the given provider. Only
new translations are pulled, existing ones are not overwritten.

You can overwrite existing translations (and remove the missing ones on local side) by using the --force flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:pull --force provider

Full example:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:pull provider --force --domains=messages --domains=validators --locales=en

This command pulls all translations associated with the messages and validators domains for the en locale.
Local translations for the specified domains and locale are deleted if they're not present on the provider and overwritten if it's the case.
Local translations for others domains and locales are ignored.

Options:
--forceOverride existing translations with provider ones (it will delete not synchronized messages).
--intl-icuAssociated to --force option, it will write messages in "%domain%+intl-icu.%locale%.xlf" files.
--domainsSpecify the domains to pull.
--localesSpecify the locales to pull.
--formatOverride the default output format.
--as-treeWrite messages as a tree-like structure. Needs --format=yaml. The given value defines the level where to switch to inline YAML
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ provider + + + + + + + + command]]> + + + + + + + + + + + + +
+ + translation:push + translation:push command pushes translations to the given provider. Only new
translations are pushed, existing ones are not overwritten.

You can overwrite existing translations by using the --force flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:push --force provider

You can delete provider translations which are not present locally by using the --delete-missing flag:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:push --delete-missing provider

Full example:

php /home/poule/encrypted/stockage-syncable/www/development/html/qualiwiki/bin/console translation:push provider --force --delete-missing --domains=messages --domains=validators --locales=en

This command pushes all translations associated with the messages and validators domains for the en locale.
Provider translations for the specified domains and locale are deleted if they're not present locally and overwritten if it's the case.
Provider translations for others domains and locales are ignored.

Options:
--forceOverride existing translations with local ones (it will delete not synchronized messages).
--delete-missingDelete translations available on provider but not locally.
--domainsSpecify the domains to push.
--localesSpecify the locales to push.
--help(-h)Display help for the given command. When no command is given display help for the list command
--silentDo not output any message
--quiet(-q)Only errors are displayed. All other output is suppressed
--verbose(-v)Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
--version(-V)Display this application version
--ansiForce (or disable --no-ansi) ANSI output
--no-ansiNegate the "--ansi" option
--no-interaction(-n)Do not ask any interactive question
--env(-e)The Environment name.
--no-debugSwitch off debug mode.
--profileEnables profiling (requires debug).

]]>
+ provider + + + + + + command]]> + + + + + + + + + + + + +
+
+ diff --git a/.idea/commandlinetools/schemas/frameworkDescriptionVersion1.1.4.xsd b/.idea/commandlinetools/schemas/frameworkDescriptionVersion1.1.4.xsd new file mode 100644 index 0000000..f2efc6d --- /dev/null +++ b/.idea/commandlinetools/schemas/frameworkDescriptionVersion1.1.4.xsd @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/.idea/inspectionProfiles/Project_Default.xml b/.idea/inspectionProfiles/Project_Default.xml new file mode 100644 index 0000000..dee35bc --- /dev/null +++ b/.idea/inspectionProfiles/Project_Default.xml @@ -0,0 +1,21 @@ + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 0000000..b095acb --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/php.xml b/.idea/php.xml new file mode 100644 index 0000000..e72d568 --- /dev/null +++ b/.idea/php.xml @@ -0,0 +1,158 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/qualiwiki.iml b/.idea/qualiwiki.iml new file mode 100644 index 0000000..046d399 --- /dev/null +++ b/.idea/qualiwiki.iml @@ -0,0 +1,140 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/symfony2.xml b/.idea/symfony2.xml new file mode 100644 index 0000000..bd98e40 --- /dev/null +++ b/.idea/symfony2.xml @@ -0,0 +1,6 @@ + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 0000000..35eb1dd --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index e69de29..49942af 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,34 @@ +# QualiWiki +Outil de mise en qualité du wiki OpenStreetMap. + +plusieurs pages: + + - l’accueil liste les pages par ordre de manque de mise à jour du plus grave au moins grave parmi les pages de tags très utilisés selon taginfo. + - on y voit aussi une liste de pages arbitrairement suivies, dont celle proposée par @AdrienHegy , on peut en mettre d’autres. + - des pages fr sans traduction en anglais + - des pages englishes sans traduction fr + - un graphe de répartition de la décrépitude en fin de page. + - chaque page peut être comparée entre version fr et englishe. on y trouve une liste des sections, des images, des propositions de correction de la page française par Grammalecte. Exemple ici où on a clairement plus de contenu en version Française qu’en Anglais: Comparaison Wiki OSM - Tag:amenity=charging_station , cas inverse, la page de procédé de proposition Comparaison Wiki OSM - Proposal process qui est bien plus riche en Anglais qu’en Français. + - on a une suggestion de page au hasard pour voir à quel point elle manque de fraîcheur + - propositions archivées: une étude des 200 propositions de tags, de leurs status et de leurs votes avec quelques stats. + - changements récents: une vue globale des dernières modifications de l’année, ce qui permet de voir qui sont les gens qui potassent le wiki régulièrement. + - les propositions en cours de vote avec un graphe des votes + +On peut aussi cliquer sur plusieurs trucs dans la page de comparaison pour copier ou rechercher dans le wiki. + +Havez fun. +# installation + +npm install +npm run build +composer install + +pas besoin de base de données, les infos sont stockées dans des fichiers json suite au lancement de scripts de wiki_compare. + +python3 -m venv venv +source venv/bin/activate +pip install -r requirements.txt + +# liens +sujet sur le forum osm fr: https://forum.openstreetmap.fr/t/fabriquer-un-outil-de-qualite-pour-le-wiki-osm/36814 +- Tykayn - Cipherbliss.com \ No newline at end of file diff --git a/README.md~ b/README.md~ new file mode 100644 index 0000000..e69de29 diff --git a/assets/app.js b/assets/app.js new file mode 100644 index 0000000..40604d5 --- /dev/null +++ b/assets/app.js @@ -0,0 +1,360 @@ +/* + * Welcome to your app's main JavaScript file! + * + * We recommend including the built version of this JavaScript file + * (and its CSS file) in your base layout (base.html.twig). + */ + +// any CSS you import will output into a single css file (app.css in this case) +import './styles/app.css'; +import jQuery from 'jquery'; +window.$ = jQuery; +window.jQuery = jQuery; +import 'tablesort/tablesort.css'; + +// start the Stimulus application +// import './bootstrap'; + +import './utils.js'; +import './opening_hours.js'; +import './josm.js'; +import './edit.js'; +import './table-map-toggles.js'; +import './stats-charts.js'; +import './dashboard-charts.js'; + +import Chart from 'chart.js/auto'; +import ChartDataLabels from 'chartjs-plugin-datalabels'; +import maplibregl from 'maplibre-gl'; +import { + genererCouleurPastel, + setupCitySearch, + handleAddCityFormSubmit, + enableLabourageForm, + getLabourerUrl, + adjustListGroupFontSize, + toggleCompletionInfo, + updateMapHeightForLargeScreens +} from './utils.js'; +import tableSortJs from 'table-sort-js/table-sort.js'; +import 'chartjs-adapter-date-fns'; +console.log('TableSort', tableSortJs) + +// Charger table-sortable (version non minifiée locale) +// import '../assets/js/table-sortable.js'; + +window.Chart = Chart; +window.genererCouleurPastel = genererCouleurPastel; +window.setupCitySearch = setupCitySearch; +window.handleAddCityFormSubmit = handleAddCityFormSubmit; +window.getLabourerUrl = getLabourerUrl; +window.ChartDataLabels = ChartDataLabels; +window.maplibregl = maplibregl; +window.toggleCompletionInfo = toggleCompletionInfo; +window.updateMapHeightForLargeScreens = updateMapHeightForLargeScreens; +// window.Tablesort = Tablesort; + +Chart.register(ChartDataLabels); + +// Attendre le chargement du DOM +document.addEventListener('DOMContentLoaded', () => { + console.log('DOMContentLoaded'); + + if(updateMapHeightForLargeScreens){ + + + window.addEventListener('resize', updateMapHeightForLargeScreens); + } + + const randombg = genererCouleurPastel(); + // Appliquer la couleur au body + + document.querySelectorAll('body, .edit-land, .body-landing').forEach(element => { + element.style.backgroundColor = randombg; + }); + + // Gestion du bouton pour afficher tous les champs + const btnShowAllFields = document.querySelector('#showAllFields'); + if (btnShowAllFields) { + console.log('btnShowAllFields détecté'); + btnShowAllFields.addEventListener('click', () => { + // Sélectionner tous les inputs dans le formulaire + const form = document.querySelector('form'); + if (form) { + // Sélectionner tous les inputs sauf #validation_messages + const hiddenInputs = form.querySelectorAll('#advanced_tags'); + + hiddenInputs.forEach(input => { + input.classList.toggle('d-none'); + }); + } + }); + } + const btnClosedCommerce = document.querySelector('#closedCommerce'); + if (btnClosedCommerce) { + btnClosedCommerce.addEventListener('click', () => { + + if (!confirm('Êtes-vous sûr de vouloir signaler ce commerce comme fermé ?')) { + return; + } + window.location.href = '/closed_commerce/' + document.getElementById('app_public_closed_commerce').value; + }); + } + + openingHoursFormManager.init(); + + + // Vérifier si l'élément avec l'ID 'userChangesHistory' existe avant d'appeler la fonction + if (document.getElementById('userChangesHistory')) { + listChangesets(); + } else { + console.log('userChangesHistory non trouvé'); + } + + document.querySelectorAll('input[type="text"]').forEach(input => { + input.addEventListener('blur', updateCompletionProgress); + }); + const form = document.querySelector('form') + if (form) { + form.addEventListener('submit', check_validity); + updateCompletionProgress() + } + updateCompletionProgress(); + + // Focus sur le premier champ texte au chargement + // const firstTextInput = document.querySelector('input.form-control'); + // if (firstTextInput) { + // firstTextInput.focus(); + // console.log('focus sur le premier champ texte', firstTextInput); + // } else { + // console.log('pas de champ texte trouvé'); + // } + + + + + parseCuisine(); + + // Modifier la fonction de recherche existante + const searchInput = document.getElementById('app_admin_labourer'); + const suggestionList = document.getElementById('suggestionList'); + + if (searchInput && suggestionList) { + let timeoutId; + + searchInput.addEventListener('input', () => { + clearTimeout(timeoutId); + const query = searchInput.value.trim(); + + if (query.length < 2) { + suggestionList.innerHTML = ''; + return; + } + + timeoutId = setTimeout(async () => { + const suggestions = await searchInseeCode(query); + suggestionList.innerHTML = ''; + + if (suggestions.length === 0) { + const li = document.createElement('li'); + li.style.cssText = ` + padding: 8px 12px; + color: #666; + font-style: italic; + `; + li.textContent = 'Aucun résultat trouvé'; + suggestionList.appendChild(li); + return; + } + + suggestions.forEach(suggestion => { + const li = document.createElement('li'); + li.style.cssText = ` + padding: 8px 12px; + cursor: pointer; + border-bottom: 1px solid #eee; + `; + li.textContent = suggestion.label; + + li.addEventListener('mouseenter', () => { + li.style.backgroundColor = '#f0f0f0'; + }); + + li.addEventListener('mouseleave', () => { + li.style.backgroundColor = 'white'; + }); + + li.addEventListener('click', () => { + searchInput.value = suggestion.insee; + suggestionList.innerHTML = ''; + labourer(); + }); + + suggestionList.appendChild(li); + }); + }, 300); + }); + } + + if(enableLabourageForm){ + + enableLabourageForm(); + } + adjustListGroupFontSize('.list-group-item'); + + // Activer le tri naturel sur tous les tableaux avec la classe table-sort + if (tableSortJs) { + tableSortJs(); + }else{ + console.log('pas de tablesort') + } + + // Initialisation du tri et filtrage sur les tableaux du dashboard et de la page stats + // if (document.querySelector('#dashboard-table')) { + // $('#dashboard-table').tableSortable({ + // pagination: false, + // showPaginationLabel: true, + // searchField: '#dashboard-table-search', + // responsive: false + // }); + // } + // if (document.querySelector('#stats-table')) { + // $('#stats-table').tableSortable({ + // pagination: false, + // showPaginationLabel: true, + // searchField: '#stats-table-search', + // responsive: false + // }); + // } + + // Correction pour le formulaire de labourage + const labourerForm = document.getElementById('labourerForm'); + if (labourerForm) { + labourerForm.addEventListener('submit', async function(e) { + e.preventDefault(); + const zipInput = document.getElementById('selectedZipCode'); + const cityInput = document.getElementById('citySearch'); + let insee = zipInput.value; + if (!insee && cityInput && cityInput.value.trim().length > 0) { + // Recherche du code INSEE via l'API + const response = await fetch(`https://geo.api.gouv.fr/communes?nom=${encodeURIComponent(cityInput.value.trim())}&fields=nom,code&limit=1`); + const data = await response.json(); + if (data.length > 0) { + insee = data[0].code; + } + } + if (insee) { + window.location.href = `/add-city-without-labourage/${insee}`; + } else { + alert('Veuillez sélectionner une ville valide.'); + } + }); + } + + // Ajouter un écouteur pour l'événement 'load' de MapLibre afin d'ajuster la hauteur de la carte + if (window.maplibregl && document.getElementById('map')) { + // On suppose que la carte est initialisée ailleurs et accessible via window.mapInstance + // Sinon, on peut essayer de détecter l'instance automatiquement + let mapInstance = window.mapInstance; + if (!mapInstance && window.maplibreMap) { + mapInstance = window.maplibreMap; + } + // Si l'instance n'est pas trouvée, essayer de la récupérer via une variable globale courante + if (!mapInstance && window.map) { + mapInstance = window.map; + } + if (mapInstance && typeof mapInstance.on === 'function') { + mapInstance.on('load', function() { + updateMapHeightForLargeScreens(); + }); + } + } + //updateMapHeightForLargeScreens(); + + console.log('window.followupSeries',window.followupSeries) + if (!window.followupSeries) return; + + const series = window.followupSeries; + + // Données bornes de recharge + const chargingStationCount = (series['charging_station_count'] || []).map(point => ({ x: point.date, y: point.value })); + const chargingStationCompletion = (series['charging_station_completion'] || []).map(point => ({ x: point.date, y: point.value })); + + // Données bornes incendie + const fireHydrantCount = (series['fire_hydrant_count'] || []).map(point => ({ x: point.date, y: point.value })); + const fireHydrantCompletion = (series['fire_hydrant_completion'] || []).map(point => ({ x: point.date, y: point.value })); + + // Graphique bornes de recharge + const chargingStationChart = document.getElementById('chargingStationChart'); + if (chargingStationChart) { + new Chart(chargingStationChart, { + type: 'line', + data: { + datasets: [ + { + label: 'Nombre de bornes de recharge', + data: chargingStationCount, + borderColor: 'blue', + backgroundColor: 'rgba(0,0,255,0.1)', + fill: false, + yAxisID: 'y', + }, + { + label: 'Complétion (%)', + data: chargingStationCompletion, + borderColor: 'green', + backgroundColor: 'rgba(0,255,0,0.1)', + fill: false, + yAxisID: 'y1', + } + ] + }, + options: { + parsing: false, + responsive: true, + scales: { + x: { type: 'time', time: { unit: 'day' }, title: { display: true, text: 'Date' } }, + y: { beginAtZero: true, title: { display: true, text: 'Nombre' } }, + y1: { beginAtZero: true, position: 'right', title: { display: true, text: 'Complétion (%)' }, grid: { drawOnChartArea: false } } + } + } + }); + } + + // Graphique bornes incendie + const fireHydrantChart = document.getElementById('fireHydrantChart'); + if (fireHydrantChart) { + new Chart(fireHydrantChart, { + type: 'line', + data: { + datasets: [ + { + label: 'Nombre de bornes incendie', + data: fireHydrantCount, + borderColor: 'red', + backgroundColor: 'rgba(255,0,0,0.1)', + fill: false, + yAxisID: 'y', + }, + { + label: 'Complétion (%)', + data: fireHydrantCompletion, + borderColor: 'orange', + backgroundColor: 'rgba(255,165,0,0.1)', + fill: false, + yAxisID: 'y1', + } + ] + }, + options: { + parsing: false, + responsive: true, + scales: { + x: { type: 'time', time: { unit: 'day' }, title: { display: true, text: 'Date' } }, + y: { beginAtZero: true, title: { display: true, text: 'Nombre' } }, + y1: { beginAtZero: true, position: 'right', title: { display: true, text: 'Complétion (%)' }, grid: { drawOnChartArea: false } } + } + } + }); + } +}); diff --git a/assets/bootstrap.js b/assets/bootstrap.js new file mode 100644 index 0000000..d4e50c9 --- /dev/null +++ b/assets/bootstrap.js @@ -0,0 +1,5 @@ +import { startStimulusApp } from '@symfony/stimulus-bundle'; + +const app = startStimulusApp(); +// register any custom, 3rd party controllers here +// app.register('some_controller_name', SomeImportedController); diff --git a/assets/controllers.json b/assets/controllers.json new file mode 100644 index 0000000..29ea244 --- /dev/null +++ b/assets/controllers.json @@ -0,0 +1,15 @@ +{ + "controllers": { + "@symfony/ux-turbo": { + "turbo-core": { + "enabled": true, + "fetch": "eager" + }, + "mercure-turbo-stream": { + "enabled": false, + "fetch": "eager" + } + } + }, + "entrypoints": [] +} diff --git a/assets/controllers/csrf_protection_controller.js b/assets/controllers/csrf_protection_controller.js new file mode 100644 index 0000000..0f56bc1 --- /dev/null +++ b/assets/controllers/csrf_protection_controller.js @@ -0,0 +1,79 @@ +const nameCheck = /^[-_a-zA-Z0-9]{4,22}$/; +const tokenCheck = /^[-_/+a-zA-Z0-9]{24,}$/; + +// Generate and double-submit a CSRF token in a form field and a cookie, as defined by Symfony's SameOriginCsrfTokenManager +document.addEventListener('submit', function (event) { + generateCsrfToken(event.target); +}, true); + +// When @hotwired/turbo handles form submissions, send the CSRF token in a header in addition to a cookie +// The `framework.csrf_protection.check_header` config option needs to be enabled for the header to be checked +document.addEventListener('turbo:submit-start', function (event) { + const h = generateCsrfHeaders(event.detail.formSubmission.formElement); + Object.keys(h).map(function (k) { + event.detail.formSubmission.fetchRequest.headers[k] = h[k]; + }); +}); + +// When @hotwired/turbo handles form submissions, remove the CSRF cookie once a form has been submitted +document.addEventListener('turbo:submit-end', function (event) { + removeCsrfToken(event.detail.formSubmission.formElement); +}); + +export function generateCsrfToken (formElement) { + const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]'); + + if (!csrfField) { + return; + } + + let csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value'); + let csrfToken = csrfField.value; + + if (!csrfCookie && nameCheck.test(csrfToken)) { + csrfField.setAttribute('data-csrf-protection-cookie-value', csrfCookie = csrfToken); + csrfField.defaultValue = csrfToken = btoa(String.fromCharCode.apply(null, (window.crypto || window.msCrypto).getRandomValues(new Uint8Array(18)))); + } + csrfField.dispatchEvent(new Event('change', { bubbles: true })); + + if (csrfCookie && tokenCheck.test(csrfToken)) { + const cookie = csrfCookie + '_' + csrfToken + '=' + csrfCookie + '; path=/; samesite=strict'; + document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie; + } +} + +export function generateCsrfHeaders (formElement) { + const headers = {}; + const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]'); + + if (!csrfField) { + return headers; + } + + const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value'); + + if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) { + headers[csrfCookie] = csrfField.value; + } + + return headers; +} + +export function removeCsrfToken (formElement) { + const csrfField = formElement.querySelector('input[data-controller="csrf-protection"], input[name="_csrf_token"]'); + + if (!csrfField) { + return; + } + + const csrfCookie = csrfField.getAttribute('data-csrf-protection-cookie-value'); + + if (tokenCheck.test(csrfField.value) && nameCheck.test(csrfCookie)) { + const cookie = csrfCookie + '_' + csrfField.value + '=0; path=/; samesite=strict; max-age=0'; + + document.cookie = window.location.protocol === 'https:' ? '__Host-' + cookie + '; secure' : cookie; + } +} + +/* stimulusFetch: 'lazy' */ +export default 'csrf-protection-controller'; diff --git a/assets/controllers/hello_controller.js b/assets/controllers/hello_controller.js new file mode 100644 index 0000000..e847027 --- /dev/null +++ b/assets/controllers/hello_controller.js @@ -0,0 +1,16 @@ +import { Controller } from '@hotwired/stimulus'; + +/* + * This is an example Stimulus controller! + * + * Any element with a data-controller="hello" attribute will cause + * this controller to be executed. The name "hello" comes from the filename: + * hello_controller.js -> "hello" + * + * Delete this file or adapt it for your use! + */ +export default class extends Controller { + connect() { + this.element.textContent = 'Hello Stimulus! Edit me in assets/controllers/hello_controller.js'; + } +} diff --git a/assets/dashboard-charts.js b/assets/dashboard-charts.js new file mode 100644 index 0000000..1e55dbd --- /dev/null +++ b/assets/dashboard-charts.js @@ -0,0 +1,229 @@ +// Bubble chart du dashboard avec option de taille de bulle proportionnelle ou égale + +let bubbleChart = null; // Déclaré en dehors pour garder la référence +function waitForChartAndDrawBubble() { + if (!window.Chart || !window.ChartDataLabels) { + setTimeout(waitForChartAndDrawBubble, 50); + return; + } + const chartCanvas = document.getElementById('bubbleChart'); + const toggle = document.getElementById('toggleBubbleSize'); + + + + + function drawBubbleChart(proportional) { + // Détruire toute instance Chart.js existante sur ce canvas (Chart.js v3+) + const existing = window.Chart.getChart(chartCanvas); + if (existing) { + try { existing.destroy(); } catch (e) { console.warn('Erreur destroy Chart:', e); } + } + if (bubbleChart) { + try { bubbleChart.destroy(); } catch (e) { console.warn('Erreur destroy Chart:', e); } + bubbleChart = null; + } + + // Forcer le canvas à occuper toute la largeur/hauteur du conteneur en pixels + if (chartCanvas && chartCanvas.parentElement) { + const parentRect = chartCanvas.parentElement.getBoundingClientRect(); + console.log('parentRect', parentRect) + + chartCanvas.width = (parentRect.width); + chartCanvas.height = (parentRect.height); + chartCanvas.style.width = parentRect.width + 'px'; + chartCanvas.style.height = parentRect.height + 'px'; + } + + + if(!getBubbleData){ + console.log('pas de getBubbleData') + return ; + } + const bubbleChartData = getBubbleData(proportional); + + if(!bubbleChartData){ + console.log('pas de bubbleChartData') + return ; + } + + // Calcul de la régression linéaire (moindres carrés) + // On ne fait la régression que si on veut, mais l'axe X = fraicheur, Y = complétion + const validPoints = bubbleChartData.filter(d => d.x !== null && d.y !== null); + const n = validPoints.length; + let regressionLine = null, slope = 0, intercept = 0; + if (n >= 2) { + let sumX = 0, sumY = 0, sumXY = 0, sumXX = 0; + validPoints.forEach(d => { + sumX += d.x; + sumY += d.y; + sumXY += d.x * d.y; + sumXX += d.x * d.x; + }); + const meanX = sumX / n; + const meanY = sumY / n; + slope = (sumXY - n * meanX * meanY) / (sumXX - n * meanX * meanX); + intercept = meanY - slope * meanX; + const xMin = Math.min(...validPoints.map(d => d.x)); + const xMax = Math.max(...validPoints.map(d => d.x)); + regressionLine = [ + { x: xMin, y: slope * xMin + intercept }, + { x: xMax, y: slope * xMax + intercept } + ]; + } + window.Chart.register(window.ChartDataLabels); + bubbleChart = new window.Chart(chartCanvas.getContext('2d'), { + type: 'bubble', + data: { + datasets: [ + { + label: 'Villes', + data: bubbleChartData, + backgroundColor: bubbleChartData.map(d => `rgba(94, 255, 121, ${d.completion / 100})`), + borderColor: 'rgb(94, 255, 121)', + datalabels: { + anchor: 'center', + align: 'center', + color: '#000', + display: true, + font: { weight: '400', size : "12px" }, + formatter: (value, context) => { + return context.dataset.data[context.dataIndex].label; + } + } + }, + regressionLine ? { + label: 'Régression linéaire', + type: 'line', + data: regressionLine, + borderColor: 'rgba(95, 168, 0, 0.7)', + borderWidth: 2, + pointRadius: 0, + fill: false, + order: 0, + tension: 0, + datalabels: { display: false } + } : null + ].filter(Boolean) + }, + options: { + plugins: { + datalabels: { + display: false + }, + legend: { display: true }, + tooltip: { + callbacks: { + label: (context) => { + const d = context.raw; + if (context.dataset.type === 'line') { + return `Régression: y = ${slope.toFixed(2)} × x + ${intercept.toFixed(2)}`; + } + return [ + `${d.label}`, + `Fraîcheur moyenne: ${d.freshnessDays ? d.freshnessDays.toLocaleString() + ' jours' : 'N/A'}`, + `Complétion: ${d.y.toFixed(2)}%`, + `Population: ${d.population ? d.population.toLocaleString() : 'N/A'}`, + `Nombre de lieux: ${d.r.toFixed(2)}`, + `Budget: ${d.budget ? d.budget.toLocaleString() + ' €' : 'N/A'}`, + `Budget/habitant: ${d.budgetParHabitant ? d.budgetParHabitant.toFixed(2) + ' €' : 'N/A'}`, + `Budget/lieu: ${d.budgetParLieu ? d.budgetParLieu.toFixed(2) + ' €' : 'N/A'}` + ]; + } + } + } + }, + scales: { + x: { + type: 'linear', + title: { display: true, text: 'Fraîcheur moyenne (jours, plus petit = plus récent)' } + }, + y: { + title: { display: true, text: 'Taux de complétion (%)' }, + min: 0, + max: 100 + } + } + } + }); + // Ajout du clic sur une bulle + chartCanvas.onclick = function(evt) { + const points = bubbleChart.getElementsAtEventForMode(evt, 'nearest', { intersect: true }, true); + if (points.length > 0) { + const firstPoint = points[0]; + const dataIndex = firstPoint.index; + const stat = window.statsDataForBubble[dataIndex]; + if (stat && stat.zone) { + window.location.href = '/admin/stats/' + stat.zone; + } + } + }; + } + + // Initial draw + console.log('[bubble chart] Initialisation avec taille proportionnelle ?', toggle?.checked); + if(drawBubbleChart){ + + drawBubbleChart(toggle && toggle.checked); + // Listener + toggle?.addEventListener('change', function() { + console.log('[bubble chart] Toggle changé, taille proportionnelle ?', toggle?.checked); + drawBubbleChart(toggle?.checked); + }); + } +} + +function getBubbleData(proportional) { + // Générer les données puis trier par rayon décroissant + const data = window.statsDataForBubble?.map(stat => { + const population = parseInt(stat.population, 10); + const placesCount = parseInt(stat.placesCount, 10); + const completion = parseInt(stat.completionPercent, 10); + // Fraîcheur moyenne : âge moyen en jours (plus récent à droite) + let freshnessDays = null; + if (stat.osmDataDateAvg) { + const now = new Date(); + const avgDate = new Date(stat.osmDataDateAvg); + freshnessDays = Math.round((now - avgDate) / (1000 * 60 * 60 * 24)); + } + // Pour l'axe X, on veut que les plus récents soient à droite (donc X = -freshnessDays) + const x = freshnessDays !== null ? -freshnessDays : 0; + // Budget + const budget = stat.budgetAnnuel ? parseFloat(stat.budgetAnnuel) : null; + const budgetParHabitant = (budget && population) ? budget / population : null; + const budgetParLieu = (budget && placesCount) ? budget / placesCount : null; + return { + x: x, + y: completion, + r: proportional ? Math.sqrt(placesCount) * 2 : 12, + label: stat.name, + completion: stat.completionPercent || 0, + zone: stat.zone, + budget, + budgetParHabitant, + budgetParLieu, + population, + placesCount, + freshnessDays + }; + }); + // Trier du plus gros au plus petit rayon + if(data){ + data.sort((a, b) => b.r - a.r); + } + return data; +} +document.addEventListener('DOMContentLoaded', function() { + waitForChartAndDrawBubble(); + + // Forcer deleteMissing=1 sur le formulaire de labourage + const labourerForm = document.getElementById('labourerForm'); + if (labourerForm) { + labourerForm.addEventListener('submit', function(e) { + e.preventDefault(); + const zipCode = document.getElementById('selectedZipCode').value; + if (zipCode) { + window.location.href = '/admin/labourer/' + zipCode + '?deleteMissing=1'; + } + }); + } +}); \ No newline at end of file diff --git a/assets/edit.js b/assets/edit.js new file mode 100644 index 0000000..75bed7e --- /dev/null +++ b/assets/edit.js @@ -0,0 +1,126 @@ + +/** + * mettre à jour la barre de progression + * pour le formulaire de modification + */ +function updateCompletionProgress() { + const inputs = document.querySelectorAll('input[data-important]'); + let filledInputs = 0; + let totalInputs = inputs.length; + let missingFields = []; + + inputs.forEach(input => { + if (input.value.trim() !== '') { + filledInputs++; + } else { + // Get the field label or name for display in the popup + let fieldName = ''; + const label = input.closest('.row')?.querySelector('.form-label, .label-translated'); + if (label) { + fieldName = label.textContent.trim(); + } else { + // If no label found, try to get a meaningful name from the input + const name = input.getAttribute('name'); + if (name) { + // Extract field name from the attribute (e.g., commerce_tag_value__contact:email -> Email) + const parts = name.split('__'); + if (parts.length > 1) { + fieldName = parts[1].replace('commerce_tag_value_', '').replace('contact:', ''); + // Capitalize first letter + fieldName = fieldName.charAt(0).toUpperCase() + fieldName.slice(1); + } else { + fieldName = name; + } + } + } + missingFields.push(fieldName || input.getAttribute('name') || 'Champ inconnu'); + } + }); + + const completionPercentage = (filledInputs / totalInputs) * 100; + const progressBar = document.querySelector('#completion_progress .progress-bar'); + if (progressBar) { + progressBar.style.width = completionPercentage + '%'; + progressBar.setAttribute('aria-valuenow', completionPercentage); + + // Create the completion display with a clickable question mark + const displayElement = document.querySelector('#completion_display'); + + // Format missing fields as an HTML list for better readability + let missingFieldsContent = ''; + if (missingFields.length > 0) { + missingFieldsContent = ''; + } else { + missingFieldsContent = 'Tous les champs importants sont remplis !'; + } + + displayElement.innerHTML = `Votre commerce est complété à ${Math.round(completionPercentage)}% ?`; + + // Initialize the Bootstrap popover + const popoverTrigger = displayElement.querySelector('.missing-fields-info'); + if (popoverTrigger) { + // Add click handler to focus on the first missing field + popoverTrigger.addEventListener('click', function(e) { + e.preventDefault(); // Prevent scrolling to top + + // Find the first missing field + const missingInput = document.querySelector('input[data-important]:not(.good_filled)'); + if (missingInput) { + // Focus on the first missing field + missingInput.focus(); + // Scroll to the field if needed + missingInput.scrollIntoView({ behavior: 'smooth', block: 'center' }); + } + }); + + // Use setTimeout to ensure this runs after the current execution context + setTimeout(() => { + if (typeof bootstrap !== 'undefined' && bootstrap.Popover) { + // Destroy existing popover if any + const existingPopover = bootstrap.Popover.getInstance(popoverTrigger); + if (existingPopover) { + existingPopover.dispose(); + } + // Initialize new popover + new bootstrap.Popover(popoverTrigger, { + html: true, + trigger: 'click', + container: 'body' + }); + } else { + console.warn('Bootstrap popover not available'); + } + }, 0); + } + } +} + +function parseCuisine() { + const cuisineInput = document.querySelector('input[name="commerce_tag_value__cuisine"]'); + + // Récupérer tous les checkboxes de type de cuisine + const cuisineCheckboxes = document.querySelectorAll('input[name="cuisine_type"]'); + + // Ajouter un écouteur d'événement sur chaque checkbox + cuisineCheckboxes.forEach(checkbox => { + checkbox.addEventListener('change', () => { + // Récupérer toutes les checkboxes cochées + const checkedCuisines = Array.from(document.querySelectorAll('input[name="cuisine_type"]:checked')) + .map(input => input.value); + + // Mettre à jour l'input avec les valeurs séparées par des points-virgules + cuisineInput.value = checkedCuisines.join(';'); + }); + }); +} + +window.updateCompletionProgress = updateCompletionProgress; +window.parseCuisine = parseCuisine; diff --git a/assets/josm.js b/assets/josm.js new file mode 100644 index 0000000..81b0c78 --- /dev/null +++ b/assets/josm.js @@ -0,0 +1,77 @@ + + +/** + * Ouvre les éléments sélectionnés dans JOSM + * @param {Object} map - L'instance de la carte MapLibre + * @param {boolean} map_is_loaded - État de chargement de la carte + * @param {Array|Object} osmElements - Élément(s) OSM à ouvrir (peut être un tableau d'objets ou un objet unique) + * @returns {void} + */ +function openInJOSM(map, map_is_loaded, osmElements) { + if (!map_is_loaded) { + alert('Veuillez attendre que la carte soit chargée'); + return; + } + + if (!osmElements || (Array.isArray(osmElements) && osmElements.length === 0)) { + alert('Aucun élément à ouvrir dans JOSM'); + return; + } + + const bounds = map.getBounds(); + + // Convertir en tableau si c'est un seul élément + const elements = Array.isArray(osmElements) ? osmElements : [osmElements]; + + // Séparer les éléments par type + const nodeIds = []; + const wayIds = []; + const relationIds = []; + + elements.forEach(element => { + if (typeof element === 'string') { + // Si c'est juste un ID, on le traite comme un node par défaut + nodeIds.push(element); + } else { + // Sinon on utilise le type spécifié + switch (element.osm_type) { + case 'node': + nodeIds.push(element.osm_id); + break; + case 'way': + wayIds.push(element.osm_id); + break; + case 'relation': + relationIds.push(element.osm_id); + break; + } + } + }); + + // Construire les paramètres de sélection + const selectParams = []; + if (nodeIds.length > 0) selectParams.push(`node${nodeIds.join(',')}`); + if (wayIds.length > 0) selectParams.push(`way${wayIds.join(',')}`); + if (relationIds.length > 0) selectParams.push(`relation${relationIds.join(',')}`); + + // Construire l'URL JOSM avec les paramètres de la boîte englobante + const josmUrl = `http://localhost:8111/load_and_zoom?` + + `left=${bounds.getWest()}&` + + `right=${bounds.getEast()}&` + + `top=${bounds.getNorth()}&` + + `bottom=${bounds.getSouth()}&` + + `select=${selectParams.join(',')}`; + + // Utiliser le bouton caché pour ouvrir JOSM + // Créer un élément temporaire + const tempLink = document.createElement('a'); + tempLink.style.display = 'none'; + document.body.appendChild(tempLink); + tempLink.href = josmUrl; + + console.log('josmUrl', josmUrl); + tempLink.click(); + document.body.removeChild(tempLink); + +} +window.openInJOSM = openInJOSM; \ No newline at end of file diff --git a/assets/js/map-utils.js b/assets/js/map-utils.js new file mode 100644 index 0000000..e69de29 diff --git a/assets/js/table-sortable.js b/assets/js/table-sortable.js new file mode 100644 index 0000000..b1e3251 --- /dev/null +++ b/assets/js/table-sortable.js @@ -0,0 +1,12 @@ +/* + * table-sortable + * version: 2.0.3 + * release date: 4/2/2021 + * (c) Ravi Dhiman https://ravid.dev + * For the full copyright and license information, please view the LICENSE +*/ +// Forcer la présence de jQuery globalement +if (typeof window.jQuery === 'undefined' && typeof window.$ !== 'undefined') { + window.jQuery = window.$; +} +!function(t){var e={};function n(a){if(e[a])return e[a].exports;var i=e[a]={i:a,l:!1,exports:{}};return t[a].call(i.exports,i,i.exports,n),i.l=!0,i.exports}n.m=t,n.c=e,n.d=function(t,e,a){n.o(t,e)||Object.defineProperty(t,e,{enumerable:!0,get:a})},n.r=function(t){"undefined"!==typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},n.t=function(t,e){if(1&e&&(t=n(t)),8&e)return t;if(4&e&&"object"===typeof t&&t&&t.__esModule)return t;var a=Object.create(null);if(n.r(a),Object.defineProperty(a,"default",{enumerable:!0,value:t}),2&e&&"string"!=typeof t)for(var i in t)n.d(a,i,function(e){return t[e]}.bind(null,i));return a},n.n=function(t){var e=t&&t.__esModule?function(){return t.default}:function(){return t};return n.d(e,"a",e),e},n.o=function(t,e){return Object.prototype.hasOwnProperty.call(t,e)},n.p="",n(n.s=1)}([function(t,e){t.exports=jQuery},function(t,e,n){t.exports=n(3)},function(t,e,n){},function(t,e,n){"use strict";n.r(e);var a={};function i(t,e){if(!(t instanceof e))throw new TypeError("Cannot call a class as a function")}function r(t,e){for(var n=0;n2?a-2:0),r=2;rparseFloat(e)?1:-1;if(g(t)){var n=new Date(t),a=new Date(e);return n.getTime()>a.getTime()?1:-1}return p(t)?t>e?1:-1:1}return 0},k=function(t,e){var n;return function(){var a=this,i=arguments;clearTimeout(n),n=window.setTimeout((function(){return t.apply(a,i)}),e)}},C=function(t){return p(t)?t.toLowerCase():String(t)},E=function(t,e){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:[];if(!e&&!h(e))return!1;var a=m(t);c(n)||(n=a);for(var i=0,r=a.length,o=!1,s=C(e);i-1&&u.indexOf(s)>-1){o=!0;break}if(!n.length&&u.indexOf(s)>-1){o=!0;break}i+=1}return o},w=function(t,e){return c(e)&&e[0]<=t&&e[1]>t},D=function(){function t(){i(this,t),this._name="dataset",this.dataset=null,this._cachedData=null,this._datasetLen=0,this._outLen=10,this.sortDirection={ASC:"asc",DESC:"desc"}}return o(t,[{key:"_formatError",value:function(t,e,n){for(var i=arguments.length,r=new Array(i>3?i-3:0),o=3;oe),"get",'"from" cannot be greater than "to"'),t=Math.max(t,0),e=Math.min(e,this._datasetLen),this.dataset.slice(t,e)}},{key:"sort",value:function(t,e){this._hasDataset(),this._formatError(p(t),"sort",'Requires "column" type of string'),this._formatError(p(e),"sort",'Requires "direction" type of string'),this._formatError("asc"===e||"desc"===e,"sort",'"%s" is invalid sort direction. Use "dataset.sortDirection.ASC" or "dataset.sortDirection.DESC".',e);var n=this.top(1)[0];return this._formatError("undefined"!==typeof n[t],"sort",'Column name "%s" does not exist in collection',t),this.sortDirection.ASC===e?this.dataset.sort((function(e,n){return P(e[t],n[t])})):this.dataset.sort((function(e,n){return P(n[t],e[t])})),this.top(this._datasetLen)}},{key:"pushData",value:function(t){c(t)&&Array.prototype.push.apply(this.dataset,t)}},{key:"lookUp",value:function(t,e){if(p(t)||h(t)){var n=JSON.parse(this._cachedData);this.dataset=""===t?n:v(n,(function(n){return E(n,t,e)})),this._datasetLen=this.dataset.length}}}]),t}(),x=function(t,e,n){return{node:t,attrs:e,children:n}},S=function(t){var e=t.node,n=t.attrs;t.children;return function(t,e){if(!e)return t;for(var n=Object.keys(e),a=0;a")),n)},U=function t(e,n,a){if(a||n.empty(),c(e)){for(var i=[],r=0;r\u25bc",desc:"\u25b2"},nextText:"Next",prevText:"Prev",tableWillMount:function(){},tableDidMount:function(){},tableWillUpdate:function(){},tableDidUpdate:function(){},tableWillUnmount:function(){},tableDidUnmount:function(){},onPaginationChange:null},this._styles=null,this._dataset=null,this._table=null,this._thead=null,this._tbody=null,this._isMounted=!1,this._isUpdating=!1,this._sorting={currentCol:"",dir:""},this._pagination={elm:null,currentPage:0,totalPages:1,visiblePageNumbers:5},this._cachedOption=null,this._cachedViewPort=-1,this.setData=function(t,e,a){n.logError(c(t),"setData","expect first argument as array of objects"),n.logError(d(e),"setData","expect second argument as objects"),n._isMounted&&t&&(a?n._dataset.pushData(t):n._dataset.fromCollection(t),e&&(n.options.columns=e),n.refresh())},this.getData=function(){return n._isMounted?n._dataset.top():[]},this.getCurrentPageData=function(){if(n._isMounted){var t=n.options.rowsPerPage,e=n._pagination.currentPage*t,a=e+t;return n._dataset.get(e,a)}return[]},this.refresh=function(t){t?(n.distroy(),n.create()):n._isMounted&&n.updateTable()},this.distroy=function(){n._isMounted&&(n.emitLifeCycles("tableWillUnmount"),n._table.remove(),n._styles&&n._styles.length&&(n._styles.remove(),n._styles=null),n._dataset=null,n._table=null,n._thead=null,n._tbody=null,n._pagination.elm&&n._pagination.elm.remove(),n._pagination={elm:null,currentPage:0,totalPages:0,visiblePageNumbers:5},n._isMounted=!1,n._isUpdating=!1,n._sorting={currentCol:"",dir:""},n._cachedViewPort=-1,n._cachedOption=null,n.emitLifeCycles("tableDidUnmount"))},this.create=function(){n._isMounted||n.init()},this.options=u.a.extend(this._defOptions,e),delete this._defOptions,this._rootElement=u()(this.options.element),this.engine=L(),this.optionDepreciation(),this.init(),this._debounceUpdateTable()}return o(t,[{key:"optionDepreciation",value:function(){var t=this.options;this.logWarn(t.columnsHtml,"columnsHtml","has been deprecated. Use formatHeader()"),this.logWarn(t.processHtml,"processHtml","has been deprecated. Use formatCell()"),this.logWarn(t.dateParsing,"dateParsing","has been deprecated. It is true by default."),this.logWarn(t.generateUniqueIds,"generateUniqueIds","has been deprecated. It is true by default."),this.logWarn(t.showPaginationLabel,"showPaginationLabel","has been deprecated. It is true by default."),this.logWarn(t.paginationLength,"paginationLength","has been deprecated. Use rowsPerPage")}},{key:"logError",value:function(t,e,n){for(var i=arguments.length,r=new Array(i>3?i-3:0),o=3;o1?n-1:0),i=1;i1&&void 0!==arguments[1]?arguments[1]:[],n=this.options.columns;this.logError(e&&c(e),"lookUp","second argument must be array of keys"),e.length||(e=n),this._pagination.currentPage=0,this._dataset.lookUp(t,m(e)),this.debounceUpdateTable()}},{key:"_bindSearchField",value:function(){var t=this,e=this.options.searchField;if(e){var n=u()(e);this.logError(n.length,"searchField",'"%s" is not a valid DOM element or string',n),n.on("input",(function(){var e=u()(this).val();t.lookUp(e)})),this.options.searchField=n}}},{key:"_validateRootElement",value:function(){this.logError(this._rootElement.length,"element",'"%s" is not a valid root element',this._rootElement)}},{key:"_createTable",value:function(){this._table=u()("
").addClass("table gs-table")}},{key:"_initDataset",value:function(){var t=this.options.data;this.logError(c(t),"data","table-sortable only supports collections. Like: [{ key: value }, { key: value }]");var e=new D;e.fromCollection(t),this._dataset=e}},{key:"_validateColumns",value:function(){var t=this.options.columns;this.logError(d(t),"columns","Invalid column type, see docs")}},{key:"sortData",value:function(t){var e=this._sorting,n=e.dir,a=e.currentCol;t!==a&&(n=""),n?n===this._dataset.sortDirection.ASC?n=this._dataset.sortDirection.DESC:n===this._dataset.sortDirection.DESC&&(n=this._dataset.sortDirection.ASC):n=this._dataset.sortDirection.ASC,a=t,this._sorting={dir:n,currentCol:a},this._dataset.sort(a,n),this.updateCellHeader()}},{key:"_addColSorting",value:function(t,e){var n=this,a=this.options.sorting,i=this;return a?(a&&!c(a)&&((t=u()(t)).attr("role","button"),t.addClass("gs-button"),e===this._sorting.currentCol&&this._sorting.dir&&t.append(this.options.sortingIcons[this._sorting.dir]),t.click((function(t){i.sortData(e)}))),c(a)&&b(a,(function(a){e===a&&((t=u()(t)).attr("role","button"),t.addClass("gs-button"),e===n._sorting.currentCol&&n._sorting.dir&&t.append(n.options.sortingIcons[n._sorting.dir]),t.click((function(t){i.sortData(e)})))})),t):t}},{key:"getCurrentPageIndex",value:function(){var t=this._dataset._datasetLen,e=this.options,n=e.pagination,a=e.rowsPerPage,i=this._pagination.currentPage;if(!n)return{from:0};var r=i*a,o=Math.min(r+a,t);return{from:r=Math.min(r,o),to:o}}},{key:"_renderHeader",value:function(t){var e=this;t||(t=u()(''));var n=this.options,a=n.columns,i=n.formatHeader,r=[],o=m(a);b(o,(function(t,n){var o=a[t];f(i)&&(o=i(a[t],t,n)),o=e._addColSorting(u()("").html(o),t);var s=e.engine.createElement("th",{html:o});r.push(s)}));var s=this.engine.createElement("tr",null,r);return this.engine.render(s,t)}},{key:"_renderBody",value:function(t){t||(t=u()(''));var e=this.engine,n=this.options,a=n.columns,i=n.formatCell,r=this.getCurrentPageIndex(),o=r.from,s=r.to,l=[];l=void 0===s?this._dataset.top():this._dataset.get(o,s);var c=[],h=m(a);return b(l,(function(t,n){var a=[];b(h,(function(n){var r;void 0!==t[n]&&(r=f(i)?e.createElement("td",{html:i(t,n)}):e.createElement("td",{html:t[n]}),a.push(r))})),c.push(e.createElement("tr",null,a))})),e.render(c,t)}},{key:"_createCells",value:function(){return{thead:this._renderHeader(),tbody:this._renderBody()}}},{key:"onPaginationBtnClick",value:function(t,e){var n=this,a=this._pagination,i=a.totalPages,r=a.currentPage,o=this.options.onPaginationChange;"up"===t?r=0&&(r-=1);if(f(o)){var s=isNaN(e)?r:e;o.apply(this,[s,function(t){return n.setPage(t)}])}else this._pagination.currentPage=void 0!==e?e:r,this.updateTable()}},{key:"renderPagination",value:function(t){var e=this,n=this.engine,a=this.options,i=a.pagination,r=a.paginationContainer,o=a.prevText,s=a.nextText,l=this._pagination,c=l.currentPage,h=l.totalPages,d=l.visiblePageNumbers,f=Math.min(h,d),p=0,g=Math.min(h,p+f);if(c>f/2&&ch-f/2&&(p=h-f,g=h),t||(t=u()('
'),u()(r).length?u()(r).append(t):this._table.after(t)),!i)return t;var _=[],m=n.createElement("button",{className:"btn btn-default",html:o,disabled:0===c,onClick:function(){return e.onPaginationBtnClick("down")}});_.push(m);var b=n.createElement("button",{className:"btn btn-default",disabled:!0,text:"..."});c>f/2&&_.push(b);for(var v=p;v=h-1,onClick:function(){return e.onPaginationBtnClick("up")}});_.push(P),t.append(_);var k=this.getCurrentPageIndex(),C=k.from,E=k.to,w=n.createElement("span",{text:"Showing ".concat(Math.min(E,C+1)," to ").concat(E," of ").concat(this._dataset._datasetLen," rows")}),D=n.createElement("div",{className:"col-md-6"},w),x=n.createElement("div",{className:"btn-group d-flex justify-content-end"},_),S=n.createElement("div",{className:"col-md-6"},x),U=n.createElement("div",{className:"row"},[D,S]);return n.render(U,t)}},{key:"createPagination",value:function(){var t=this.options,e=t.rowsPerPage,n=t.pagination,a=t.totalPages;if(!n)return!1;this.logError(e&&h(e),"rowsPerPage","should be a number greater than zero."),this.logError(h(a),"totalPages","should be a number greater than zero.");var i=a||Math.ceil(this._dataset._datasetLen/e);0>=i&&(i=1),this._pagination.totalPages=i,this._pagination.elm?this.renderPagination(this._pagination.elm):this._pagination.elm=this.renderPagination()}},{key:"_generateTable",value:function(t,e){this._table.html(""),this._table.append(t),this._table.append(e),this._thead=t,this._tbody=e}},{key:"_renderTable",value:function(){if(this._rootElement.is("table"))this._rootElement.html(this._table.html());else{var t=this.engine.createElement("div",{className:"gs-table-container",append:this._table});this._rootElement=this.engine.render(t,this._rootElement)}}},{key:"_initStyles",value:function(){if(!this.options.responsive){var t=u()("");t.attr("id","gs-table"),t.html(".gs-table-container .table{table-layout:fixed}@media(max-width:767px){.gs-table-container{overflow:auto;max-width:100%}}"),u()("head").append(t),this._styles=t}}},{key:"init",value:function(){this.emitLifeCycles("tableWillMount"),this._validateRootElement(),this._initDataset(),this._createTable(),this._validateColumns();var t=this._createCells(),e=t.thead,n=t.tbody;this._generateTable(e,n),this._renderTable(),this.createPagination(),this._bindSearchField(),this._initStyles(),this._isMounted=!0,this.emitLifeCycles("tableDidMount"),-1===this._cachedViewPort&&this.resizeSideEffect()}},{key:"_debounceUpdateTable",value:function(){this.debounceUpdateTable=k(this.updateTable,400)}},{key:"updateTable",value:function(){this._isUpdating||(this.emitLifeCycles("tableWillUpdate"),this._isUpdating=!0,this._renderHeader(this._thead),this._renderBody(this._tbody),this.createPagination(),this._isUpdating=!1,this.emitLifeCycles("tableDidUpdate"))}},{key:"updateCellHeader",value:function(){this._isUpdating||(this._isUpdating=!0,this.emitLifeCycles("tableWillUpdate"),this._renderHeader(this._thead),this._renderBody(this._tbody),this._isUpdating=!1,this.emitLifeCycles("tableDidUpdate"))}},{key:"resizeSideEffect",value:function(){var t=k(this.makeResponsive,500);window.addEventListener("resize",t.bind(this)),this.makeResponsive()}},{key:"makeResponsive",value:function(){var t,e=this.options.responsive,n=window.innerWidth,a=_(m(e),"desc");if(this.logError(d(e),"responsive",'Invalid type of responsive option provided: "%s"',e),b(a,(function(e){parseInt(e,10)>n&&(t=e)})),this._cachedViewPort!==t){this._cachedViewPort=t;var i=e[t];d(i)?(this._cachedOption||(this._cachedOption=u.a.extend({},this.options)),this.options=u.a.extend(this.options,i),this.refresh()):this._cachedOption&&(this.options=u.a.extend({},this._cachedOption),this._cachedOption=null,this._cachedViewPort=-1,this.refresh())}}}]),t}());window.Pret=L(),window.TableSortable=O,window.DataSet=D,(s=jQuery).fn.tableSortable=function(t){return t.element=s(this),new window.TableSortable(t)};e.default=O}]); \ No newline at end of file diff --git a/assets/js/table-sortable.min.js b/assets/js/table-sortable.min.js new file mode 100644 index 0000000..e69de29 diff --git a/assets/opening_hours.js b/assets/opening_hours.js new file mode 100644 index 0000000..54a394a --- /dev/null +++ b/assets/opening_hours.js @@ -0,0 +1,683 @@ +/** + * Gestion du formulaire d'horaires d'ouverture + * + */ +const openingHoursFormManager = { + defaultOpeningHours: '', + inputSelector: '', + init: function (inputSelector = 'input[name="custom__opening_hours"]') { + // Rechercher l'élément par son attribut name plutôt que par son id + this.setInputSelector(inputSelector); + const openingHoursInput = document.querySelector(inputSelector); + if (!openingHoursInput) { + console.warn('Élément ', inputSelector, ' non trouvé'); + return; + } + this.defaultOpeningHours = openingHoursInput.value; + + // Créer la div de rendu si elle n'existe pas + let renderDiv = document.getElementById('opening_hours_render'); + if (!renderDiv) { + renderDiv = document.createElement('div'); + renderDiv.id = 'opening_hours_render'; + renderDiv.classList.add('mt-4'); + openingHoursInput.parentNode.insertBefore(renderDiv, openingHoursInput.nextSibling); + } + + this.makeForm(inputSelector); + + if (this.defaultOpeningHours !== '') { + this.parseOpeningHoursValue(inputSelector); + } + + // Ajouter un écouteur d'événement keyup sur l'input des horaires + openingHoursInput.addEventListener('keyup', () => { + this.defaultOpeningHours = openingHoursInput.value; + this.parseOpeningHoursValue(inputSelector); + }); + }, + setInputSelector: function (inputSelector) { + this.inputSelector = inputSelector; + }, + /** + * convertir les checkboxes et inputs en horaires OSM dans l'input de référence + * @param {string} inputSelector + */ + parseOpeningHoursValue: function (inputSelector = 'input[name="custom__opening_hours"]') { + // Analyser la chaîne d'horaires d'ouverture + const parsedOpeningHours = []; + + // Masquer toutes les plages horaires par défaut + const allDayContainers = document.querySelectorAll('.jour-container'); + allDayContainers.forEach(container => { + const checkbox = container.querySelector('input[type="checkbox"]'); + const horairesContainer = container.querySelector('.horaires-container'); + checkbox.checked = false; + horairesContainer.classList.add('d-none'); + }); + + if (this.defaultOpeningHours) { + // Diviser les différentes règles (séparées par des points-virgules) + const rules = this.defaultOpeningHours.split(';').map(r => r.trim()); + + rules.forEach(rule => { + // Extraire les jours et les heures + const parts = rule.split(' ').filter(Boolean); + const days = parts[0]; + const hours = parts.slice(1).join(' '); + + // Convertir les jours en français + const daysMap = { + 'Mo': 'lundi', + 'Tu': 'mardi', + 'We': 'mercredi', + 'Th': 'jeudi', + 'Fr': 'vendredi', + 'Sa': 'samedi', + 'Su': 'dimanche' + }; + + // Gérer les plages de jours (ex: Mo-Fr) + if (days.includes('-')) { + const [start, end] = days.split('-'); + const startIndex = Object.keys(daysMap).indexOf(start); + const endIndex = Object.keys(daysMap).indexOf(end); + + const dayRange = []; + for (let i = startIndex; i <= endIndex; i++) { + const day = Object.keys(daysMap)[i]; + dayRange.push(day); + // Cocher la case du jour + const checkbox = document.querySelector(`#jour-${daysMap[day]}`); + if (checkbox) { + checkbox.checked = true; + const horairesContainer = checkbox.closest('.jour-container').querySelector('.horaires-container'); + horairesContainer.classList.remove('d-none'); + + // Gérer le cas "fermé" + if (hours === 'off') { + const fermeCheckbox = horairesContainer.querySelector(`input[name="${daysMap[day]}-ferme"]`); + if (fermeCheckbox) { + fermeCheckbox.checked = true; + // Décocher les plages horaires + const plageInputs = horairesContainer.querySelectorAll('.time-range input[type="checkbox"]'); + plageInputs.forEach(plageInput => { + plageInput.checked = false; + plageInput.dispatchEvent(new Event('change')); + }); + } + } else { + // Décocher la deuxième plage si elle n'est pas présente dans l'input + if (hours && !hours.includes(',')) { + const plage2Checkbox = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage2-active"]`); + if (plage2Checkbox) { + plage2Checkbox.checked = false; + } + } + + // Remplir la première plage horaire si spécifiée + if (hours) { + const [startTime, endTime] = hours.split('-'); + if (startTime && endTime) { + const [startHour, startMinute] = startTime.split(':'); + const [endHour, endMinute] = endTime.split(':'); + + const startHourInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-start-hour"]`); + const startMinuteInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-start-minute"]`); + const endHourInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-end-hour"]`); + const endMinuteInput = horairesContainer.querySelector(`input[name="${daysMap[day]}-plage1-end-minute"]`); + + if (startHourInput) startHourInput.value = startHour; + if (startMinuteInput) startMinuteInput.value = startMinute; + if (endHourInput) endHourInput.value = endHour; + if (endMinuteInput) endMinuteInput.value = endMinute; + } + } + } + } + } + parsedOpeningHours.push({ + days: dayRange, + hours: hours + }); + } else { + // Jour unique + const day = daysMap[days]; + const checkbox = document.querySelector(`#jour-${day}`); + if (checkbox) { + checkbox.checked = true; + const horairesContainer = checkbox.closest('.jour-container').querySelector('.horaires-container'); + horairesContainer.classList.remove('d-none'); + + // Gérer le cas "fermé" + if (hours === 'off') { + const fermeCheckbox = horairesContainer.querySelector(`input[name="${day}-ferme"]`); + if (fermeCheckbox) { + fermeCheckbox.checked = true; + // Décocher les plages horaires + const plageInputs = horairesContainer.querySelectorAll('.time-range input[type="checkbox"]'); + plageInputs.forEach(plageInput => { + plageInput.checked = false; + plageInput.dispatchEvent(new Event('change')); + }); + } + } else { + // Décocher la deuxième plage si elle n'est pas présente dans l'input + if (hours && !hours.includes(',')) { + const plage2Checkbox = horairesContainer.querySelector(`input[name="${day}-plage2-active"]`); + if (plage2Checkbox) { + plage2Checkbox.checked = false; + } + } + + // Remplir la première plage horaire si spécifiée + if (hours) { + const [startTime, endTime] = hours.split('-'); + if (startTime && endTime) { + const [startHour, startMinute] = startTime.split(':'); + const [endHour, endMinute] = endTime.split(':'); + + const startHourInput = horairesContainer.querySelector(`input[name="${day}-plage1-start-hour"]`); + const startMinuteInput = horairesContainer.querySelector(`input[name="${day}-plage1-start-minute"]`); + const endHourInput = horairesContainer.querySelector(`input[name="${day}-plage1-end-hour"]`); + const endMinuteInput = horairesContainer.querySelector(`input[name="${day}-plage1-end-minute"]`); + + if (startHourInput) startHourInput.value = startHour; + if (startMinuteInput) startMinuteInput.value = startMinute; + if (endHourInput) endHourInput.value = endHour; + if (endMinuteInput) endMinuteInput.value = endMinute; + } + } + } + } + parsedOpeningHours.push({ + days: [days], + hours: hours + }); + } + }); + } + + this.renderOpeningHours(parsedOpeningHours); + console.log(parsedOpeningHours); + }, + makeForm: function (inputSelector = 'input[name="custom__opening_hours"]') { + const customOpeningHours = document.querySelector(inputSelector); + console.log('makeForm customOpeningHours', customOpeningHours); + + if (customOpeningHours) { + // Créer un conteneur flex pour aligner l'input et le formulaire + const container = document.createElement('div'); + container.classList.add('d-flex', 'flex-column', 'flex-md-row', 'align-items-start', 'gap-3', 'w-100'); + + // Créer le formulaire + const form = document.createElement('form'); + form.id = 'app_public_opening_hours'; + form.classList.add('mt-3', 'flex-grow-1'); + + // Créer les cases à cocher pour chaque jour + const jours = ['Lundi', 'Mardi', 'Mercredi', 'Jeudi', 'Vendredi', 'Samedi', 'Dimanche']; + const joursDiv = document.createElement('div'); + joursDiv.classList.add('jours-ouverture', 'mb-4', 'row', 'mx-4'); + + jours.forEach(jour => { + const jourContainer = document.createElement('div'); + jourContainer.classList.add('jour-container', 'col-12'); + + // Checkbox pour le jour + const divCheck = document.createElement('div'); + divCheck.classList.add('form-check', 'mb-2'); + + const input = document.createElement('input'); + input.type = 'checkbox'; + input.id = `jour-${jour.toLowerCase()}`; + input.name = `jour-${jour.toLowerCase()}`; + input.classList.add('form-check-input'); + + const label = document.createElement('label'); + label.htmlFor = `jour-${jour.toLowerCase()}`; + label.classList.add('form-check-label'); + label.textContent = jour; + + divCheck.appendChild(input); + divCheck.appendChild(label); + jourContainer.appendChild(divCheck); + + // Conteneur pour les plages horaires + const horairesContainer = document.createElement('div'); + horairesContainer.classList.add('horaires-container', 'ml-2', 'd-none', 'row'); + + // Option "fermé" + const fermeContainer = document.createElement('div'); + fermeContainer.classList.add('col-12', 'mb-2'); + const fermeCheck = document.createElement('div'); + fermeCheck.classList.add('form-check'); + const fermeInput = document.createElement('input'); + fermeInput.type = 'checkbox'; + fermeInput.id = `${jour.toLowerCase()}-ferme`; + fermeInput.name = `${jour.toLowerCase()}-ferme`; + fermeInput.classList.add('form-check-input'); + const fermeLabel = document.createElement('label'); + fermeLabel.htmlFor = `${jour.toLowerCase()}-ferme`; + fermeLabel.classList.add('form-check-label'); + fermeLabel.textContent = 'Fermé'; + fermeCheck.appendChild(fermeInput); + fermeCheck.appendChild(fermeLabel); + fermeContainer.appendChild(fermeCheck); + horairesContainer.appendChild(fermeContainer); + + // Première plage horaire + const plage1 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage1`); + horairesContainer.appendChild(plage1); + + // Deuxième plage horaire + const plage2 = this.createTimeRangeInputs(`${jour.toLowerCase()}-plage2`); + horairesContainer.appendChild(plage2); + + jourContainer.appendChild(horairesContainer); + joursDiv.appendChild(jourContainer); + + // Ajouter l'événement pour afficher/masquer les plages horaires + input.addEventListener('change', (e) => { + horairesContainer.classList.toggle('d-none', !e.target.checked); + this.convertToOSMOpeningHours(inputSelector); + }); + + // Ajouter l'événement pour gérer l'option "fermé" + fermeInput.addEventListener('change', (e) => { + const plageInputs = horairesContainer.querySelectorAll('.time-range input[type="checkbox"]'); + plageInputs.forEach(plageInput => { + plageInput.checked = !e.target.checked; + plageInput.dispatchEvent(new Event('change')); + }); + this.convertToOSMOpeningHours(inputSelector); + }); + }); + + form.appendChild(joursDiv); + + // Ajouter le formulaire au conteneur + container.appendChild(form); + + // Insérer le conteneur après l'input original + const parent = customOpeningHours.parentNode; + if (parent) { + parent.insertBefore(container, customOpeningHours.nextSibling); + } + + // Ajouter un debounce pour limiter les appels lors des modifications + const debounce = (func, wait) => { + let timeout; + return function executedFunction(...args) { + const later = () => { + clearTimeout(timeout); + func(...args); + }; + clearTimeout(timeout); + timeout = setTimeout(later, wait); + }; + }; + + // Appliquer le debounce à la fonction de conversion + const debouncedConvert = debounce(() => { + this.convertToOSMOpeningHours(); + }, 300); + + // Ajouter les listeners sur tous les inputs + const allInputs = form.querySelectorAll('input'); + allInputs.forEach(input => { + input.addEventListener('change', debouncedConvert); + input.addEventListener('input', debouncedConvert); + }); + } else { + console.log('pas d input opening hours détecté') + } + }, + + createTimeRangeInputs: function (prefix) { + const container = document.createElement('div'); + container.classList.add('time-range', 'mb-2', 'col-12', 'col-md-6'); + + // Case à cocher pour activer la plage + const checkboxContainer = document.createElement('div'); + checkboxContainer.classList.add('form-check', 'mb-2'); + + const checkbox = document.createElement('input'); + checkbox.type = 'checkbox'; + checkbox.id = `${prefix}-active`; + checkbox.name = `${prefix}-active`; + checkbox.classList.add('form-check-input'); + checkbox.checked = true; + + const checkboxLabel = document.createElement('label'); + checkboxLabel.htmlFor = `${prefix}-active`; + checkboxLabel.classList.add('form-check-label'); + checkboxLabel.textContent = ''; + + checkboxContainer.appendChild(checkbox); + checkboxContainer.appendChild(checkboxLabel); + container.appendChild(checkboxContainer); + + // Conteneur pour les inputs d'horaires + const timeContainer = document.createElement('div'); + timeContainer.classList.add('ms-4', 'row', 'g-2'); + + // Heure de début + const startContainer = document.createElement('div'); + startContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2', 'start-hour'); + + const startHour = document.createElement('input'); + startHour.type = 'number'; + startHour.min = '0'; + startHour.max = '23'; + startHour.classList.add('form-control', 'form-control-sm'); + startHour.style.width = '60px'; + startHour.placeholder = 'HH'; + startHour.name = `${prefix}-start-hour`; + // Définir les horaires par défaut selon la plage + startHour.value = prefix.includes('plage1') ? '08' : '14'; + + const startMinute = document.createElement('input'); + startMinute.type = 'number'; + startMinute.min = '0'; + startMinute.max = '59'; + startMinute.classList.add('form-control', 'form-control-sm'); + startMinute.style.width = '60px'; + startMinute.placeholder = 'MM'; + startMinute.name = `${prefix}-start-minute`; + startMinute.value = '00'; + + // Heure de fin + const endContainer = document.createElement('div'); + endContainer.classList.add('col-6', 'd-flex', 'align-items-center', 'gap-2', 'end-hour'); + + const endHour = document.createElement('input'); + endHour.type = 'number'; + endHour.min = '0'; + endHour.max = '23'; + endHour.classList.add('form-control', 'form-control-sm'); + endHour.style.width = '60px'; + endHour.placeholder = 'HH'; + endHour.name = `${prefix}-end-hour`; + // Définir les horaires par défaut selon la plage + endHour.value = prefix.includes('plage1') ? '12' : '18'; + + const endMinute = document.createElement('input'); + endMinute.type = 'number'; + endMinute.min = '0'; + endMinute.max = '59'; + endMinute.classList.add('form-control', 'form-control-sm'); + endMinute.style.width = '60px'; + endMinute.placeholder = 'MM'; + endMinute.name = `${prefix}-end-minute`; + endMinute.value = '00'; + + // Créer le texte avec les horaires + const timeText = document.createElement('div'); + timeText.classList.add('d-flex', 'align-items-center', 'gap-2', 'flex-wrap'); + + // Texte de début + const startText = document.createElement('span'); + startText.textContent = 'de'; + timeText.appendChild(startText); + timeText.appendChild(startHour); + timeText.appendChild(document.createTextNode(':')); + timeText.appendChild(startMinute); + + // Texte du milieu + const middleText = document.createElement('span'); + middleText.textContent = 'à'; + timeText.appendChild(middleText); + + // Texte de fin + timeText.appendChild(endHour); + timeText.appendChild(document.createTextNode(':')); + timeText.appendChild(endMinute); + + timeContainer.appendChild(timeText); + container.appendChild(timeContainer); + + // Fonction pour mettre à jour le style des inputs + const updateInputsStyle = (isActive) => { + const inputs = timeContainer.querySelectorAll('input'); + inputs.forEach(input => { + if (isActive) { + input.classList.remove('bg-light', 'text-muted'); + input.disabled = false; + } else { + input.classList.add('bg-light', 'text-muted'); + input.disabled = true; + } + }); + }; + + // Ajouter l'événement sur la checkbox + checkbox.addEventListener('change', (e) => { + updateInputsStyle(e.target.checked); + }); + + // Appliquer le style initial + updateInputsStyle(checkbox.checked); + + return container; + }, + + convertToOSMOpeningHours: function (inputSelector = 'input[name="custom__opening_hours"]') { + const jours = { + 'Lundi': 'Mo', + 'Mardi': 'Tu', + 'Mercredi': 'We', + 'Jeudi': 'Th', + 'Vendredi': 'Fr', + 'Samedi': 'Sa', + 'Dimanche': 'Su' + }; + + let joursSelectionnes = []; + let horairesParJour = {}; + + // Parcourir les checkboxes des jours + Object.keys(jours).forEach(jour => { + const checkbox = document.getElementById(`jour-${jour.toLowerCase()}`); + if (checkbox && checkbox.checked) { + joursSelectionnes.push(jours[jour]); + + // Vérifier si le jour est marqué comme fermé + const fermeCheckbox = document.getElementById(`${jour.toLowerCase()}-ferme`); + if (fermeCheckbox && fermeCheckbox.checked) { + horairesParJour[jours[jour]] = 'off'; + } else { + // Récupérer les horaires pour ce jour + const prefix = jour.toLowerCase(); + const plage1 = this.getTimeRange(`${prefix}-plage1`); + const plage2 = this.getTimeRange(`${prefix}-plage2`); + + let horaires = []; + if (plage1) horaires.push(plage1); + if (plage2) horaires.push(plage2); + + if (horaires.length > 0) { + horairesParJour[jours[jour]] = horaires.join(','); + } + } + } + }); + + // Optimiser les plages horaires identiques consécutives + let optimizedRules = []; + let currentRule = null; + let currentDays = []; + let currentHours = null; + + joursSelectionnes.forEach((jour, index) => { + const hours = horairesParJour[jour]; + + if (currentHours === null) { + // Première règle + currentHours = hours; + currentDays = [jour]; + } else if (hours === currentHours) { + // Mêmes horaires que la règle en cours + currentDays.push(jour); + } else { + // Horaires différents, on finalise la règle en cours + if (currentDays.length > 0) { + optimizedRules.push({ + days: currentDays, + hours: currentHours + }); + } + // On commence une nouvelle règle + currentDays = [jour]; + currentHours = hours; + } + + // Si c'est le dernier jour, on finalise la règle en cours + if (index === joursSelectionnes.length - 1 && currentDays.length > 0) { + optimizedRules.push({ + days: currentDays, + hours: currentHours + }); + } + }); + + // Construire la chaîne au format OSM + let osmFormat = optimizedRules.map(rule => { + const days = rule.days.length > 1 ? `${rule.days[0]}-${rule.days[rule.days.length - 1]}` : rule.days[0]; + return rule.hours ? `${days} ${rule.hours}` : days; + }).join('; '); + + // Mettre à jour l'input custom__opening_hours + const customOpeningHours = document.querySelector(inputSelector); + if (customOpeningHours) { + customOpeningHours.value = osmFormat; + } + + // Mettre à jour le rendu visuel + this.renderOpeningHours(optimizedRules); + }, + + renderOpeningHours: function (rules) { + const container = document.getElementById('opening_hours_render'); + console.log('renderOpeningHours', rules); + if (!container) return; + + // Vider le conteneur + container.innerHTML = ''; + + // Créer le style pour les sections d'ouverture + const style = document.createElement('style'); + style.textContent = ` + .opening-hours-day { + background-color: #f8f9fa; + border-radius: 4px; + margin-bottom: 8px; + padding: 8px; + position: relative; + height: 40px; + } + .opening-hours-time { + background-color: #d4edda; + border-radius: 4px; + position: absolute; + height: 24px; + top: 8px; + } + .opening-hours-label { + position: absolute; + left: 8px; + top: 50%; + transform: translateY(-50%); + z-index: 1; + } + .opening-hours-closed { + background-color: #f8d7da; + } + `; + document.head.appendChild(style); + + // Mapping des jours OSM vers français + const joursMap = { + 'Mo': 'Lundi', + 'Tu': 'Mardi', + 'We': 'Mercredi', + 'Th': 'Jeudi', + 'Fr': 'Vendredi', + 'Sa': 'Samedi', + 'Su': 'Dimanche' + }; + + // Créer les lignes pour chaque jour + Object.entries(joursMap).forEach(([osmDay, frenchDay]) => { + const dayDiv = document.createElement('div'); + dayDiv.classList.add('opening-hours-day'); + + // Ajouter le label du jour + const label = document.createElement('span'); + label.classList.add('opening-hours-label'); + label.textContent = frenchDay; + dayDiv.appendChild(label); + + // Trouver les horaires pour ce jour + const rule = rules.find(r => r.days.includes(osmDay)); + if (rule) { + if (rule.hours === 'off') { + // Jour fermé + dayDiv.classList.add('opening-hours-closed'); + } else if (rule.hours) { + // Plages horaires spécifiques + const timeRanges = rule.hours.split(','); + timeRanges.forEach((timeRange, index) => { + const [start, end] = timeRange.split('-'); + const [startHour, startMinute] = start.split(':'); + const [endHour, endMinute] = end.split(':'); + + // Calculer la position et la largeur + const startMinutes = parseInt(startHour) * 60 + parseInt(startMinute); + const endMinutes = parseInt(endHour) * 60 + parseInt(endMinute); + const totalMinutes = 24 * 60; + + const left = (startMinutes / totalMinutes) * 100; + const width = ((endMinutes - startMinutes) / totalMinutes) * 100; + + const timeDiv = document.createElement('div'); + timeDiv.classList.add('opening-hours-time'); + timeDiv.style.left = `${left}%`; + timeDiv.style.width = `${width}%`; + timeDiv.title = `${start}-${end}`; + + dayDiv.appendChild(timeDiv); + }); + } else { + // Toute la journée + const timeDiv = document.createElement('div'); + timeDiv.classList.add('opening-hours-time'); + timeDiv.style.left = '0%'; + timeDiv.style.width = '100%'; + timeDiv.title = 'Toute la journée'; + dayDiv.appendChild(timeDiv); + } + } + + container.appendChild(dayDiv); + }); + }, + + getTimeRange: function (prefix) { + const isActive = document.querySelector(`input[name="${prefix}-active"]`).checked; + if (!isActive) return null; + + const startHour = document.querySelector(`input[name="${prefix}-start-hour"]`).value; + const startMinute = document.querySelector(`input[name="${prefix}-start-minute"]`).value; + const endHour = document.querySelector(`input[name="${prefix}-end-hour"]`).value; + const endMinute = document.querySelector(`input[name="${prefix}-end-minute"]`).value; + + if (startHour && startMinute && endHour && endMinute) { + const start = `${startHour.padStart(2, '0')}:${startMinute.padStart(2, '0')}`; + const end = `${endHour.padStart(2, '0')}:${endMinute.padStart(2, '0')}`; + return `${start}-${end}`; + } + return null; + } +} +window.openingHoursFormManager = openingHoursFormManager; \ No newline at end of file diff --git a/assets/stats-charts.js b/assets/stats-charts.js new file mode 100644 index 0000000..6034f23 --- /dev/null +++ b/assets/stats-charts.js @@ -0,0 +1,44 @@ +// Affichage du graphique de fréquence des mises à jour par trimestre sur la page stats d'une ville + +document.addEventListener('DOMContentLoaded', function() { + function drawModificationsByQuarterChart() { + if (!window.Chart) { + setTimeout(drawModificationsByQuarterChart, 50); + return; + } + if (typeof window.modificationsByQuarter === 'undefined') return; + const modifData = window.modificationsByQuarter; + const modifLabels = Object.keys(modifData); + const modifCounts = Object.values(modifData); + const modifCanvas = document.getElementById('modificationsByQuarterChart'); + if (modifCanvas && modifLabels.length > 0) { + new window.Chart(modifCanvas.getContext('2d'), { + type: 'bar', + data: { + labels: modifLabels, + datasets: [{ + label: 'Nombre de lieux modifiés', + data: modifCounts, + backgroundColor: 'rgba(54, 162, 235, 0.7)', + borderColor: 'rgba(54, 162, 235, 1)', + borderWidth: 1 + }] + }, + options: { + responsive: true, + plugins: { + legend: { display: false }, + title: { display: true, text: 'Fréquence des mises à jour par trimestre' } + }, + scales: { + y: { beginAtZero: true, title: { display: true, text: 'Nombre de lieux' } }, + x: { title: { display: true, text: 'Trimestre' } } + } + } + }); + } else if (modifCanvas) { + modifCanvas.parentNode.innerHTML = '
Aucune donnée de modification disponible pour cette ville.
'; + } + } + drawModificationsByQuarterChart(); +}); \ No newline at end of file diff --git a/assets/styles/app.css b/assets/styles/app.css new file mode 100644 index 0000000..854d95a --- /dev/null +++ b/assets/styles/app.css @@ -0,0 +1,192 @@ +body { + background-color: rgb(236, 236, 236); + transition: background-color ease 0.5s; +} + +.body-landing .container { + background-color: white; + border-radius: 10px; + padding: 20px; +} + +.main-footer { + padding-bottom: 20rem; + background-color: #dfe5eb; + +} + +#qrcode { + margin-bottom: 8rem; +} + +input[data-important] { + border-color: #7a8fbb; + border-left-width: 5px; +} + +input[data-important]:before { + content: ">" !important; +} + +.filled, .good_filled { + border-color: rgba(0, 255, 0, 0.8) !important; + color: #082b0a !important; +} + +.filled:hover, .good_filled:hover { + background-color: #d9ffd1 !important; +} + +.no-name { + color: #df5a0d; +} + +table { + max-height: 100vh; + max-width: 100vw; +} + +table.js-sort-table th { + cursor: pointer; +} + +table.js-sort-table th:hover { + background-color: #f0f0f0; +} + +table.js-sort-table th:active { + background-color: #e0e0e0; +} + +/*// formulaire de temps d'ouverture */ +.form-check-input { + margin-right: 2rem; +} + +.jour-container { + border: solid #dedede 1px; +} + +#maploader { + position: relative; + top: 200px; + left: 50%; + z-index: 100; +} + +.maplibregl-popup-content { + overflow: auto; + min-width: 300px; + max-height: 11rem !important; +} + +.maplibregl-popup-content strong { + min-width: 10rem; +} + +.maplibregl-popup-content table { + width: 100%; + max-height: 300px; + overflow: auto; +} + +.maplibregl-popup-content h1, +.maplibregl-popup-content h2, +.maplibregl-popup-contenth3 { + font-size: 1rem; +} + +.card { + overflow: auto; +} + +#attribution { + font-size: 0.6rem; +} + +#restaurant .form-check-label { + margin-top: 0; + display: block; + cursor: pointer; +} + +#restaurant .form-check-label:hover { + background-color: #f0f0f0; + color: #1e40c6; +} + +#advanced_tags { + border-left: solid 3px #ccc; + padding-left: 2rem; +} + + +.start-hour { + margin-left: -1rem; +} + +.end-hour { + margin-left: -1rem; +} + +.good_filled { + border-color: green; +} + +.hidden { + display: none; +} + +input[type="checkbox"] { + width: 20px; + height: 20px; +} + +.is-invalid { + border: 1px solid red; +} + +.is-invalid #validation_messages { + color: red; +} + +img { + max-width: 100%; + max-height: 400px; +} + + +#completionHistoryChart { + min-height: 500px; +} + +@media (max-width: 768px) { + .form-label { + margin-bottom: 0.5rem; + } + + .mb-3 { + margin-bottom: 1rem !important; + } +} + +table tbody { + max-height: 700px; + overflow: auto; +} + +#table_container, .table-container, #table-container { + max-height: 700px; + overflow: auto; + display: block; + border: solid 3px rgb(255, 255, 255); +} + +#citySuggestions { + z-index: 10; +} + +body .card:hover { + transform: none !important; + box-shadow: none !important; +} \ No newline at end of file diff --git a/assets/table-map-toggles.js b/assets/table-map-toggles.js new file mode 100644 index 0000000..5f4fcf4 --- /dev/null +++ b/assets/table-map-toggles.js @@ -0,0 +1,19 @@ +// Gestion du tri des tableaux +// import Tablesort from 'tablesort'; + +document.addEventListener('DOMContentLoaded', () => { + // Gestion du toggle gouttes/ronds sur la carte + const toggle = document.getElementById('toggleMarkers'); + if (toggle && window.updateMarkers) { + toggle.addEventListener('change', (e) => { + window.updateMarkers(e.target.value); + }); + } +}); + +// Exposer une fonction pour (ré)appliquer le tri si besoin +export function applyTableSort() { + document.querySelectorAll('.js-sort-table').forEach(table => { + new window.Tablesort(table); + }); +} \ No newline at end of file diff --git a/assets/utils.js b/assets/utils.js new file mode 100644 index 0000000..1abee1e --- /dev/null +++ b/assets/utils.js @@ -0,0 +1,384 @@ +function colorHeadingTable() { + const headers = document.querySelectorAll('th'); + headers.forEach(header => { + const text = header.textContent; + const match = text.match(/\((\d+)\s*\/\s*(\d+)\)/); + if (match) { + const [_, completed, total] = match; + const ratio = completed / total; + const alpha = ratio.toFixed(2); + header.style.backgroundColor = `rgba(154, 205, 50, ${alpha})`; + } + }); +} + +function check_validity(e) { + list_inputs_good_to_fill = [ + 'input[name="commerce_tag_value__contact:email"]', + 'input[name="commerce_tag_value__contact:phone"]', + 'input[name="commerce_tag_value__contact:website"]', + 'input[name="commerce_tag_value__contact:mastodon"]', + 'input[name="commerce_tag_value__address"]', + 'input[name="custom_opening_hours"]', + 'input[name="commerce_tag_value__contact:street"]', + 'input[name="commerce_tag_value__contact:housenumber"]', + 'input[name="custom__cuisine"]', + ] + + list_inputs_good_to_fill.forEach(selector => { + const input = document.querySelector(selector); + if (input) { + if (input.value.trim() !== '') { + input.classList.add('good_filled'); + } else { + input.classList.remove('good_filled'); + } + } + }); + let errors = []; + document.querySelectorAll('.is-invalid').forEach(input => { + input.classList.remove('is-invalid'); + }); + + const nameInput = document.querySelector('input[name="commerce_tag_value__name"]'); + if (!nameInput.value.trim()) { + errors.push("Le nom de l'établissement est obligatoire"); + nameInput.classList.add('is-invalid'); + } + + const emailInput = document.querySelector('input[name="commerce_tag_value__contact:email"]'); + if (emailInput && emailInput.value) { + const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; + if (!emailRegex.test(emailInput.value)) { + errors.push("L'adresse email n'est pas valide"); + emailInput.classList.add('is-invalid'); + } + } + + const phoneInput = document.querySelector('input[name="commerce_tag_value__contact:phone"]'); + if (phoneInput && phoneInput.value) { + const phoneRegex = /^(\+33|0)[1-9](\d{2}){4}$/; + if (!phoneRegex.test(phoneInput.value.replace(/\s/g, ''))) { + errors.push("Le numéro de téléphone n'est pas valide"); + phoneInput.classList.add('is-invalid'); + } + } + + if (errors.length > 0) { + e.preventDefault(); + document.querySelector('#validation_messages').innerHTML = errors.join('
'); + document.querySelector('#validation_messages').classList.add('is-invalid'); + } +} + +export const genererCouleurPastel = () => { + const r = Math.floor(Math.random() * 75 + 180); + const g = Math.floor(Math.random() * 75 + 180); + const b = Math.floor(Math.random() * 75 + 180); + return `rgb(${r}, ${g}, ${b})`; +}; + +async function searchInseeCode(query) { + try { + document.querySelector('#loading_search_insee').classList.remove('d-none'); + + const response = await fetch(`https://geo.api.gouv.fr/communes?nom=${query}&fields=nom,code,codesPostaux&limit=10`); + const data = await response.json(); + document.querySelector('#loading_search_insee').classList.add('d-none'); + + return data.map(commune => ({ + label: `${commune.nom} (${commune.codesPostaux.join(', ')}, code insee ${commune.code})`, + insee: commune.code, + postcodes: commune.codesPostaux + })); + } catch (error) { + console.error('Erreur lors de la recherche du code INSEE:', error); + return []; + } +} + +export function updateMapHeightForLargeScreens() { + const mapFound = document.querySelector('#map'); + const canvasFound = document.querySelector('#map canvas'); + const newHeight = window.innerHeight * 0.5 + 'px' + if (mapFound && window.innerHeight > 800 && window.innerWidth > 800) { + mapFound.style.height = newHeight; + } else { + console.log('window.innerHeight', window.innerHeight); + } +} + +async function listChangesets() { + const options = { + headers: { + 'Accept': 'application/json' + } + }; + const changesets = await fetch('https://api.openstreetmap.org/api/0.6/changesets?display_name=osm-commerce-fr', options); + const data = await changesets.json(); + console.log(data.changesets.length); + + const now = new Date(); + const last24h = new Date(now - 24 * 60 * 60 * 1000); + const last7days = new Date(now - 7 * 24 * 60 * 60 * 1000); + const last30days = new Date(now - 30 * 24 * 60 * 60 * 1000); + + const stats = { + last24h: 0, + last7days: 0, + last30days: 0 + }; + + data.changesets.forEach(changeset => { + const changesetDate = new Date(changeset.closed_at); + + if (changesetDate >= last24h) { + stats.last24h++; + } + if (changesetDate >= last7days) { + stats.last7days++; + } + if (changesetDate >= last30days) { + stats.last30days++; + } + }); + + const historyDiv = document.getElementById('userChangesHistory'); + if (historyDiv) { + historyDiv.innerHTML = ` +
+

Changesets créés :

+
+
Dernières 24h :
${stats.last24h}
+
7 derniers jours :
${stats.last7days}
+
30 derniers jours :
${stats.last30days}
+
+
+ `; + } +} + +function openInPanoramax() { + const center = map.getCenter(); + const zoom = map.getZoom(); + const panoramaxUrl = `https://api.panoramax.xyz/?focus=map&map=${zoom}/${center.lat}/${center.lng}`; + window.open(panoramaxUrl); +} + +export function enableLabourageForm() { + const citySearchInput = document.getElementById('citySearch'); + const citySuggestionsList = document.getElementById('citySuggestions'); + + if (citySearchInput && citySuggestionsList) { + const form = citySearchInput.closest('form'); + setupCitySearch('citySearch', 'citySuggestions', function (result_search) { + if (form) { + const labourageBtn = form.querySelector('button[type="submit"]'); + if (labourageBtn) { + // Remplir le champ caché avec le code INSEE + const inseeInput = form.querySelector('#selectedZipCode'); + if (inseeInput) { + inseeInput.value = result_search.insee; + } + // Changer l'action du formulaire pour pointer vers la bonne URL + form.action = getLabourerUrl(result_search); + + // Changer le texte du bouton et le désactiver + labourageBtn.innerHTML = ' Ajout de ' + result_search.name + '...'; + labourageBtn.disabled = true; + + // Soumettre le formulaire + form.submit(); + } + }else{ + console.warn('pas de form pour labourage trouvé') + } + }); + }else{ + console.warn('pas de labourage citySearchInput citySuggestionsList trouvé', citySearchInput,citySuggestionsList ) + } +} + +export function setupCitySearch(inputId, suggestionListId, onSelect) { + const searchInput = document.getElementById(inputId); + const suggestionList = document.getElementById(suggestionListId); + + if (!searchInput || !suggestionList) return; + + let timeoutId = null; + let searchOngoing = false; + + searchInput.addEventListener('keyup', function () { + clearTimeout(timeoutId); + const query = this.value.trim(); + if (query.length < 3) { + clearSuggestions(); + return; + } + timeoutId = setTimeout(() => { + if (!searchOngoing) { + searchOngoing = true; + performSearch(query).then(() => { + searchOngoing = false; + }); + } + }, 300); + }); + + async function performSearch(query) { + try { + const response = await fetch(`https://geo.api.gouv.fr/communes?nom=${encodeURIComponent(query)}&fields=nom,code,codesPostaux&limit=5`); + const data = await response.json(); + const citySuggestions = data.map(city => ({ + name: city.nom, + insee: city.code, + postcodes: city.codesPostaux, + postcode: city.codesPostaux && city.codesPostaux.length > 0 ? city.codesPostaux[0] : '', + display_name: `${city.nom} (${city.codesPostaux && city.codesPostaux.length > 0 ? city.codesPostaux[0] : ''})` + })); + displaySuggestions(citySuggestions); + } catch (error) { + console.error("Erreur de recherche:", error); + } + } + + function displaySuggestions(suggestions) { + clearSuggestions(); + suggestions.forEach(suggestion => { + const item = document.createElement('div'); + item.classList.add('suggestion-item'); + // Nouveau rendu : nom en gras, INSEE et CP en petit/gris + item.innerHTML = ` + ${suggestion.name}
+ + INSEE : ${suggestion.insee} + CP : ${Array.isArray(suggestion.postcodes) ? suggestion.postcodes.join(', ') : suggestion.postcode} + + `; + item.addEventListener('click', () => { + searchInput.value = suggestion.name; + clearSuggestions(); + if (onSelect) { + onSelect(suggestion); + } + }); + suggestionList.appendChild(item); + }); + suggestionList.style.display = 'block'; + } + + function clearSuggestions() { + suggestionList.innerHTML = ''; + suggestionList.style.display = 'none'; + } + + document.addEventListener('click', (e) => { + if (!searchInput.contains(e.target) && !suggestionList.contains(e.target)) { + clearSuggestions(); + } + }); +} + +export function getLabourerUrl(obj) { + if (obj && obj.insee) { + return `/add-city-without-labourage/${obj.insee}`; + } + return '#'; +} + +export function handleAddCityFormSubmit(event) { + event.preventDefault(); + const zipCode = document.getElementById('selectedZipCode').value; + if (zipCode && zipCode.match(/^\d{5}$/)) { + window.location.href = `/add-city-without-labourage/${zipCode}`; + } else { + alert('Veuillez sélectionner une ville valide avec un code postal.'); + } +} + +export function colorizePercentageCells(selector, color = '154, 205, 50') { + document.querySelectorAll(selector).forEach(cell => { + const percentage = parseInt(cell.textContent.replace('%', ''), 10); + if (!isNaN(percentage)) { + const alpha = percentage / 100; + cell.style.backgroundColor = `rgba(${color}, ${alpha})`; + } + }); +} + +export function colorizePercentageCellsRelative(selector, color = '154, 205, 50') { + let min = Infinity; + let max = -Infinity; + const cells = document.querySelectorAll(selector); + + cells.forEach(cell => { + const value = parseInt(cell.textContent.replace('%', ''), 10); + if (!isNaN(value)) { + min = Math.min(min, value); + max = Math.max(max, value); + } + }); + + if (max > min) { + cells.forEach(cell => { + const value = parseInt(cell.textContent.replace('%', ''), 10); + if (!isNaN(value)) { + const ratio = (value - min) / (max - min); + cell.style.backgroundColor = `rgba(${color}, ${ratio.toFixed(2)})`; + } + }); + } +} + +export function adjustListGroupFontSize(selector, minFont = 0.8, maxFont = 1.2) { + const listItems = document.querySelectorAll(selector); + if (listItems.length === 0) return; + + let fontSize = maxFont; + const count = listItems.length; + if (count > 0) { + fontSize = Math.max(minFont, maxFont - (count - 5) * 0.05); + } + listItems.forEach(item => { + item.style.fontSize = fontSize + 'rem'; + }); +} + +export function calculateCompletion(properties) { + let completed = 0; + const total = 7; // Nombre de critères + + if (properties.name) completed++; + if (properties['addr:housenumber'] && properties['addr:street']) completed++; + if (properties.opening_hours) completed++; + if (properties.website || properties['contact:website']) completed++; + if (properties.phone || properties['contact:phone']) completed++; + if (properties.wheelchair) completed++; + + return { + percentage: total > 0 ? (completed / total) * 100 : 0, + completed: completed, + total: total + }; +} + +export function toggleCompletionInfo() { + const content = document.getElementById('completionInfoContent'); + const icon = document.getElementById('completionInfoIcon'); + if (content) { + const isVisible = content.style.display === 'block'; + content.style.display = isVisible ? 'none' : 'block'; + if (icon) { + icon.classList.toggle('bi-chevron-down', isVisible); + icon.classList.toggle('bi-chevron-up', !isVisible); + } + } +} + +window.check_validity = check_validity; +window.colorHeadingTable = colorHeadingTable; +window.openInPanoramax = openInPanoramax; +window.listChangesets = listChangesets; +window.adjustListGroupFontSize = adjustListGroupFontSize; +window.calculateCompletion = calculateCompletion; +window.toggleCompletionInfo = toggleCompletionInfo; \ No newline at end of file diff --git a/assets/vendor/@hotwired/stimulus/stimulus.index.js b/assets/vendor/@hotwired/stimulus/stimulus.index.js new file mode 100644 index 0000000..6d1225a --- /dev/null +++ b/assets/vendor/@hotwired/stimulus/stimulus.index.js @@ -0,0 +1,7 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/@hotwired/stimulus@3.2.2/dist/stimulus.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +class e{constructor(e,t,s){this.eventTarget=e,this.eventName=t,this.eventOptions=s,this.unorderedBindings=new Set}connect(){this.eventTarget.addEventListener(this.eventName,this,this.eventOptions)}disconnect(){this.eventTarget.removeEventListener(this.eventName,this,this.eventOptions)}bindingConnected(e){this.unorderedBindings.add(e)}bindingDisconnected(e){this.unorderedBindings.delete(e)}handleEvent(e){const t=function(e){if("immediatePropagationStopped"in e)return e;{const{stopImmediatePropagation:t}=e;return Object.assign(e,{immediatePropagationStopped:!1,stopImmediatePropagation(){this.immediatePropagationStopped=!0,t.call(this)}})}}(e);for(const e of this.bindings){if(t.immediatePropagationStopped)break;e.handleEvent(t)}}hasBindings(){return this.unorderedBindings.size>0}get bindings(){return Array.from(this.unorderedBindings).sort(((e,t)=>{const s=e.index,r=t.index;return sr?1:0}))}}class t{constructor(e){this.application=e,this.eventListenerMaps=new Map,this.started=!1}start(){this.started||(this.started=!0,this.eventListeners.forEach((e=>e.connect())))}stop(){this.started&&(this.started=!1,this.eventListeners.forEach((e=>e.disconnect())))}get eventListeners(){return Array.from(this.eventListenerMaps.values()).reduce(((e,t)=>e.concat(Array.from(t.values()))),[])}bindingConnected(e){this.fetchEventListenerForBinding(e).bindingConnected(e)}bindingDisconnected(e,t=!1){this.fetchEventListenerForBinding(e).bindingDisconnected(e),t&&this.clearEventListenersForBinding(e)}handleError(e,t,s={}){this.application.handleError(e,`Error ${t}`,s)}clearEventListenersForBinding(e){const t=this.fetchEventListenerForBinding(e);t.hasBindings()||(t.disconnect(),this.removeMappedEventListenerFor(e))}removeMappedEventListenerFor(e){const{eventTarget:t,eventName:s,eventOptions:r}=e,n=this.fetchEventListenerMapForEventTarget(t),i=this.cacheKey(s,r);n.delete(i),0==n.size&&this.eventListenerMaps.delete(t)}fetchEventListenerForBinding(e){const{eventTarget:t,eventName:s,eventOptions:r}=e;return this.fetchEventListener(t,s,r)}fetchEventListener(e,t,s){const r=this.fetchEventListenerMapForEventTarget(e),n=this.cacheKey(t,s);let i=r.get(n);return i||(i=this.createEventListener(e,t,s),r.set(n,i)),i}createEventListener(t,s,r){const n=new e(t,s,r);return this.started&&n.connect(),n}fetchEventListenerMapForEventTarget(e){let t=this.eventListenerMaps.get(e);return t||(t=new Map,this.eventListenerMaps.set(e,t)),t}cacheKey(e,t){const s=[e];return Object.keys(t).sort().forEach((e=>{s.push(`${t[e]?"":"!"}${e}`)})),s.join(":")}}const s={stop:({event:e,value:t})=>(t&&e.stopPropagation(),!0),prevent:({event:e,value:t})=>(t&&e.preventDefault(),!0),self:({event:e,value:t,element:s})=>!t||s===e.target},r=/^(?:(?:([^.]+?)\+)?(.+?)(?:\.(.+?))?(?:@(window|document))?->)?(.+?)(?:#([^:]+?))(?::(.+))?$/;function n(e){return"window"==e?window:"document"==e?document:void 0}function i(e){return e.replace(/(?:[_-])([a-z0-9])/g,((e,t)=>t.toUpperCase()))}function o(e){return i(e.replace(/--/g,"-").replace(/__/g,"_"))}function a(e){return e.charAt(0).toUpperCase()+e.slice(1)}function c(e){return e.replace(/([A-Z])/g,((e,t)=>`-${t.toLowerCase()}`))}function l(e){return null!=e}function h(e,t){return Object.prototype.hasOwnProperty.call(e,t)}const u=["meta","ctrl","alt","shift"];class d{constructor(e,t,s,r){this.element=e,this.index=t,this.eventTarget=s.eventTarget||e,this.eventName=s.eventName||function(e){const t=e.tagName.toLowerCase();if(t in m)return m[t](e)}(e)||g("missing event name"),this.eventOptions=s.eventOptions||{},this.identifier=s.identifier||g("missing identifier"),this.methodName=s.methodName||g("missing method name"),this.keyFilter=s.keyFilter||"",this.schema=r}static forToken(e,t){return new this(e.element,e.index,function(e){const t=e.trim().match(r)||[];let s=t[2],i=t[3];return i&&!["keydown","keyup","keypress"].includes(s)&&(s+=`.${i}`,i=""),{eventTarget:n(t[4]),eventName:s,eventOptions:t[7]?(o=t[7],o.split(":").reduce(((e,t)=>Object.assign(e,{[t.replace(/^!/,"")]:!/^!/.test(t)})),{})):{},identifier:t[5],methodName:t[6],keyFilter:t[1]||i};var o}(e.content),t)}toString(){const e=this.keyFilter?`.${this.keyFilter}`:"",t=this.eventTargetName?`@${this.eventTargetName}`:"";return`${this.eventName}${e}${t}->${this.identifier}#${this.methodName}`}shouldIgnoreKeyboardEvent(e){if(!this.keyFilter)return!1;const t=this.keyFilter.split("+");if(this.keyFilterDissatisfied(e,t))return!0;const s=t.filter((e=>!u.includes(e)))[0];return!!s&&(h(this.keyMappings,s)||g(`contains unknown key filter: ${this.keyFilter}`),this.keyMappings[s].toLowerCase()!==e.key.toLowerCase())}shouldIgnoreMouseEvent(e){if(!this.keyFilter)return!1;const t=[this.keyFilter];return!!this.keyFilterDissatisfied(e,t)}get params(){const e={},t=new RegExp(`^data-${this.identifier}-(.+)-param$`,"i");for(const{name:s,value:r}of Array.from(this.element.attributes)){const n=s.match(t),o=n&&n[1];o&&(e[i(o)]=p(r))}return e}get eventTargetName(){return(e=this.eventTarget)==window?"window":e==document?"document":void 0;var e}get keyMappings(){return this.schema.keyMappings}keyFilterDissatisfied(e,t){const[s,r,n,i]=u.map((e=>t.includes(e)));return e.metaKey!==s||e.ctrlKey!==r||e.altKey!==n||e.shiftKey!==i}}const m={a:()=>"click",button:()=>"click",form:()=>"submit",details:()=>"toggle",input:e=>"submit"==e.getAttribute("type")?"click":"input",select:()=>"change",textarea:()=>"input"};function g(e){throw new Error(e)}function p(e){try{return JSON.parse(e)}catch(t){return e}}class f{constructor(e,t){this.context=e,this.action=t}get index(){return this.action.index}get eventTarget(){return this.action.eventTarget}get eventOptions(){return this.action.eventOptions}get identifier(){return this.context.identifier}handleEvent(e){const t=this.prepareActionEvent(e);this.willBeInvokedByEvent(e)&&this.applyEventModifiers(t)&&this.invokeWithEvent(t)}get eventName(){return this.action.eventName}get method(){const e=this.controller[this.methodName];if("function"==typeof e)return e;throw new Error(`Action "${this.action}" references undefined method "${this.methodName}"`)}applyEventModifiers(e){const{element:t}=this.action,{actionDescriptorFilters:s}=this.context.application,{controller:r}=this.context;let n=!0;for(const[i,o]of Object.entries(this.eventOptions))if(i in s){const a=s[i];n=n&&a({name:i,value:o,event:e,element:t,controller:r})}return n}prepareActionEvent(e){return Object.assign(e,{params:this.action.params})}invokeWithEvent(e){const{target:t,currentTarget:s}=e;try{this.method.call(this.controller,e),this.context.logDebugActivity(this.methodName,{event:e,target:t,currentTarget:s,action:this.methodName})}catch(t){const{identifier:s,controller:r,element:n,index:i}=this,o={identifier:s,controller:r,element:n,index:i,event:e};this.context.handleError(t,`invoking action "${this.action}"`,o)}}willBeInvokedByEvent(e){const t=e.target;return!(e instanceof KeyboardEvent&&this.action.shouldIgnoreKeyboardEvent(e))&&(!(e instanceof MouseEvent&&this.action.shouldIgnoreMouseEvent(e))&&(this.element===t||(t instanceof Element&&this.element.contains(t)?this.scope.containsElement(t):this.scope.containsElement(this.action.element))))}get controller(){return this.context.controller}get methodName(){return this.action.methodName}get element(){return this.scope.element}get scope(){return this.context.scope}}class b{constructor(e,t){this.mutationObserverInit={attributes:!0,childList:!0,subtree:!0},this.element=e,this.started=!1,this.delegate=t,this.elements=new Set,this.mutationObserver=new MutationObserver((e=>this.processMutations(e)))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,this.mutationObserverInit),this.refresh())}pause(e){this.started&&(this.mutationObserver.disconnect(),this.started=!1),e(),this.started||(this.mutationObserver.observe(this.element,this.mutationObserverInit),this.started=!0)}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started){const e=new Set(this.matchElementsInTree());for(const t of Array.from(this.elements))e.has(t)||this.removeElement(t);for(const t of Array.from(e))this.addElement(t)}}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){"attributes"==e.type?this.processAttributeChange(e.target,e.attributeName):"childList"==e.type&&(this.processRemovedNodes(e.removedNodes),this.processAddedNodes(e.addedNodes))}processAttributeChange(e,t){this.elements.has(e)?this.delegate.elementAttributeChanged&&this.matchElement(e)?this.delegate.elementAttributeChanged(e,t):this.removeElement(e):this.matchElement(e)&&this.addElement(e)}processRemovedNodes(e){for(const t of Array.from(e)){const e=this.elementFromNode(t);e&&this.processTree(e,this.removeElement)}}processAddedNodes(e){for(const t of Array.from(e)){const e=this.elementFromNode(t);e&&this.elementIsActive(e)&&this.processTree(e,this.addElement)}}matchElement(e){return this.delegate.matchElement(e)}matchElementsInTree(e=this.element){return this.delegate.matchElementsInTree(e)}processTree(e,t){for(const s of this.matchElementsInTree(e))t.call(this,s)}elementFromNode(e){if(e.nodeType==Node.ELEMENT_NODE)return e}elementIsActive(e){return e.isConnected==this.element.isConnected&&this.element.contains(e)}addElement(e){this.elements.has(e)||this.elementIsActive(e)&&(this.elements.add(e),this.delegate.elementMatched&&this.delegate.elementMatched(e))}removeElement(e){this.elements.has(e)&&(this.elements.delete(e),this.delegate.elementUnmatched&&this.delegate.elementUnmatched(e))}}class v{constructor(e,t,s){this.attributeName=t,this.delegate=s,this.elementObserver=new b(e,this)}get element(){return this.elementObserver.element}get selector(){return`[${this.attributeName}]`}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get started(){return this.elementObserver.started}matchElement(e){return e.hasAttribute(this.attributeName)}matchElementsInTree(e){const t=this.matchElement(e)?[e]:[],s=Array.from(e.querySelectorAll(this.selector));return t.concat(s)}elementMatched(e){this.delegate.elementMatchedAttribute&&this.delegate.elementMatchedAttribute(e,this.attributeName)}elementUnmatched(e){this.delegate.elementUnmatchedAttribute&&this.delegate.elementUnmatchedAttribute(e,this.attributeName)}elementAttributeChanged(e,t){this.delegate.elementAttributeValueChanged&&this.attributeName==t&&this.delegate.elementAttributeValueChanged(e,t)}}function y(e,t,s){A(e,t).add(s)}function O(e,t,s){A(e,t).delete(s),E(e,t)}function A(e,t){let s=e.get(t);return s||(s=new Set,e.set(t,s)),s}function E(e,t){const s=e.get(t);null!=s&&0==s.size&&e.delete(t)}class w{constructor(){this.valuesByKey=new Map}get keys(){return Array.from(this.valuesByKey.keys())}get values(){return Array.from(this.valuesByKey.values()).reduce(((e,t)=>e.concat(Array.from(t))),[])}get size(){return Array.from(this.valuesByKey.values()).reduce(((e,t)=>e+t.size),0)}add(e,t){y(this.valuesByKey,e,t)}delete(e,t){O(this.valuesByKey,e,t)}has(e,t){const s=this.valuesByKey.get(e);return null!=s&&s.has(t)}hasKey(e){return this.valuesByKey.has(e)}hasValue(e){return Array.from(this.valuesByKey.values()).some((t=>t.has(e)))}getValuesForKey(e){const t=this.valuesByKey.get(e);return t?Array.from(t):[]}getKeysForValue(e){return Array.from(this.valuesByKey).filter((([t,s])=>s.has(e))).map((([e,t])=>e))}}class M extends w{constructor(){super(),this.keysByValue=new Map}get values(){return Array.from(this.keysByValue.keys())}add(e,t){super.add(e,t),y(this.keysByValue,t,e)}delete(e,t){super.delete(e,t),O(this.keysByValue,t,e)}hasValue(e){return this.keysByValue.has(e)}getKeysForValue(e){const t=this.keysByValue.get(e);return t?Array.from(t):[]}}class k{constructor(e,t,s,r){this._selector=t,this.details=r,this.elementObserver=new b(e,this),this.delegate=s,this.matchesByElement=new w}get started(){return this.elementObserver.started}get selector(){return this._selector}set selector(e){this._selector=e,this.refresh()}start(){this.elementObserver.start()}pause(e){this.elementObserver.pause(e)}stop(){this.elementObserver.stop()}refresh(){this.elementObserver.refresh()}get element(){return this.elementObserver.element}matchElement(e){const{selector:t}=this;if(t){const s=e.matches(t);return this.delegate.selectorMatchElement?s&&this.delegate.selectorMatchElement(e,this.details):s}return!1}matchElementsInTree(e){const{selector:t}=this;if(t){const s=this.matchElement(e)?[e]:[],r=Array.from(e.querySelectorAll(t)).filter((e=>this.matchElement(e)));return s.concat(r)}return[]}elementMatched(e){const{selector:t}=this;t&&this.selectorMatched(e,t)}elementUnmatched(e){const t=this.matchesByElement.getKeysForValue(e);for(const s of t)this.selectorUnmatched(e,s)}elementAttributeChanged(e,t){const{selector:s}=this;if(s){const t=this.matchElement(e),r=this.matchesByElement.has(s,e);t&&!r?this.selectorMatched(e,s):!t&&r&&this.selectorUnmatched(e,s)}}selectorMatched(e,t){this.delegate.selectorMatched(e,t,this.details),this.matchesByElement.add(t,e)}selectorUnmatched(e,t){this.delegate.selectorUnmatched(e,t,this.details),this.matchesByElement.delete(t,e)}}class N{constructor(e,t){this.element=e,this.delegate=t,this.started=!1,this.stringMap=new Map,this.mutationObserver=new MutationObserver((e=>this.processMutations(e)))}start(){this.started||(this.started=!0,this.mutationObserver.observe(this.element,{attributes:!0,attributeOldValue:!0}),this.refresh())}stop(){this.started&&(this.mutationObserver.takeRecords(),this.mutationObserver.disconnect(),this.started=!1)}refresh(){if(this.started)for(const e of this.knownAttributeNames)this.refreshAttribute(e,null)}processMutations(e){if(this.started)for(const t of e)this.processMutation(t)}processMutation(e){const t=e.attributeName;t&&this.refreshAttribute(t,e.oldValue)}refreshAttribute(e,t){const s=this.delegate.getStringMapKeyForAttribute(e);if(null!=s){this.stringMap.has(e)||this.stringMapKeyAdded(s,e);const r=this.element.getAttribute(e);if(this.stringMap.get(e)!=r&&this.stringMapValueChanged(r,s,t),null==r){const t=this.stringMap.get(e);this.stringMap.delete(e),t&&this.stringMapKeyRemoved(s,e,t)}else this.stringMap.set(e,r)}}stringMapKeyAdded(e,t){this.delegate.stringMapKeyAdded&&this.delegate.stringMapKeyAdded(e,t)}stringMapValueChanged(e,t,s){this.delegate.stringMapValueChanged&&this.delegate.stringMapValueChanged(e,t,s)}stringMapKeyRemoved(e,t,s){this.delegate.stringMapKeyRemoved&&this.delegate.stringMapKeyRemoved(e,t,s)}get knownAttributeNames(){return Array.from(new Set(this.currentAttributeNames.concat(this.recordedAttributeNames)))}get currentAttributeNames(){return Array.from(this.element.attributes).map((e=>e.name))}get recordedAttributeNames(){return Array.from(this.stringMap.keys())}}class F{constructor(e,t,s){this.attributeObserver=new v(e,t,this),this.delegate=s,this.tokensByElement=new w}get started(){return this.attributeObserver.started}start(){this.attributeObserver.start()}pause(e){this.attributeObserver.pause(e)}stop(){this.attributeObserver.stop()}refresh(){this.attributeObserver.refresh()}get element(){return this.attributeObserver.element}get attributeName(){return this.attributeObserver.attributeName}elementMatchedAttribute(e){this.tokensMatched(this.readTokensForElement(e))}elementAttributeValueChanged(e){const[t,s]=this.refreshTokensForElement(e);this.tokensUnmatched(t),this.tokensMatched(s)}elementUnmatchedAttribute(e){this.tokensUnmatched(this.tokensByElement.getValuesForKey(e))}tokensMatched(e){e.forEach((e=>this.tokenMatched(e)))}tokensUnmatched(e){e.forEach((e=>this.tokenUnmatched(e)))}tokenMatched(e){this.delegate.tokenMatched(e),this.tokensByElement.add(e.element,e)}tokenUnmatched(e){this.delegate.tokenUnmatched(e),this.tokensByElement.delete(e.element,e)}refreshTokensForElement(e){const t=this.tokensByElement.getValuesForKey(e),s=this.readTokensForElement(e),r=function(e,t){const s=Math.max(e.length,t.length);return Array.from({length:s},((s,r)=>[e[r],t[r]]))}(t,s).findIndex((([e,t])=>{return r=t,!((s=e)&&r&&s.index==r.index&&s.content==r.content);var s,r}));return-1==r?[[],[]]:[t.slice(r),s.slice(r)]}readTokensForElement(e){const t=this.attributeName;return function(e,t,s){return e.trim().split(/\s+/).filter((e=>e.length)).map(((e,r)=>({element:t,attributeName:s,content:e,index:r})))}(e.getAttribute(t)||"",e,t)}}class B{constructor(e,t,s){this.tokenListObserver=new F(e,t,this),this.delegate=s,this.parseResultsByToken=new WeakMap,this.valuesByTokenByElement=new WeakMap}get started(){return this.tokenListObserver.started}start(){this.tokenListObserver.start()}stop(){this.tokenListObserver.stop()}refresh(){this.tokenListObserver.refresh()}get element(){return this.tokenListObserver.element}get attributeName(){return this.tokenListObserver.attributeName}tokenMatched(e){const{element:t}=e,{value:s}=this.fetchParseResultForToken(e);s&&(this.fetchValuesByTokenForElement(t).set(e,s),this.delegate.elementMatchedValue(t,s))}tokenUnmatched(e){const{element:t}=e,{value:s}=this.fetchParseResultForToken(e);s&&(this.fetchValuesByTokenForElement(t).delete(e),this.delegate.elementUnmatchedValue(t,s))}fetchParseResultForToken(e){let t=this.parseResultsByToken.get(e);return t||(t=this.parseToken(e),this.parseResultsByToken.set(e,t)),t}fetchValuesByTokenForElement(e){let t=this.valuesByTokenByElement.get(e);return t||(t=new Map,this.valuesByTokenByElement.set(e,t)),t}parseToken(e){try{return{value:this.delegate.parseValueForToken(e)}}catch(e){return{error:e}}}}class C{constructor(e,t){this.context=e,this.delegate=t,this.bindingsByAction=new Map}start(){this.valueListObserver||(this.valueListObserver=new B(this.element,this.actionAttribute,this),this.valueListObserver.start())}stop(){this.valueListObserver&&(this.valueListObserver.stop(),delete this.valueListObserver,this.disconnectAllActions())}get element(){return this.context.element}get identifier(){return this.context.identifier}get actionAttribute(){return this.schema.actionAttribute}get schema(){return this.context.schema}get bindings(){return Array.from(this.bindingsByAction.values())}connectAction(e){const t=new f(this.context,e);this.bindingsByAction.set(e,t),this.delegate.bindingConnected(t)}disconnectAction(e){const t=this.bindingsByAction.get(e);t&&(this.bindingsByAction.delete(e),this.delegate.bindingDisconnected(t))}disconnectAllActions(){this.bindings.forEach((e=>this.delegate.bindingDisconnected(e,!0))),this.bindingsByAction.clear()}parseValueForToken(e){const t=d.forToken(e,this.schema);if(t.identifier==this.identifier)return t}elementMatchedValue(e,t){this.connectAction(t)}elementUnmatchedValue(e,t){this.disconnectAction(t)}}class ${constructor(e,t){this.context=e,this.receiver=t,this.stringMapObserver=new N(this.element,this),this.valueDescriptorMap=this.controller.valueDescriptorMap}start(){this.stringMapObserver.start(),this.invokeChangedCallbacksForDefaultValues()}stop(){this.stringMapObserver.stop()}get element(){return this.context.element}get controller(){return this.context.controller}getStringMapKeyForAttribute(e){if(e in this.valueDescriptorMap)return this.valueDescriptorMap[e].name}stringMapKeyAdded(e,t){const s=this.valueDescriptorMap[t];this.hasValue(e)||this.invokeChangedCallback(e,s.writer(this.receiver[e]),s.writer(s.defaultValue))}stringMapValueChanged(e,t,s){const r=this.valueDescriptorNameMap[t];null!==e&&(null===s&&(s=r.writer(r.defaultValue)),this.invokeChangedCallback(t,e,s))}stringMapKeyRemoved(e,t,s){const r=this.valueDescriptorNameMap[e];this.hasValue(e)?this.invokeChangedCallback(e,r.writer(this.receiver[e]),s):this.invokeChangedCallback(e,r.writer(r.defaultValue),s)}invokeChangedCallbacksForDefaultValues(){for(const{key:e,name:t,defaultValue:s,writer:r}of this.valueDescriptors)null==s||this.controller.data.has(e)||this.invokeChangedCallback(t,r(s),void 0)}invokeChangedCallback(e,t,s){const r=`${e}Changed`,n=this.receiver[r];if("function"==typeof n){const r=this.valueDescriptorNameMap[e];try{const e=r.reader(t);let i=s;s&&(i=r.reader(s)),n.call(this.receiver,e,i)}catch(e){throw e instanceof TypeError&&(e.message=`Stimulus Value "${this.context.identifier}.${r.name}" - ${e.message}`),e}}}get valueDescriptors(){const{valueDescriptorMap:e}=this;return Object.keys(e).map((t=>e[t]))}get valueDescriptorNameMap(){const e={};return Object.keys(this.valueDescriptorMap).forEach((t=>{const s=this.valueDescriptorMap[t];e[s.name]=s})),e}hasValue(e){const t=`has${a(this.valueDescriptorNameMap[e].name)}`;return this.receiver[t]}}class T{constructor(e,t){this.context=e,this.delegate=t,this.targetsByName=new w}start(){this.tokenListObserver||(this.tokenListObserver=new F(this.element,this.attributeName,this),this.tokenListObserver.start())}stop(){this.tokenListObserver&&(this.disconnectAllTargets(),this.tokenListObserver.stop(),delete this.tokenListObserver)}tokenMatched({element:e,content:t}){this.scope.containsElement(e)&&this.connectTarget(e,t)}tokenUnmatched({element:e,content:t}){this.disconnectTarget(e,t)}connectTarget(e,t){var s;this.targetsByName.has(t,e)||(this.targetsByName.add(t,e),null===(s=this.tokenListObserver)||void 0===s||s.pause((()=>this.delegate.targetConnected(e,t))))}disconnectTarget(e,t){var s;this.targetsByName.has(t,e)&&(this.targetsByName.delete(t,e),null===(s=this.tokenListObserver)||void 0===s||s.pause((()=>this.delegate.targetDisconnected(e,t))))}disconnectAllTargets(){for(const e of this.targetsByName.keys)for(const t of this.targetsByName.getValuesForKey(e))this.disconnectTarget(t,e)}get attributeName(){return`data-${this.context.identifier}-target`}get element(){return this.context.element}get scope(){return this.context.scope}}function S(e,t){const s=D(e);return Array.from(s.reduce(((e,s)=>(function(e,t){const s=e[t];return Array.isArray(s)?s:[]}(s,t).forEach((t=>e.add(t))),e)),new Set))}function x(e,t){return D(e).reduce(((e,s)=>(e.push(...function(e,t){const s=e[t];return s?Object.keys(s).map((e=>[e,s[e]])):[]}(s,t)),e)),[])}function D(e){const t=[];for(;e;)t.push(e),e=Object.getPrototypeOf(e);return t.reverse()}class L{constructor(e,t){this.started=!1,this.context=e,this.delegate=t,this.outletsByName=new w,this.outletElementsByName=new w,this.selectorObserverMap=new Map,this.attributeObserverMap=new Map}start(){this.started||(this.outletDefinitions.forEach((e=>{this.setupSelectorObserverForOutlet(e),this.setupAttributeObserverForOutlet(e)})),this.started=!0,this.dependentContexts.forEach((e=>e.refresh())))}refresh(){this.selectorObserverMap.forEach((e=>e.refresh())),this.attributeObserverMap.forEach((e=>e.refresh()))}stop(){this.started&&(this.started=!1,this.disconnectAllOutlets(),this.stopSelectorObservers(),this.stopAttributeObservers())}stopSelectorObservers(){this.selectorObserverMap.size>0&&(this.selectorObserverMap.forEach((e=>e.stop())),this.selectorObserverMap.clear())}stopAttributeObservers(){this.attributeObserverMap.size>0&&(this.attributeObserverMap.forEach((e=>e.stop())),this.attributeObserverMap.clear())}selectorMatched(e,t,{outletName:s}){const r=this.getOutlet(e,s);r&&this.connectOutlet(r,e,s)}selectorUnmatched(e,t,{outletName:s}){const r=this.getOutletFromMap(e,s);r&&this.disconnectOutlet(r,e,s)}selectorMatchElement(e,{outletName:t}){const s=this.selector(t),r=this.hasOutlet(e,t),n=e.matches(`[${this.schema.controllerAttribute}~=${t}]`);return!!s&&(r&&n&&e.matches(s))}elementMatchedAttribute(e,t){const s=this.getOutletNameFromOutletAttributeName(t);s&&this.updateSelectorObserverForOutlet(s)}elementAttributeValueChanged(e,t){const s=this.getOutletNameFromOutletAttributeName(t);s&&this.updateSelectorObserverForOutlet(s)}elementUnmatchedAttribute(e,t){const s=this.getOutletNameFromOutletAttributeName(t);s&&this.updateSelectorObserverForOutlet(s)}connectOutlet(e,t,s){var r;this.outletElementsByName.has(s,t)||(this.outletsByName.add(s,e),this.outletElementsByName.add(s,t),null===(r=this.selectorObserverMap.get(s))||void 0===r||r.pause((()=>this.delegate.outletConnected(e,t,s))))}disconnectOutlet(e,t,s){var r;this.outletElementsByName.has(s,t)&&(this.outletsByName.delete(s,e),this.outletElementsByName.delete(s,t),null===(r=this.selectorObserverMap.get(s))||void 0===r||r.pause((()=>this.delegate.outletDisconnected(e,t,s))))}disconnectAllOutlets(){for(const e of this.outletElementsByName.keys)for(const t of this.outletElementsByName.getValuesForKey(e))for(const s of this.outletsByName.getValuesForKey(e))this.disconnectOutlet(s,t,e)}updateSelectorObserverForOutlet(e){const t=this.selectorObserverMap.get(e);t&&(t.selector=this.selector(e))}setupSelectorObserverForOutlet(e){const t=this.selector(e),s=new k(document.body,t,this,{outletName:e});this.selectorObserverMap.set(e,s),s.start()}setupAttributeObserverForOutlet(e){const t=this.attributeNameForOutletName(e),s=new v(this.scope.element,t,this);this.attributeObserverMap.set(e,s),s.start()}selector(e){return this.scope.outlets.getSelectorForOutletName(e)}attributeNameForOutletName(e){return this.scope.schema.outletAttributeForScope(this.identifier,e)}getOutletNameFromOutletAttributeName(e){return this.outletDefinitions.find((t=>this.attributeNameForOutletName(t)===e))}get outletDependencies(){const e=new w;return this.router.modules.forEach((t=>{S(t.definition.controllerConstructor,"outlets").forEach((s=>e.add(s,t.identifier)))})),e}get outletDefinitions(){return this.outletDependencies.getKeysForValue(this.identifier)}get dependentControllerIdentifiers(){return this.outletDependencies.getValuesForKey(this.identifier)}get dependentContexts(){const e=this.dependentControllerIdentifiers;return this.router.contexts.filter((t=>e.includes(t.identifier)))}hasOutlet(e,t){return!!this.getOutlet(e,t)||!!this.getOutletFromMap(e,t)}getOutlet(e,t){return this.application.getControllerForElementAndIdentifier(e,t)}getOutletFromMap(e,t){return this.outletsByName.getValuesForKey(t).find((t=>t.element===e))}get scope(){return this.context.scope}get schema(){return this.context.schema}get identifier(){return this.context.identifier}get application(){return this.context.application}get router(){return this.application.router}}class V{constructor(e,t){this.logDebugActivity=(e,t={})=>{const{identifier:s,controller:r,element:n}=this;t=Object.assign({identifier:s,controller:r,element:n},t),this.application.logDebugActivity(this.identifier,e,t)},this.module=e,this.scope=t,this.controller=new e.controllerConstructor(this),this.bindingObserver=new C(this,this.dispatcher),this.valueObserver=new $(this,this.controller),this.targetObserver=new T(this,this),this.outletObserver=new L(this,this);try{this.controller.initialize(),this.logDebugActivity("initialize")}catch(e){this.handleError(e,"initializing controller")}}connect(){this.bindingObserver.start(),this.valueObserver.start(),this.targetObserver.start(),this.outletObserver.start();try{this.controller.connect(),this.logDebugActivity("connect")}catch(e){this.handleError(e,"connecting controller")}}refresh(){this.outletObserver.refresh()}disconnect(){try{this.controller.disconnect(),this.logDebugActivity("disconnect")}catch(e){this.handleError(e,"disconnecting controller")}this.outletObserver.stop(),this.targetObserver.stop(),this.valueObserver.stop(),this.bindingObserver.stop()}get application(){return this.module.application}get identifier(){return this.module.identifier}get schema(){return this.application.schema}get dispatcher(){return this.application.dispatcher}get element(){return this.scope.element}get parentElement(){return this.element.parentElement}handleError(e,t,s={}){const{identifier:r,controller:n,element:i}=this;s=Object.assign({identifier:r,controller:n,element:i},s),this.application.handleError(e,`Error ${t}`,s)}targetConnected(e,t){this.invokeControllerMethod(`${t}TargetConnected`,e)}targetDisconnected(e,t){this.invokeControllerMethod(`${t}TargetDisconnected`,e)}outletConnected(e,t,s){this.invokeControllerMethod(`${o(s)}OutletConnected`,e,t)}outletDisconnected(e,t,s){this.invokeControllerMethod(`${o(s)}OutletDisconnected`,e,t)}invokeControllerMethod(e,...t){const s=this.controller;"function"==typeof s[e]&&s[e](...t)}}function K(e){return function(e,t){const s=j(e),r=function(e,t){return I(t).reduce(((s,r)=>{const n=function(e,t,s){const r=Object.getOwnPropertyDescriptor(e,s);if(!r||!("value"in r)){const e=Object.getOwnPropertyDescriptor(t,s).value;return r&&(e.get=r.get||e.get,e.set=r.set||e.set),e}}(e,t,r);return n&&Object.assign(s,{[r]:n}),s}),{})}(e.prototype,t);return Object.defineProperties(s.prototype,r),s}(e,function(e){const t=S(e,"blessings");return t.reduce(((t,s)=>{const r=s(e);for(const e in r){const s=t[e]||{};t[e]=Object.assign(s,r[e])}return t}),{})}(e))}const I="function"==typeof Object.getOwnPropertySymbols?e=>[...Object.getOwnPropertyNames(e),...Object.getOwnPropertySymbols(e)]:Object.getOwnPropertyNames,j=(()=>{function e(e){function t(){return Reflect.construct(e,arguments,new.target)}return t.prototype=Object.create(e.prototype,{constructor:{value:t}}),Reflect.setPrototypeOf(t,e),t}try{return function(){const t=e((function(){this.a.call(this)}));t.prototype.a=function(){},new t}(),e}catch(e){return e=>class extends e{}}})();class U{constructor(e,t){this.application=e,this.definition=function(e){return{identifier:e.identifier,controllerConstructor:K(e.controllerConstructor)}}(t),this.contextsByScope=new WeakMap,this.connectedContexts=new Set}get identifier(){return this.definition.identifier}get controllerConstructor(){return this.definition.controllerConstructor}get contexts(){return Array.from(this.connectedContexts)}connectContextForScope(e){const t=this.fetchContextForScope(e);this.connectedContexts.add(t),t.connect()}disconnectContextForScope(e){const t=this.contextsByScope.get(e);t&&(this.connectedContexts.delete(t),t.disconnect())}fetchContextForScope(e){let t=this.contextsByScope.get(e);return t||(t=new V(this,e),this.contextsByScope.set(e,t)),t}}class P{constructor(e){this.scope=e}has(e){return this.data.has(this.getDataKey(e))}get(e){return this.getAll(e)[0]}getAll(e){const t=this.data.get(this.getDataKey(e))||"";return t.match(/[^\s]+/g)||[]}getAttributeName(e){return this.data.getAttributeNameForKey(this.getDataKey(e))}getDataKey(e){return`${e}-class`}get data(){return this.scope.data}}class R{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get(e){const t=this.getAttributeNameForKey(e);return this.element.getAttribute(t)}set(e,t){const s=this.getAttributeNameForKey(e);return this.element.setAttribute(s,t),this.get(e)}has(e){const t=this.getAttributeNameForKey(e);return this.element.hasAttribute(t)}delete(e){if(this.has(e)){const t=this.getAttributeNameForKey(e);return this.element.removeAttribute(t),!0}return!1}getAttributeNameForKey(e){return`data-${this.identifier}-${c(e)}`}}class z{constructor(e){this.warnedKeysByObject=new WeakMap,this.logger=e}warn(e,t,s){let r=this.warnedKeysByObject.get(e);r||(r=new Set,this.warnedKeysByObject.set(e,r)),r.has(t)||(r.add(t),this.logger.warn(s,e))}}function _(e,t){return`[${e}~="${t}"]`}class q{constructor(e){this.scope=e}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce(((e,t)=>e||this.findTarget(t)||this.findLegacyTarget(t)),void 0)}findAll(...e){return e.reduce(((e,t)=>[...e,...this.findAllTargets(t),...this.findAllLegacyTargets(t)]),[])}findTarget(e){const t=this.getSelectorForTargetName(e);return this.scope.findElement(t)}findAllTargets(e){const t=this.getSelectorForTargetName(e);return this.scope.findAllElements(t)}getSelectorForTargetName(e){return _(this.schema.targetAttributeForScope(this.identifier),e)}findLegacyTarget(e){const t=this.getLegacySelectorForTargetName(e);return this.deprecate(this.scope.findElement(t),e)}findAllLegacyTargets(e){const t=this.getLegacySelectorForTargetName(e);return this.scope.findAllElements(t).map((t=>this.deprecate(t,e)))}getLegacySelectorForTargetName(e){const t=`${this.identifier}.${e}`;return _(this.schema.targetAttribute,t)}deprecate(e,t){if(e){const{identifier:s}=this,r=this.schema.targetAttribute,n=this.schema.targetAttributeForScope(s);this.guide.warn(e,`target:${t}`,`Please replace ${r}="${s}.${t}" with ${n}="${t}". The ${r} attribute is deprecated and will be removed in a future version of Stimulus.`)}return e}get guide(){return this.scope.guide}}class W{constructor(e,t){this.scope=e,this.controllerElement=t}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get schema(){return this.scope.schema}has(e){return null!=this.find(e)}find(...e){return e.reduce(((e,t)=>e||this.findOutlet(t)),void 0)}findAll(...e){return e.reduce(((e,t)=>[...e,...this.findAllOutlets(t)]),[])}getSelectorForOutletName(e){const t=this.schema.outletAttributeForScope(this.identifier,e);return this.controllerElement.getAttribute(t)}findOutlet(e){const t=this.getSelectorForOutletName(e);if(t)return this.findElement(t,e)}findAllOutlets(e){const t=this.getSelectorForOutletName(e);return t?this.findAllElements(t,e):[]}findElement(e,t){return this.scope.queryElements(e).filter((s=>this.matchesElement(s,e,t)))[0]}findAllElements(e,t){return this.scope.queryElements(e).filter((s=>this.matchesElement(s,e,t)))}matchesElement(e,t,s){const r=e.getAttribute(this.scope.schema.controllerAttribute)||"";return e.matches(t)&&r.split(" ").includes(s)}}class J{constructor(e,t,s,r){this.targets=new q(this),this.classes=new P(this),this.data=new R(this),this.containsElement=e=>e.closest(this.controllerSelector)===this.element,this.schema=e,this.element=t,this.identifier=s,this.guide=new z(r),this.outlets=new W(this.documentScope,t)}findElement(e){return this.element.matches(e)?this.element:this.queryElements(e).find(this.containsElement)}findAllElements(e){return[...this.element.matches(e)?[this.element]:[],...this.queryElements(e).filter(this.containsElement)]}queryElements(e){return Array.from(this.element.querySelectorAll(e))}get controllerSelector(){return _(this.schema.controllerAttribute,this.identifier)}get isDocumentScope(){return this.element===document.documentElement}get documentScope(){return this.isDocumentScope?this:new J(this.schema,document.documentElement,this.identifier,this.guide.logger)}}class H{constructor(e,t,s){this.element=e,this.schema=t,this.delegate=s,this.valueListObserver=new B(this.element,this.controllerAttribute,this),this.scopesByIdentifierByElement=new WeakMap,this.scopeReferenceCounts=new WeakMap}start(){this.valueListObserver.start()}stop(){this.valueListObserver.stop()}get controllerAttribute(){return this.schema.controllerAttribute}parseValueForToken(e){const{element:t,content:s}=e;return this.parseValueForElementAndIdentifier(t,s)}parseValueForElementAndIdentifier(e,t){const s=this.fetchScopesByIdentifierForElement(e);let r=s.get(t);return r||(r=this.delegate.createScopeForElementAndIdentifier(e,t),s.set(t,r)),r}elementMatchedValue(e,t){const s=(this.scopeReferenceCounts.get(t)||0)+1;this.scopeReferenceCounts.set(t,s),1==s&&this.delegate.scopeConnected(t)}elementUnmatchedValue(e,t){const s=this.scopeReferenceCounts.get(t);s&&(this.scopeReferenceCounts.set(t,s-1),1==s&&this.delegate.scopeDisconnected(t))}fetchScopesByIdentifierForElement(e){let t=this.scopesByIdentifierByElement.get(e);return t||(t=new Map,this.scopesByIdentifierByElement.set(e,t)),t}}class Z{constructor(e){this.application=e,this.scopeObserver=new H(this.element,this.schema,this),this.scopesByIdentifier=new w,this.modulesByIdentifier=new Map}get element(){return this.application.element}get schema(){return this.application.schema}get logger(){return this.application.logger}get controllerAttribute(){return this.schema.controllerAttribute}get modules(){return Array.from(this.modulesByIdentifier.values())}get contexts(){return this.modules.reduce(((e,t)=>e.concat(t.contexts)),[])}start(){this.scopeObserver.start()}stop(){this.scopeObserver.stop()}loadDefinition(e){this.unloadIdentifier(e.identifier);const t=new U(this.application,e);this.connectModule(t);const s=e.controllerConstructor.afterLoad;s&&s.call(e.controllerConstructor,e.identifier,this.application)}unloadIdentifier(e){const t=this.modulesByIdentifier.get(e);t&&this.disconnectModule(t)}getContextForElementAndIdentifier(e,t){const s=this.modulesByIdentifier.get(t);if(s)return s.contexts.find((t=>t.element==e))}proposeToConnectScopeForElementAndIdentifier(e,t){const s=this.scopeObserver.parseValueForElementAndIdentifier(e,t);s?this.scopeObserver.elementMatchedValue(s.element,s):console.error(`Couldn't find or create scope for identifier: "${t}" and element:`,e)}handleError(e,t,s){this.application.handleError(e,t,s)}createScopeForElementAndIdentifier(e,t){return new J(this.schema,e,t,this.logger)}scopeConnected(e){this.scopesByIdentifier.add(e.identifier,e);const t=this.modulesByIdentifier.get(e.identifier);t&&t.connectContextForScope(e)}scopeDisconnected(e){this.scopesByIdentifier.delete(e.identifier,e);const t=this.modulesByIdentifier.get(e.identifier);t&&t.disconnectContextForScope(e)}connectModule(e){this.modulesByIdentifier.set(e.identifier,e);this.scopesByIdentifier.getValuesForKey(e.identifier).forEach((t=>e.connectContextForScope(t)))}disconnectModule(e){this.modulesByIdentifier.delete(e.identifier);this.scopesByIdentifier.getValuesForKey(e.identifier).forEach((t=>e.disconnectContextForScope(t)))}}const G={controllerAttribute:"data-controller",actionAttribute:"data-action",targetAttribute:"data-target",targetAttributeForScope:e=>`data-${e}-target`,outletAttributeForScope:(e,t)=>`data-${e}-${t}-outlet`,keyMappings:Object.assign(Object.assign({enter:"Enter",tab:"Tab",esc:"Escape",space:" ",up:"ArrowUp",down:"ArrowDown",left:"ArrowLeft",right:"ArrowRight",home:"Home",end:"End",page_up:"PageUp",page_down:"PageDown"},Q("abcdefghijklmnopqrstuvwxyz".split("").map((e=>[e,e])))),Q("0123456789".split("").map((e=>[e,e]))))};function Q(e){return e.reduce(((e,[t,s])=>Object.assign(Object.assign({},e),{[t]:s})),{})}class X{constructor(e=document.documentElement,r=G){this.logger=console,this.debug=!1,this.logDebugActivity=(e,t,s={})=>{this.debug&&this.logFormattedMessage(e,t,s)},this.element=e,this.schema=r,this.dispatcher=new t(this),this.router=new Z(this),this.actionDescriptorFilters=Object.assign({},s)}static start(e,t){const s=new this(e,t);return s.start(),s}async start(){await new Promise((e=>{"loading"==document.readyState?document.addEventListener("DOMContentLoaded",(()=>e())):e()})),this.logDebugActivity("application","starting"),this.dispatcher.start(),this.router.start(),this.logDebugActivity("application","start")}stop(){this.logDebugActivity("application","stopping"),this.dispatcher.stop(),this.router.stop(),this.logDebugActivity("application","stop")}register(e,t){this.load({identifier:e,controllerConstructor:t})}registerActionOption(e,t){this.actionDescriptorFilters[e]=t}load(e,...t){(Array.isArray(e)?e:[e,...t]).forEach((e=>{e.controllerConstructor.shouldLoad&&this.router.loadDefinition(e)}))}unload(e,...t){(Array.isArray(e)?e:[e,...t]).forEach((e=>this.router.unloadIdentifier(e)))}get controllers(){return this.router.contexts.map((e=>e.controller))}getControllerForElementAndIdentifier(e,t){const s=this.router.getContextForElementAndIdentifier(e,t);return s?s.controller:null}handleError(e,t,s){var r;this.logger.error("%s\n\n%o\n\n%o",t,e,s),null===(r=window.onerror)||void 0===r||r.call(window,t,"",0,0,e)}logFormattedMessage(e,t,s={}){s=Object.assign({application:this},s),this.logger.groupCollapsed(`${e} #${t}`),this.logger.log("details:",Object.assign({},s)),this.logger.groupEnd()}}function Y(e,t,s){return e.application.getControllerForElementAndIdentifier(t,s)}function ee(e,t,s){let r=Y(e,t,s);return r||(e.application.router.proposeToConnectScopeForElementAndIdentifier(t,s),r=Y(e,t,s),r||void 0)}function te([e,t],s){return function(e){const{token:t,typeDefinition:s}=e,r=`${c(t)}-value`,n=function(e){const{controller:t,token:s,typeDefinition:r}=e,n={controller:t,token:s,typeObject:r},i=function(e){const{controller:t,token:s,typeObject:r}=e,n=l(r.type),i=l(r.default),o=n&&i,a=n&&!i,c=!n&&i,h=se(r.type),u=re(e.typeObject.default);if(a)return h;if(c)return u;if(h!==u){throw new Error(`The specified default value for the Stimulus Value "${t?`${t}.${s}`:s}" must match the defined type "${h}". The provided default value of "${r.default}" is of type "${u}".`)}if(o)return h}(n),o=re(r),a=se(r),c=i||o||a;if(c)return c;const h=t?`${t}.${r}`:s;throw new Error(`Unknown value type "${h}" for "${s}" value`)}(e);return{type:n,key:r,name:i(r),get defaultValue(){return function(e){const t=se(e);if(t)return ne[t];const s=h(e,"default"),r=h(e,"type"),n=e;if(s)return n.default;if(r){const{type:e}=n,t=se(e);if(t)return ne[t]}return e}(s)},get hasCustomDefaultValue(){return void 0!==re(s)},reader:ie[n],writer:oe[n]||oe.default}}({controller:s,token:e,typeDefinition:t})}function se(e){switch(e){case Array:return"array";case Boolean:return"boolean";case Number:return"number";case Object:return"object";case String:return"string"}}function re(e){switch(typeof e){case"boolean":return"boolean";case"number":return"number";case"string":return"string"}return Array.isArray(e)?"array":"[object Object]"===Object.prototype.toString.call(e)?"object":void 0}const ne={get array(){return[]},boolean:!1,number:0,get object(){return{}},string:""},ie={array(e){const t=JSON.parse(e);if(!Array.isArray(t))throw new TypeError(`expected value of type "array" but instead got value "${e}" of type "${re(t)}"`);return t},boolean:e=>!("0"==e||"false"==String(e).toLowerCase()),number:e=>Number(e.replace(/_/g,"")),object(e){const t=JSON.parse(e);if(null===t||"object"!=typeof t||Array.isArray(t))throw new TypeError(`expected value of type "object" but instead got value "${e}" of type "${re(t)}"`);return t},string:e=>e},oe={default:function(e){return`${e}`},array:ae,object:ae};function ae(e){return JSON.stringify(e)}class ce{constructor(e){this.context=e}static get shouldLoad(){return!0}static afterLoad(e,t){}get application(){return this.context.application}get scope(){return this.context.scope}get element(){return this.scope.element}get identifier(){return this.scope.identifier}get targets(){return this.scope.targets}get outlets(){return this.scope.outlets}get classes(){return this.scope.classes}get data(){return this.scope.data}initialize(){}connect(){}disconnect(){}dispatch(e,{target:t=this.element,detail:s={},prefix:r=this.identifier,bubbles:n=!0,cancelable:i=!0}={}){const o=new CustomEvent(r?`${r}:${e}`:e,{detail:s,bubbles:n,cancelable:i});return t.dispatchEvent(o),o}}ce.blessings=[function(e){return S(e,"classes").reduce(((e,t)=>{return Object.assign(e,(s=t,{[`${s}Class`]:{get(){const{classes:e}=this;if(e.has(s))return e.get(s);{const t=e.getAttributeName(s);throw new Error(`Missing attribute "${t}"`)}}},[`${s}Classes`]:{get(){return this.classes.getAll(s)}},[`has${a(s)}Class`]:{get(){return this.classes.has(s)}}}));var s}),{})},function(e){return S(e,"targets").reduce(((e,t)=>{return Object.assign(e,(s=t,{[`${s}Target`]:{get(){const e=this.targets.find(s);if(e)return e;throw new Error(`Missing target element "${s}" for "${this.identifier}" controller`)}},[`${s}Targets`]:{get(){return this.targets.findAll(s)}},[`has${a(s)}Target`]:{get(){return this.targets.has(s)}}}));var s}),{})},function(e){const t=x(e,"values"),s={valueDescriptorMap:{get(){return t.reduce(((e,t)=>{const s=te(t,this.identifier),r=this.data.getAttributeNameForKey(s.key);return Object.assign(e,{[r]:s})}),{})}}};return t.reduce(((e,t)=>Object.assign(e,function(e,t){const s=te(e,t),{key:r,name:n,reader:i,writer:o}=s;return{[n]:{get(){const e=this.data.get(r);return null!==e?i(e):s.defaultValue},set(e){void 0===e?this.data.delete(r):this.data.set(r,o(e))}},[`has${a(n)}`]:{get(){return this.data.has(r)||s.hasCustomDefaultValue}}}}(t))),s)},function(e){return S(e,"outlets").reduce(((e,t)=>Object.assign(e,function(e){const t=o(e);return{[`${t}Outlet`]:{get(){const t=this.outlets.find(e),s=this.outlets.getSelectorForOutletName(e);if(t){const s=ee(this,t,e);if(s)return s;throw new Error(`The provided outlet element is missing an outlet controller "${e}" instance for host controller "${this.identifier}"`)}throw new Error(`Missing outlet element "${e}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${s}".`)}},[`${t}Outlets`]:{get(){const t=this.outlets.findAll(e);return t.length>0?t.map((t=>{const s=ee(this,t,e);if(s)return s;console.warn(`The provided outlet element is missing an outlet controller "${e}" instance for host controller "${this.identifier}"`,t)})).filter((e=>e)):[]}},[`${t}OutletElement`]:{get(){const t=this.outlets.find(e),s=this.outlets.getSelectorForOutletName(e);if(t)return t;throw new Error(`Missing outlet element "${e}" for host controller "${this.identifier}". Stimulus couldn't find a matching outlet element using selector "${s}".`)}},[`${t}OutletElements`]:{get(){return this.outlets.findAll(e)}},[`has${a(t)}Outlet`]:{get(){return this.outlets.has(e)}}}}(t))),{})}],ce.targets=[],ce.outlets=[],ce.values={};export{X as Application,v as AttributeObserver,V as Context,ce as Controller,b as ElementObserver,M as IndexedMultimap,w as Multimap,k as SelectorObserver,N as StringMapObserver,F as TokenListObserver,B as ValueListObserver,y as add,G as defaultSchema,O as del,A as fetch,E as prune};export default null; diff --git a/assets/vendor/@hotwired/turbo/turbo.index.js b/assets/vendor/@hotwired/turbo/turbo.index.js new file mode 100644 index 0000000..7d28730 --- /dev/null +++ b/assets/vendor/@hotwired/turbo/turbo.index.js @@ -0,0 +1,30 @@ +/** + * Bundled by jsDelivr using Rollup v2.79.2 and Terser v5.39.0. + * Original file: /npm/@hotwired/turbo@7.3.0/dist/turbo.es2017-esm.js + * + * Do NOT use SRI with dynamically generated files! More information: https://www.jsdelivr.com/using-sri-with-dynamic-files + */ +!function(){if(void 0===window.Reflect||void 0===window.customElements||window.customElements.polyfillWrapFlushCallback)return;const e=HTMLElement,t=function(){return Reflect.construct(e,[],this.constructor)};window.HTMLElement=t,HTMLElement.prototype=e.prototype,HTMLElement.prototype.constructor=HTMLElement,Object.setPrototypeOf(HTMLElement,e)}(),function(e){function t(e,t,s){throw new e("Failed to execute 'requestSubmit' on 'HTMLFormElement': "+t+".",s)}"function"!=typeof e.requestSubmit&&(e.requestSubmit=function(e){e?(!function(e,s){e instanceof HTMLElement||t(TypeError,"parameter 1 is not of type 'HTMLElement'"),"submit"==e.type||t(TypeError,"The specified element is not a submit button"),e.form==s||t(DOMException,"The specified element is not owned by this form element","NotFoundError")}(e,this),e.click()):((e=document.createElement("input")).type="submit",e.hidden=!0,this.appendChild(e),e.click(),this.removeChild(e))})}(HTMLFormElement.prototype);const e=new WeakMap;function t(t){const s=function(e){const t=e instanceof Element?e:e instanceof Node?e.parentElement:null,s=t?t.closest("input, button"):null;return"submit"==(null==s?void 0:s.type)?s:null}(t.target);s&&s.form&&e.set(s.form,s)}var s,i,r,n,o,a;!function(){if("submitter"in Event.prototype)return;let s=window.Event.prototype;if("SubmitEvent"in window&&/Apple Computer/.test(navigator.vendor))s=window.SubmitEvent.prototype;else if("SubmitEvent"in window)return;addEventListener("click",t,!0),Object.defineProperty(s,"submitter",{get(){if("submit"==this.type&&this.target instanceof HTMLFormElement)return e.get(this.target)}})}(),function(e){e.eager="eager",e.lazy="lazy"}(s||(s={}));class l extends HTMLElement{static get observedAttributes(){return["disabled","complete","loading","src"]}constructor(){super(),this.loaded=Promise.resolve(),this.delegate=new l.delegateConstructor(this)}connectedCallback(){this.delegate.connect()}disconnectedCallback(){this.delegate.disconnect()}reload(){return this.delegate.sourceURLReloaded()}attributeChangedCallback(e){"loading"==e?this.delegate.loadingStyleChanged():"complete"==e?this.delegate.completeChanged():"src"==e?this.delegate.sourceURLChanged():this.delegate.disabledChanged()}get src(){return this.getAttribute("src")}set src(e){e?this.setAttribute("src",e):this.removeAttribute("src")}get loading(){return function(e){if("lazy"===e.toLowerCase())return s.lazy;return s.eager}(this.getAttribute("loading")||"")}set loading(e){e?this.setAttribute("loading",e):this.removeAttribute("loading")}get disabled(){return this.hasAttribute("disabled")}set disabled(e){e?this.setAttribute("disabled",""):this.removeAttribute("disabled")}get autoscroll(){return this.hasAttribute("autoscroll")}set autoscroll(e){e?this.setAttribute("autoscroll",""):this.removeAttribute("autoscroll")}get complete(){return!this.delegate.isLoading}get isActive(){return this.ownerDocument===document&&!this.isPreview}get isPreview(){var e,t;return null===(t=null===(e=this.ownerDocument)||void 0===e?void 0:e.documentElement)||void 0===t?void 0:t.hasAttribute("data-turbo-preview")}}function h(e){return new URL(e.toString(),document.baseURI)}function c(e){let t;return e.hash?e.hash.slice(1):(t=e.href.match(/#(.*)$/))?t[1]:void 0}function d(e,t){return h((null==t?void 0:t.getAttribute("formaction"))||e.getAttribute("action")||e.action)}function u(e){return(function(e){return function(e){return e.pathname.split("/").slice(1)}(e).slice(-1)[0]}(e).match(/\.[^.]*$/)||[])[0]||""}function m(e,t){const s=function(e){return t=e.origin+e.pathname,t.endsWith("/")?t:t+"/";var t}(t);return e.href===h(s).href||e.href.startsWith(s)}function p(e,t){return m(e,t)&&!!u(e).match(/^(?:|\.(?:htm|html|xhtml|php))$/)}function g(e){const t=c(e);return null!=t?e.href.slice(0,-(t.length+1)):e.href}function f(e){return g(e)}class v{constructor(e){this.response=e}get succeeded(){return this.response.ok}get failed(){return!this.succeeded}get clientError(){return this.statusCode>=400&&this.statusCode<=499}get serverError(){return this.statusCode>=500&&this.statusCode<=599}get redirected(){return this.response.redirected}get location(){return h(this.response.url)}get isHTML(){return this.contentType&&this.contentType.match(/^(?:text\/([^\s;,]+\b)?html|application\/xhtml\+xml)\b/)}get statusCode(){return this.response.status}get contentType(){return this.header("Content-Type")}get responseText(){return this.response.clone().text()}get responseHTML(){return this.isHTML?this.response.clone().text():Promise.resolve(void 0)}header(e){return this.response.headers.get(e)}}function b(e){if("false"==e.getAttribute("data-turbo-eval"))return e;{const t=document.createElement("script"),s=M("csp-nonce");return s&&(t.nonce=s),t.textContent=e.textContent,t.async=!1,function(e,t){for(const{name:s,value:i}of t.attributes)e.setAttribute(s,i)}(t,e),t}}function w(e,{target:t,cancelable:s,detail:i}={}){const r=new CustomEvent(e,{cancelable:s,bubbles:!0,composed:!0,detail:i});return t&&t.isConnected?t.dispatchEvent(r):document.documentElement.dispatchEvent(r),r}function S(){return new Promise((e=>requestAnimationFrame((()=>e()))))}function E(e=""){return(new DOMParser).parseFromString(e,"text/html")}function y(e,...t){const s=function(e,t){return e.reduce(((e,s,i)=>e+s+(null==t[i]?"":t[i])),"")}(e,t).replace(/^\n/,"").split("\n"),i=s[0].match(/^\s+/),r=i?i[0].length:0;return s.map((e=>e.slice(r))).join("\n")}function L(){return Array.from({length:36}).map(((e,t)=>8==t||13==t||18==t||23==t?"-":14==t?"4":19==t?(Math.floor(4*Math.random())+8).toString(16):Math.floor(15*Math.random()).toString(16))).join("")}function R(e,...t){for(const s of t.map((t=>null==t?void 0:t.getAttribute(e))))if("string"==typeof s)return s;return null}function C(...e){for(const t of e)"turbo-frame"==t.localName&&t.setAttribute("busy",""),t.setAttribute("aria-busy","true")}function T(...e){for(const t of e)"turbo-frame"==t.localName&&t.removeAttribute("busy"),t.removeAttribute("aria-busy")}function A(e,t=2e3){return new Promise((s=>{const i=()=>{e.removeEventListener("error",i),e.removeEventListener("load",i),s()};e.addEventListener("load",i,{once:!0}),e.addEventListener("error",i,{once:!0}),setTimeout(s,t)}))}function P(e){switch(e){case"replace":return history.replaceState;case"advance":case"restore":return history.pushState}}function F(...e){const t=R("data-turbo-action",...e);return function(e){return"advance"==e||"replace"==e||"restore"==e}(t)?t:null}function k(e){return document.querySelector(`meta[name="${e}"]`)}function M(e){const t=k(e);return t&&t.content}function I(e,t){var s;if(e instanceof Element)return e.closest(t)||I(e.assignedSlot||(null===(s=e.getRootNode())||void 0===s?void 0:s.host),t)}!function(e){e[e.get=0]="get",e[e.post=1]="post",e[e.put=2]="put",e[e.patch=3]="patch",e[e.delete=4]="delete"}(i||(i={}));class H{constructor(e,t,s,i=new URLSearchParams,r=null){this.abortController=new AbortController,this.resolveRequestPromise=e=>{},this.delegate=e,this.method=t,this.headers=this.defaultHeaders,this.body=i,this.url=s,this.target=r}get location(){return this.url}get params(){return this.url.searchParams}get entries(){return this.body?Array.from(this.body.entries()):[]}cancel(){this.abortController.abort()}async perform(){const{fetchOptions:e}=this;this.delegate.prepareRequest(this),await this.allowRequestToBeIntercepted(e);try{this.delegate.requestStarted(this);const t=await fetch(this.url.href,e);return await this.receive(t)}catch(e){if("AbortError"!==e.name)throw this.willDelegateErrorHandling(e)&&this.delegate.requestErrored(this,e),e}finally{this.delegate.requestFinished(this)}}async receive(e){const t=new v(e);return w("turbo:before-fetch-response",{cancelable:!0,detail:{fetchResponse:t},target:this.target}).defaultPrevented?this.delegate.requestPreventedHandlingResponse(this,t):t.succeeded?this.delegate.requestSucceededWithResponse(this,t):this.delegate.requestFailedWithResponse(this,t),t}get fetchOptions(){var e;return{method:i[this.method].toUpperCase(),credentials:"same-origin",headers:this.headers,redirect:"follow",body:this.isSafe?null:this.body,signal:this.abortSignal,referrer:null===(e=this.delegate.referrer)||void 0===e?void 0:e.href}}get defaultHeaders(){return{Accept:"text/html, application/xhtml+xml"}}get isSafe(){return this.method===i.get}get abortSignal(){return this.abortController.signal}acceptResponseType(e){this.headers.Accept=[e,this.headers.Accept].join(", ")}async allowRequestToBeIntercepted(e){const t=new Promise((e=>this.resolveRequestPromise=e));w("turbo:before-fetch-request",{cancelable:!0,detail:{fetchOptions:e,url:this.url,resume:this.resolveRequestPromise},target:this.target}).defaultPrevented&&await t}willDelegateErrorHandling(e){return!w("turbo:fetch-request-error",{target:this.target,cancelable:!0,detail:{request:this,error:e}}).defaultPrevented}}class q{constructor(e,t){this.started=!1,this.intersect=e=>{const t=e.slice(-1)[0];(null==t?void 0:t.isIntersecting)&&this.delegate.elementAppearedInViewport(this.element)},this.delegate=e,this.element=t,this.intersectionObserver=new IntersectionObserver(this.intersect)}start(){this.started||(this.started=!0,this.intersectionObserver.observe(this.element))}stop(){this.started&&(this.started=!1,this.intersectionObserver.unobserve(this.element))}}class B{static wrap(e){return"string"==typeof e?new this(function(e){const t=document.createElement("template");return t.innerHTML=e,t.content}(e)):e}constructor(e){this.fragment=function(e){for(const t of e.querySelectorAll("turbo-stream")){const e=document.importNode(t,!0);for(const t of e.templateElement.content.querySelectorAll("script"))t.replaceWith(b(t));t.replaceWith(e)}return e}(e)}}B.contentType="text/vnd.turbo-stream.html",function(e){e[e.initialized=0]="initialized",e[e.requesting=1]="requesting",e[e.waiting=2]="waiting",e[e.receiving=3]="receiving",e[e.stopping=4]="stopping",e[e.stopped=5]="stopped"}(r||(r={})),function(e){e.urlEncoded="application/x-www-form-urlencoded",e.multipart="multipart/form-data",e.plain="text/plain"}(n||(n={}));class O{static confirmMethod(e,t,s){return Promise.resolve(confirm(e))}constructor(e,t,s,n=!1){this.state=r.initialized,this.delegate=e,this.formElement=t,this.submitter=s,this.formData=function(e,t){const s=new FormData(e),i=null==t?void 0:t.getAttribute("name"),r=null==t?void 0:t.getAttribute("value");i&&s.append(i,r||"");return s}(t,s),this.location=h(this.action),this.method==i.get&&function(e,t){const s=new URLSearchParams;for(const[e,i]of t)i instanceof File||s.append(e,i);e.search=s.toString()}(this.location,[...this.body.entries()]),this.fetchRequest=new H(this,this.method,this.location,this.body,this.formElement),this.mustRedirect=n}get method(){var e;return function(e){switch(e.toLowerCase()){case"get":return i.get;case"post":return i.post;case"put":return i.put;case"patch":return i.patch;case"delete":return i.delete}}(((null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("formmethod"))||this.formElement.getAttribute("method")||"").toLowerCase())||i.get}get action(){var e;const t="string"==typeof this.formElement.action?this.formElement.action:null;return(null===(e=this.submitter)||void 0===e?void 0:e.hasAttribute("formaction"))?this.submitter.getAttribute("formaction")||"":this.formElement.getAttribute("action")||t||""}get body(){return this.enctype==n.urlEncoded||this.method==i.get?new URLSearchParams(this.stringFormData):this.formData}get enctype(){var e;return function(e){switch(e.toLowerCase()){case n.multipart:return n.multipart;case n.plain:return n.plain;default:return n.urlEncoded}}((null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("formenctype"))||this.formElement.enctype)}get isSafe(){return this.fetchRequest.isSafe}get stringFormData(){return[...this.formData].reduce(((e,[t,s])=>e.concat("string"==typeof s?[[t,s]]:[])),[])}async start(){const{initialized:e,requesting:t}=r,s=R("data-turbo-confirm",this.submitter,this.formElement);if("string"==typeof s){if(!await O.confirmMethod(s,this.formElement,this.submitter))return}if(this.state==e)return this.state=t,this.fetchRequest.perform()}stop(){const{stopping:e,stopped:t}=r;if(this.state!=e&&this.state!=t)return this.state=e,this.fetchRequest.cancel(),!0}prepareRequest(e){if(!e.isSafe){const t=function(e){if(null!=e){const t=(document.cookie?document.cookie.split("; "):[]).find((t=>t.startsWith(e)));if(t){const e=t.split("=").slice(1).join("=");return e?decodeURIComponent(e):void 0}}}(M("csrf-param"))||M("csrf-token");t&&(e.headers["X-CSRF-Token"]=t)}this.requestAcceptsTurboStreamResponse(e)&&e.acceptResponseType(B.contentType)}requestStarted(e){var t;this.state=r.waiting,null===(t=this.submitter)||void 0===t||t.setAttribute("disabled",""),this.setSubmitsWith(),w("turbo:submit-start",{target:this.formElement,detail:{formSubmission:this}}),this.delegate.formSubmissionStarted(this)}requestPreventedHandlingResponse(e,t){this.result={success:t.succeeded,fetchResponse:t}}requestSucceededWithResponse(e,t){if(t.clientError||t.serverError)this.delegate.formSubmissionFailedWithResponse(this,t);else if(this.requestMustRedirect(e)&&function(e){return 200==e.statusCode&&!e.redirected}(t)){const e=new Error("Form responses must redirect to another location");this.delegate.formSubmissionErrored(this,e)}else this.state=r.receiving,this.result={success:!0,fetchResponse:t},this.delegate.formSubmissionSucceededWithResponse(this,t)}requestFailedWithResponse(e,t){this.result={success:!1,fetchResponse:t},this.delegate.formSubmissionFailedWithResponse(this,t)}requestErrored(e,t){this.result={success:!1,error:t},this.delegate.formSubmissionErrored(this,t)}requestFinished(e){var t;this.state=r.stopped,null===(t=this.submitter)||void 0===t||t.removeAttribute("disabled"),this.resetSubmitterText(),w("turbo:submit-end",{target:this.formElement,detail:Object.assign({formSubmission:this},this.result)}),this.delegate.formSubmissionFinished(this)}setSubmitsWith(){if(this.submitter&&this.submitsWith)if(this.submitter.matches("button"))this.originalSubmitText=this.submitter.innerHTML,this.submitter.innerHTML=this.submitsWith;else if(this.submitter.matches("input")){const e=this.submitter;this.originalSubmitText=e.value,e.value=this.submitsWith}}resetSubmitterText(){if(this.submitter&&this.originalSubmitText)if(this.submitter.matches("button"))this.submitter.innerHTML=this.originalSubmitText;else if(this.submitter.matches("input")){this.submitter.value=this.originalSubmitText}}requestMustRedirect(e){return!e.isSafe&&this.mustRedirect}requestAcceptsTurboStreamResponse(e){return!e.isSafe||function(e,...t){return t.some((t=>t&&t.hasAttribute(e)))}("data-turbo-stream",this.submitter,this.formElement)}get submitsWith(){var e;return null===(e=this.submitter)||void 0===e?void 0:e.getAttribute("data-turbo-submits-with")}}class N{constructor(e){this.element=e}get activeElement(){return this.element.ownerDocument.activeElement}get children(){return[...this.element.children]}hasAnchor(e){return null!=this.getElementForAnchor(e)}getElementForAnchor(e){return e?this.element.querySelector(`[id='${e}'], a[name='${e}']`):null}get isConnected(){return this.element.isConnected}get firstAutofocusableElement(){for(const e of this.element.querySelectorAll("[autofocus]"))if(null==e.closest("[inert], :disabled, [hidden], details:not([open]), dialog:not([open])"))return e;return null}get permanentElements(){return W(this.element)}getPermanentElementById(e){return V(this.element,e)}getPermanentElementMapForSnapshot(e){const t={};for(const s of this.permanentElements){const{id:i}=s,r=e.getPermanentElementById(i);r&&(t[i]=[s,r])}return t}}function V(e,t){return e.querySelector(`#${t}[data-turbo-permanent]`)}function W(e){return e.querySelectorAll("[id][data-turbo-permanent]")}class D{constructor(e,t){this.started=!1,this.submitCaptured=()=>{this.eventTarget.removeEventListener("submit",this.submitBubbled,!1),this.eventTarget.addEventListener("submit",this.submitBubbled,!1)},this.submitBubbled=e=>{if(!e.defaultPrevented){const t=e.target instanceof HTMLFormElement?e.target:void 0,s=e.submitter||void 0;t&&function(e,t){const s=(null==t?void 0:t.getAttribute("formmethod"))||e.getAttribute("method");return"dialog"!=s}(t,s)&&function(e,t){if((null==t?void 0:t.hasAttribute("formtarget"))||e.hasAttribute("target")){const s=(null==t?void 0:t.getAttribute("formtarget"))||e.target;for(const e of document.getElementsByName(s))if(e instanceof HTMLIFrameElement)return!1;return!0}return!0}(t,s)&&this.delegate.willSubmitForm(t,s)&&(e.preventDefault(),e.stopImmediatePropagation(),this.delegate.formSubmitted(t,s))}},this.delegate=e,this.eventTarget=t}start(){this.started||(this.eventTarget.addEventListener("submit",this.submitCaptured,!0),this.started=!0)}stop(){this.started&&(this.eventTarget.removeEventListener("submit",this.submitCaptured,!0),this.started=!1)}}class x{constructor(e,t){this.resolveRenderPromise=e=>{},this.resolveInterceptionPromise=e=>{},this.delegate=e,this.element=t}scrollToAnchor(e){const t=this.snapshot.getElementForAnchor(e);t?(this.scrollToElement(t),this.focusElement(t)):this.scrollToPosition({x:0,y:0})}scrollToAnchorFromLocation(e){this.scrollToAnchor(c(e))}scrollToElement(e){e.scrollIntoView()}focusElement(e){e instanceof HTMLElement&&(e.hasAttribute("tabindex")?e.focus():(e.setAttribute("tabindex","-1"),e.focus(),e.removeAttribute("tabindex")))}scrollToPosition({x:e,y:t}){this.scrollRoot.scrollTo(e,t)}scrollToTop(){this.scrollToPosition({x:0,y:0})}get scrollRoot(){return window}async render(e){const{isPreview:t,shouldRender:s,newSnapshot:i}=e;if(s)try{this.renderPromise=new Promise((e=>this.resolveRenderPromise=e)),this.renderer=e,await this.prepareToRenderSnapshot(e);const s=new Promise((e=>this.resolveInterceptionPromise=e)),r={resume:this.resolveInterceptionPromise,render:this.renderer.renderElement};this.delegate.allowsImmediateRender(i,r)||await s,await this.renderSnapshot(e),this.delegate.viewRenderedSnapshot(i,t),this.delegate.preloadOnLoadLinksForView(this.element),this.finishRenderingSnapshot(e)}finally{delete this.renderer,this.resolveRenderPromise(void 0),delete this.renderPromise}else this.invalidate(e.reloadReason)}invalidate(e){this.delegate.viewInvalidated(e)}async prepareToRenderSnapshot(e){this.markAsPreview(e.isPreview),await e.prepareToRender()}markAsPreview(e){e?this.element.setAttribute("data-turbo-preview",""):this.element.removeAttribute("data-turbo-preview")}async renderSnapshot(e){await e.render()}finishRenderingSnapshot(e){e.finishRendering()}}class U extends x{missing(){this.element.innerHTML='Content missing'}get snapshot(){return new N(this.element)}}class j{constructor(e,t){this.clickBubbled=e=>{this.respondsToEventTarget(e.target)?this.clickEvent=e:delete this.clickEvent},this.linkClicked=e=>{this.clickEvent&&this.respondsToEventTarget(e.target)&&e.target instanceof Element&&this.delegate.shouldInterceptLinkClick(e.target,e.detail.url,e.detail.originalEvent)&&(this.clickEvent.preventDefault(),e.preventDefault(),this.delegate.linkClickIntercepted(e.target,e.detail.url,e.detail.originalEvent)),delete this.clickEvent},this.willVisit=e=>{delete this.clickEvent},this.delegate=e,this.element=t}start(){this.element.addEventListener("click",this.clickBubbled),document.addEventListener("turbo:click",this.linkClicked),document.addEventListener("turbo:before-visit",this.willVisit)}stop(){this.element.removeEventListener("click",this.clickBubbled),document.removeEventListener("turbo:click",this.linkClicked),document.removeEventListener("turbo:before-visit",this.willVisit)}respondsToEventTarget(e){const t=e instanceof Element?e:e instanceof Node?e.parentElement:null;return t&&t.closest("turbo-frame, html")==this.element}}class ${constructor(e,t){this.started=!1,this.clickCaptured=()=>{this.eventTarget.removeEventListener("click",this.clickBubbled,!1),this.eventTarget.addEventListener("click",this.clickBubbled,!1)},this.clickBubbled=e=>{if(e instanceof MouseEvent&&this.clickEventIsSignificant(e)){const t=e.composedPath&&e.composedPath()[0]||e.target,s=this.findLinkFromClickTarget(t);if(s&&function(e){if(e.hasAttribute("target")){for(const t of document.getElementsByName(e.target))if(t instanceof HTMLIFrameElement)return!1;return!0}return!0}(s)){const t=this.getLocationForLink(s);this.delegate.willFollowLinkToLocation(s,t,e)&&(e.preventDefault(),this.delegate.followedLinkToLocation(s,t))}}},this.delegate=e,this.eventTarget=t}start(){this.started||(this.eventTarget.addEventListener("click",this.clickCaptured,!0),this.started=!0)}stop(){this.started&&(this.eventTarget.removeEventListener("click",this.clickCaptured,!0),this.started=!1)}clickEventIsSignificant(e){return!(e.target&&e.target.isContentEditable||e.defaultPrevented||e.which>1||e.altKey||e.ctrlKey||e.metaKey||e.shiftKey)}findLinkFromClickTarget(e){return I(e,"a[href]:not([target^=_]):not([download])")}getLocationForLink(e){return h(e.getAttribute("href")||"")}}class z{constructor(e,t){this.delegate=e,this.linkInterceptor=new $(this,t)}start(){this.linkInterceptor.start()}stop(){this.linkInterceptor.stop()}willFollowLinkToLocation(e,t,s){return this.delegate.willSubmitFormLinkToLocation(e,t,s)&&e.hasAttribute("data-turbo-method")}followedLinkToLocation(e,t){const s=document.createElement("form");for(const[e,i]of t.searchParams)s.append(Object.assign(document.createElement("input"),{type:"hidden",name:e,value:i}));const i=Object.assign(t,{search:""});s.setAttribute("data-turbo","true"),s.setAttribute("action",i.href),s.setAttribute("hidden","");const r=e.getAttribute("data-turbo-method");r&&s.setAttribute("method",r);const n=e.getAttribute("data-turbo-frame");n&&s.setAttribute("data-turbo-frame",n);const o=F(e);o&&s.setAttribute("data-turbo-action",o);const a=e.getAttribute("data-turbo-confirm");a&&s.setAttribute("data-turbo-confirm",a);e.hasAttribute("data-turbo-stream")&&s.setAttribute("data-turbo-stream",""),this.delegate.submittedFormLinkToLocation(e,t,s),document.body.appendChild(s),s.addEventListener("turbo:submit-end",(()=>s.remove()),{once:!0}),requestAnimationFrame((()=>s.requestSubmit()))}}class _{static async preservingPermanentElements(e,t,s){const i=new this(e,t);i.enter(),await s(),i.leave()}constructor(e,t){this.delegate=e,this.permanentElementMap=t}enter(){for(const e in this.permanentElementMap){const[t,s]=this.permanentElementMap[e];this.delegate.enteringBardo(t,s),this.replaceNewPermanentElementWithPlaceholder(s)}}leave(){for(const e in this.permanentElementMap){const[t]=this.permanentElementMap[e];this.replaceCurrentPermanentElementWithClone(t),this.replacePlaceholderWithPermanentElement(t),this.delegate.leavingBardo(t)}}replaceNewPermanentElementWithPlaceholder(e){const t=function(e){const t=document.createElement("meta");return t.setAttribute("name","turbo-permanent-placeholder"),t.setAttribute("content",e.id),t}(e);e.replaceWith(t)}replaceCurrentPermanentElementWithClone(e){const t=e.cloneNode(!0);e.replaceWith(t)}replacePlaceholderWithPermanentElement(e){const t=this.getPlaceholderById(e.id);null==t||t.replaceWith(e)}getPlaceholderById(e){return this.placeholders.find((t=>t.content==e))}get placeholders(){return[...document.querySelectorAll("meta[name=turbo-permanent-placeholder][content]")]}}class K{constructor(e,t,s,i,r=!0){this.activeElement=null,this.currentSnapshot=e,this.newSnapshot=t,this.isPreview=i,this.willRender=r,this.renderElement=s,this.promise=new Promise(((e,t)=>this.resolvingFunctions={resolve:e,reject:t}))}get shouldRender(){return!0}get reloadReason(){}prepareToRender(){}finishRendering(){this.resolvingFunctions&&(this.resolvingFunctions.resolve(),delete this.resolvingFunctions)}async preservingPermanentElements(e){await _.preservingPermanentElements(this,this.permanentElementMap,e)}focusFirstAutofocusableElement(){const e=this.connectedSnapshot.firstAutofocusableElement;(function(e){return e&&"function"==typeof e.focus})(e)&&e.focus()}enteringBardo(e){this.activeElement||e.contains(this.currentSnapshot.activeElement)&&(this.activeElement=this.currentSnapshot.activeElement)}leavingBardo(e){e.contains(this.activeElement)&&this.activeElement instanceof HTMLElement&&(this.activeElement.focus(),this.activeElement=null)}get connectedSnapshot(){return this.newSnapshot.isConnected?this.newSnapshot:this.currentSnapshot}get currentElement(){return this.currentSnapshot.element}get newElement(){return this.newSnapshot.element}get permanentElementMap(){return this.currentSnapshot.getPermanentElementMapForSnapshot(this.newSnapshot)}}class Q extends K{static renderElement(e,t){var s;const i=document.createRange();i.selectNodeContents(e),i.deleteContents();const r=t,n=null===(s=r.ownerDocument)||void 0===s?void 0:s.createRange();n&&(n.selectNodeContents(r),e.appendChild(n.extractContents()))}constructor(e,t,s,i,r,n=!0){super(t,s,i,r,n),this.delegate=e}get shouldRender(){return!0}async render(){await S(),this.preservingPermanentElements((()=>{this.loadFrameElement()})),this.scrollFrameIntoView(),await S(),this.focusFirstAutofocusableElement(),await S(),this.activateScriptElements()}loadFrameElement(){this.delegate.willRenderFrame(this.currentElement,this.newElement),this.renderElement(this.currentElement,this.newElement)}scrollFrameIntoView(){if(this.currentElement.autoscroll||this.newElement.autoscroll){const s=this.currentElement.firstElementChild,i=(e=this.currentElement.getAttribute("data-autoscroll-block"),t="end","end"==e||"start"==e||"center"==e||"nearest"==e?e:t),r=function(e,t){return"auto"==e||"smooth"==e?e:t}(this.currentElement.getAttribute("data-autoscroll-behavior"),"auto");if(s)return s.scrollIntoView({block:i,behavior:r}),!0}var e,t;return!1}activateScriptElements(){for(const e of this.newScriptElements){const t=b(e);e.replaceWith(t)}}get newScriptElements(){return this.currentElement.querySelectorAll("script")}}class X{static get defaultCSS(){return y` + .turbo-progress-bar { + position: fixed; + display: block; + top: 0; + left: 0; + height: 3px; + background: #0076ff; + z-index: 2147483647; + transition: + width ${X.animationDuration}ms ease-out, + opacity ${X.animationDuration/2}ms ${X.animationDuration/2}ms ease-in; + transform: translate3d(0, 0, 0); + } + `}constructor(){this.hiding=!1,this.value=0,this.visible=!1,this.trickle=()=>{this.setValue(this.value+Math.random()/100)},this.stylesheetElement=this.createStylesheetElement(),this.progressElement=this.createProgressElement(),this.installStylesheetElement(),this.setValue(0)}show(){this.visible||(this.visible=!0,this.installProgressElement(),this.startTrickling())}hide(){this.visible&&!this.hiding&&(this.hiding=!0,this.fadeProgressElement((()=>{this.uninstallProgressElement(),this.stopTrickling(),this.visible=!1,this.hiding=!1})))}setValue(e){this.value=e,this.refresh()}installStylesheetElement(){document.head.insertBefore(this.stylesheetElement,document.head.firstChild)}installProgressElement(){this.progressElement.style.width="0",this.progressElement.style.opacity="1",document.documentElement.insertBefore(this.progressElement,document.body),this.refresh()}fadeProgressElement(e){this.progressElement.style.opacity="0",setTimeout(e,1.5*X.animationDuration)}uninstallProgressElement(){this.progressElement.parentNode&&document.documentElement.removeChild(this.progressElement)}startTrickling(){this.trickleInterval||(this.trickleInterval=window.setInterval(this.trickle,X.animationDuration))}stopTrickling(){window.clearInterval(this.trickleInterval),delete this.trickleInterval}refresh(){requestAnimationFrame((()=>{this.progressElement.style.width=10+90*this.value+"%"}))}createStylesheetElement(){const e=document.createElement("style");return e.type="text/css",e.textContent=X.defaultCSS,this.cspNonce&&(e.nonce=this.cspNonce),e}createProgressElement(){const e=document.createElement("div");return e.className="turbo-progress-bar",e}get cspNonce(){return M("csp-nonce")}}X.animationDuration=300;class Y extends N{constructor(){super(...arguments),this.detailsByOuterHTML=this.children.filter((e=>!function(e){const t=e.localName;return"noscript"==t}(e))).map((e=>function(e){e.hasAttribute("nonce")&&e.setAttribute("nonce","");return e}(e))).reduce(((e,t)=>{const{outerHTML:s}=t,i=s in e?e[s]:{type:J(t),tracked:G(t),elements:[]};return Object.assign(Object.assign({},e),{[s]:Object.assign(Object.assign({},i),{elements:[...i.elements,t]})})}),{})}get trackedElementSignature(){return Object.keys(this.detailsByOuterHTML).filter((e=>this.detailsByOuterHTML[e].tracked)).join("")}getScriptElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("script",e)}getStylesheetElementsNotInSnapshot(e){return this.getElementsMatchingTypeNotInSnapshot("stylesheet",e)}getElementsMatchingTypeNotInSnapshot(e,t){return Object.keys(this.detailsByOuterHTML).filter((e=>!(e in t.detailsByOuterHTML))).map((e=>this.detailsByOuterHTML[e])).filter((({type:t})=>t==e)).map((({elements:[e]})=>e))}get provisionalElements(){return Object.keys(this.detailsByOuterHTML).reduce(((e,t)=>{const{type:s,tracked:i,elements:r}=this.detailsByOuterHTML[t];return null!=s||i?r.length>1?[...e,...r.slice(1)]:e:[...e,...r]}),[])}getMetaValue(e){const t=this.findMetaElementByName(e);return t?t.getAttribute("content"):null}findMetaElementByName(e){return Object.keys(this.detailsByOuterHTML).reduce(((t,s)=>{const{elements:[i]}=this.detailsByOuterHTML[s];return function(e,t){const s=e.localName;return"meta"==s&&e.getAttribute("name")==t}(i,e)?i:t}),void 0)}}function J(e){return function(e){const t=e.localName;return"script"==t}(e)?"script":function(e){const t=e.localName;return"style"==t||"link"==t&&"stylesheet"==e.getAttribute("rel")}(e)?"stylesheet":void 0}function G(e){return"reload"==e.getAttribute("data-turbo-track")}class Z extends N{static fromHTMLString(e=""){return this.fromDocument(E(e))}static fromElement(e){return this.fromDocument(e.ownerDocument)}static fromDocument({head:e,body:t}){return new this(t,new Y(e))}constructor(e,t){super(e),this.headSnapshot=t}clone(){const e=this.element.cloneNode(!0),t=this.element.querySelectorAll("select"),s=e.querySelectorAll("select");for(const[e,i]of t.entries()){const t=s[e];for(const e of t.selectedOptions)e.selected=!1;for(const e of i.selectedOptions)t.options[e.index].selected=!0}for(const t of e.querySelectorAll('input[type="password"]'))t.value="";return new Z(e,this.headSnapshot)}get headElement(){return this.headSnapshot.element}get rootLocation(){var e;return h(null!==(e=this.getSetting("root"))&&void 0!==e?e:"/")}get cacheControlValue(){return this.getSetting("cache-control")}get isPreviewable(){return"no-preview"!=this.cacheControlValue}get isCacheable(){return"no-cache"!=this.cacheControlValue}get isVisitable(){return"reload"!=this.getSetting("visit-control")}getSetting(e){return this.headSnapshot.getMetaValue(`turbo-${e}`)}}!function(e){e.visitStart="visitStart",e.requestStart="requestStart",e.requestEnd="requestEnd",e.visitEnd="visitEnd"}(o||(o={})),function(e){e.initialized="initialized",e.started="started",e.canceled="canceled",e.failed="failed",e.completed="completed"}(a||(a={}));const ee={action:"advance",historyChanged:!1,visitCachedSnapshot:()=>{},willRender:!0,updateHistory:!0,shouldCacheSnapshot:!0,acceptsStreamResponse:!1};var te,se;!function(e){e[e.networkFailure=0]="networkFailure",e[e.timeoutFailure=-1]="timeoutFailure",e[e.contentTypeMismatch=-2]="contentTypeMismatch"}(te||(te={}));class ie{constructor(e,t,s,i={}){this.identifier=L(),this.timingMetrics={},this.followedRedirect=!1,this.historyChanged=!1,this.scrolled=!1,this.shouldCacheSnapshot=!0,this.acceptsStreamResponse=!1,this.snapshotCached=!1,this.state=a.initialized,this.delegate=e,this.location=t,this.restorationIdentifier=s||L();const{action:r,historyChanged:n,referrer:o,snapshot:l,snapshotHTML:h,response:c,visitCachedSnapshot:d,willRender:u,updateHistory:m,shouldCacheSnapshot:p,acceptsStreamResponse:g}=Object.assign(Object.assign({},ee),i);this.action=r,this.historyChanged=n,this.referrer=o,this.snapshot=l,this.snapshotHTML=h,this.response=c,this.isSamePage=this.delegate.locationWithActionIsSamePage(this.location,this.action),this.visitCachedSnapshot=d,this.willRender=u,this.updateHistory=m,this.scrolled=!u,this.shouldCacheSnapshot=p,this.acceptsStreamResponse=g}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}get restorationData(){return this.history.getRestorationDataForIdentifier(this.restorationIdentifier)}get silent(){return this.isSamePage}start(){this.state==a.initialized&&(this.recordTimingMetric(o.visitStart),this.state=a.started,this.adapter.visitStarted(this),this.delegate.visitStarted(this))}cancel(){this.state==a.started&&(this.request&&this.request.cancel(),this.cancelRender(),this.state=a.canceled)}complete(){this.state==a.started&&(this.recordTimingMetric(o.visitEnd),this.state=a.completed,this.followRedirect(),this.followedRedirect||(this.adapter.visitCompleted(this),this.delegate.visitCompleted(this)))}fail(){this.state==a.started&&(this.state=a.failed,this.adapter.visitFailed(this))}changeHistory(){var e;if(!this.historyChanged&&this.updateHistory){const t=P(this.location.href===(null===(e=this.referrer)||void 0===e?void 0:e.href)?"replace":this.action);this.history.update(t,this.location,this.restorationIdentifier),this.historyChanged=!0}}issueRequest(){this.hasPreloadedResponse()?this.simulateRequest():this.shouldIssueRequest()&&!this.request&&(this.request=new H(this,i.get,this.location),this.request.perform())}simulateRequest(){this.response&&(this.startRequest(),this.recordResponse(),this.finishRequest())}startRequest(){this.recordTimingMetric(o.requestStart),this.adapter.visitRequestStarted(this)}recordResponse(e=this.response){if(this.response=e,e){const{statusCode:t}=e;re(t)?this.adapter.visitRequestCompleted(this):this.adapter.visitRequestFailedWithStatusCode(this,t)}}finishRequest(){this.recordTimingMetric(o.requestEnd),this.adapter.visitRequestFinished(this)}loadResponse(){if(this.response){const{statusCode:e,responseHTML:t}=this.response;this.render((async()=>{this.shouldCacheSnapshot&&this.cacheSnapshot(),this.view.renderPromise&&await this.view.renderPromise,re(e)&&null!=t?(await this.view.renderPage(Z.fromHTMLString(t),!1,this.willRender,this),this.performScroll(),this.adapter.visitRendered(this),this.complete()):(await this.view.renderError(Z.fromHTMLString(t),this),this.adapter.visitRendered(this),this.fail())}))}}getCachedSnapshot(){const e=this.view.getCachedSnapshotForLocation(this.location)||this.getPreloadedSnapshot();if(e&&(!c(this.location)||e.hasAnchor(c(this.location)))&&("restore"==this.action||e.isPreviewable))return e}getPreloadedSnapshot(){if(this.snapshotHTML)return Z.fromHTMLString(this.snapshotHTML)}hasCachedSnapshot(){return null!=this.getCachedSnapshot()}loadCachedSnapshot(){const e=this.getCachedSnapshot();if(e){const t=this.shouldIssueRequest();this.render((async()=>{this.cacheSnapshot(),this.isSamePage?this.adapter.visitRendered(this):(this.view.renderPromise&&await this.view.renderPromise,await this.view.renderPage(e,t,this.willRender,this),this.performScroll(),this.adapter.visitRendered(this),t||this.complete())}))}}followRedirect(){var e;this.redirectedToLocation&&!this.followedRedirect&&(null===(e=this.response)||void 0===e?void 0:e.redirected)&&(this.adapter.visitProposedToLocation(this.redirectedToLocation,{action:"replace",response:this.response,shouldCacheSnapshot:!1,willRender:!1}),this.followedRedirect=!0)}goToSamePageAnchor(){this.isSamePage&&this.render((async()=>{this.cacheSnapshot(),this.performScroll(),this.changeHistory(),this.adapter.visitRendered(this)}))}prepareRequest(e){this.acceptsStreamResponse&&e.acceptResponseType(B.contentType)}requestStarted(){this.startRequest()}requestPreventedHandlingResponse(e,t){}async requestSucceededWithResponse(e,t){const s=await t.responseHTML,{redirected:i,statusCode:r}=t;null==s?this.recordResponse({statusCode:te.contentTypeMismatch,redirected:i}):(this.redirectedToLocation=t.redirected?t.location:void 0,this.recordResponse({statusCode:r,responseHTML:s,redirected:i}))}async requestFailedWithResponse(e,t){const s=await t.responseHTML,{redirected:i,statusCode:r}=t;null==s?this.recordResponse({statusCode:te.contentTypeMismatch,redirected:i}):this.recordResponse({statusCode:r,responseHTML:s,redirected:i})}requestErrored(e,t){this.recordResponse({statusCode:te.networkFailure,redirected:!1})}requestFinished(){this.finishRequest()}performScroll(){this.scrolled||this.view.forceReloaded||("restore"==this.action?this.scrollToRestoredPosition()||this.scrollToAnchor()||this.view.scrollToTop():this.scrollToAnchor()||this.view.scrollToTop(),this.isSamePage&&this.delegate.visitScrolledToSamePageLocation(this.view.lastRenderedLocation,this.location),this.scrolled=!0)}scrollToRestoredPosition(){const{scrollPosition:e}=this.restorationData;if(e)return this.view.scrollToPosition(e),!0}scrollToAnchor(){const e=c(this.location);if(null!=e)return this.view.scrollToAnchor(e),!0}recordTimingMetric(e){this.timingMetrics[e]=(new Date).getTime()}getTimingMetrics(){return Object.assign({},this.timingMetrics)}getHistoryMethodForAction(e){switch(e){case"replace":return history.replaceState;case"advance":case"restore":return history.pushState}}hasPreloadedResponse(){return"object"==typeof this.response}shouldIssueRequest(){return!this.isSamePage&&("restore"==this.action?!this.hasCachedSnapshot():this.willRender)}cacheSnapshot(){this.snapshotCached||(this.view.cacheSnapshot(this.snapshot).then((e=>e&&this.visitCachedSnapshot(e))),this.snapshotCached=!0)}async render(e){this.cancelRender(),await new Promise((e=>{this.frame=requestAnimationFrame((()=>e()))})),await e(),delete this.frame}cancelRender(){this.frame&&(cancelAnimationFrame(this.frame),delete this.frame)}}function re(e){return e>=200&&e<300}class ne{constructor(e){this.progressBar=new X,this.showProgressBar=()=>{this.progressBar.show()},this.session=e}visitProposedToLocation(e,t){this.navigator.startVisit(e,(null==t?void 0:t.restorationIdentifier)||L(),t)}visitStarted(e){this.location=e.location,e.loadCachedSnapshot(),e.issueRequest(),e.goToSamePageAnchor()}visitRequestStarted(e){this.progressBar.setValue(0),e.hasCachedSnapshot()||"restore"!=e.action?this.showVisitProgressBarAfterDelay():this.showProgressBar()}visitRequestCompleted(e){e.loadResponse()}visitRequestFailedWithStatusCode(e,t){switch(t){case te.networkFailure:case te.timeoutFailure:case te.contentTypeMismatch:return this.reload({reason:"request_failed",context:{statusCode:t}});default:return e.loadResponse()}}visitRequestFinished(e){this.progressBar.setValue(1),this.hideVisitProgressBar()}visitCompleted(e){}pageInvalidated(e){this.reload(e)}visitFailed(e){}visitRendered(e){}formSubmissionStarted(e){this.progressBar.setValue(0),this.showFormProgressBarAfterDelay()}formSubmissionFinished(e){this.progressBar.setValue(1),this.hideFormProgressBar()}showVisitProgressBarAfterDelay(){this.visitProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay)}hideVisitProgressBar(){this.progressBar.hide(),null!=this.visitProgressBarTimeout&&(window.clearTimeout(this.visitProgressBarTimeout),delete this.visitProgressBarTimeout)}showFormProgressBarAfterDelay(){null==this.formProgressBarTimeout&&(this.formProgressBarTimeout=window.setTimeout(this.showProgressBar,this.session.progressBarDelay))}hideFormProgressBar(){this.progressBar.hide(),null!=this.formProgressBarTimeout&&(window.clearTimeout(this.formProgressBarTimeout),delete this.formProgressBarTimeout)}reload(e){var t;w("turbo:reload",{detail:e}),window.location.href=(null===(t=this.location)||void 0===t?void 0:t.toString())||window.location.href}get navigator(){return this.session.navigator}}class oe{constructor(){this.selector="[data-turbo-temporary]",this.deprecatedSelector="[data-turbo-cache=false]",this.started=!1,this.removeTemporaryElements=e=>{for(const e of this.temporaryElements)e.remove()}}start(){this.started||(this.started=!0,addEventListener("turbo:before-cache",this.removeTemporaryElements,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-cache",this.removeTemporaryElements,!1))}get temporaryElements(){return[...document.querySelectorAll(this.selector),...this.temporaryElementsWithDeprecation]}get temporaryElementsWithDeprecation(){const e=document.querySelectorAll(this.deprecatedSelector);return e.length&&console.warn(`The ${this.deprecatedSelector} selector is deprecated and will be removed in a future version. Use ${this.selector} instead.`),[...e]}}class ae{constructor(e,t){this.session=e,this.element=t,this.linkInterceptor=new j(this,t),this.formSubmitObserver=new D(this,t)}start(){this.linkInterceptor.start(),this.formSubmitObserver.start()}stop(){this.linkInterceptor.stop(),this.formSubmitObserver.stop()}shouldInterceptLinkClick(e,t,s){return this.shouldRedirect(e)}linkClickIntercepted(e,t,s){const i=this.findFrameElement(e);i&&i.delegate.linkClickIntercepted(e,t,s)}willSubmitForm(e,t){return null==e.closest("turbo-frame")&&this.shouldSubmit(e,t)&&this.shouldRedirect(e,t)}formSubmitted(e,t){const s=this.findFrameElement(e,t);s&&s.delegate.formSubmitted(e,t)}shouldSubmit(e,t){var s;const i=d(e,t),r=this.element.ownerDocument.querySelector('meta[name="turbo-root"]'),n=h(null!==(s=null==r?void 0:r.content)&&void 0!==s?s:"/");return this.shouldRedirect(e,t)&&p(i,n)}shouldRedirect(e,t){if(e instanceof HTMLFormElement?this.session.submissionIsNavigatable(e,t):this.session.elementIsNavigatable(e)){const s=this.findFrameElement(e,t);return!!s&&s!=e.closest("turbo-frame")}return!1}findFrameElement(e,t){const s=(null==t?void 0:t.getAttribute("data-turbo-frame"))||e.getAttribute("data-turbo-frame");if(s&&"_top"!=s){const e=this.element.querySelector(`#${s}:not([disabled])`);if(e instanceof l)return e}}}class le{constructor(e){this.restorationIdentifier=L(),this.restorationData={},this.started=!1,this.pageLoaded=!1,this.onPopState=e=>{if(this.shouldHandlePopState()){const{turbo:t}=e.state||{};if(t){this.location=new URL(window.location.href);const{restorationIdentifier:e}=t;this.restorationIdentifier=e,this.delegate.historyPoppedToLocationWithRestorationIdentifier(this.location,e)}}},this.onPageLoad=async e=>{await Promise.resolve(),this.pageLoaded=!0},this.delegate=e}start(){this.started||(addEventListener("popstate",this.onPopState,!1),addEventListener("load",this.onPageLoad,!1),this.started=!0,this.replace(new URL(window.location.href)))}stop(){this.started&&(removeEventListener("popstate",this.onPopState,!1),removeEventListener("load",this.onPageLoad,!1),this.started=!1)}push(e,t){this.update(history.pushState,e,t)}replace(e,t){this.update(history.replaceState,e,t)}update(e,t,s=L()){const i={turbo:{restorationIdentifier:s}};e.call(history,i,"",t.href),this.location=t,this.restorationIdentifier=s}getRestorationDataForIdentifier(e){return this.restorationData[e]||{}}updateRestorationData(e){const{restorationIdentifier:t}=this,s=this.restorationData[t];this.restorationData[t]=Object.assign(Object.assign({},s),e)}assumeControlOfScrollRestoration(){var e;this.previousScrollRestoration||(this.previousScrollRestoration=null!==(e=history.scrollRestoration)&&void 0!==e?e:"auto",history.scrollRestoration="manual")}relinquishControlOfScrollRestoration(){this.previousScrollRestoration&&(history.scrollRestoration=this.previousScrollRestoration,delete this.previousScrollRestoration)}shouldHandlePopState(){return this.pageIsLoaded()}pageIsLoaded(){return this.pageLoaded||"complete"==document.readyState}}class he{constructor(e){this.delegate=e}proposeVisit(e,t={}){this.delegate.allowsVisitingLocationWithAction(e,t.action)&&(p(e,this.view.snapshot.rootLocation)?this.delegate.visitProposedToLocation(e,t):window.location.href=e.toString())}startVisit(e,t,s={}){this.stop(),this.currentVisit=new ie(this,h(e),t,Object.assign({referrer:this.location},s)),this.currentVisit.start()}submitForm(e,t){this.stop(),this.formSubmission=new O(this,e,t,!0),this.formSubmission.start()}stop(){this.formSubmission&&(this.formSubmission.stop(),delete this.formSubmission),this.currentVisit&&(this.currentVisit.cancel(),delete this.currentVisit)}get adapter(){return this.delegate.adapter}get view(){return this.delegate.view}get history(){return this.delegate.history}formSubmissionStarted(e){"function"==typeof this.adapter.formSubmissionStarted&&this.adapter.formSubmissionStarted(e)}async formSubmissionSucceededWithResponse(e,t){if(e==this.formSubmission){const s=await t.responseHTML;if(s){const i=e.isSafe;i||this.view.clearSnapshotCache();const{statusCode:r,redirected:n}=t,o={action:this.getActionForFormSubmission(e),shouldCacheSnapshot:i,response:{statusCode:r,responseHTML:s,redirected:n}};this.proposeVisit(t.location,o)}}}async formSubmissionFailedWithResponse(e,t){const s=await t.responseHTML;if(s){const e=Z.fromHTMLString(s);t.serverError?await this.view.renderError(e,this.currentVisit):await this.view.renderPage(e,!1,!0,this.currentVisit),this.view.scrollToTop(),this.view.clearSnapshotCache()}}formSubmissionErrored(e,t){console.error(t)}formSubmissionFinished(e){"function"==typeof this.adapter.formSubmissionFinished&&this.adapter.formSubmissionFinished(e)}visitStarted(e){this.delegate.visitStarted(e)}visitCompleted(e){this.delegate.visitCompleted(e)}locationWithActionIsSamePage(e,t){const s=c(e),i=c(this.view.lastRenderedLocation),r="restore"===t&&void 0===s;return"replace"!==t&&g(e)===g(this.view.lastRenderedLocation)&&(r||null!=s&&s!==i)}visitScrolledToSamePageLocation(e,t){this.delegate.visitScrolledToSamePageLocation(e,t)}get location(){return this.history.location}get restorationIdentifier(){return this.history.restorationIdentifier}getActionForFormSubmission({submitter:e,formElement:t}){return F(e,t)||"advance"}}!function(e){e[e.initial=0]="initial",e[e.loading=1]="loading",e[e.interactive=2]="interactive",e[e.complete=3]="complete"}(se||(se={}));class ce{constructor(e){this.stage=se.initial,this.started=!1,this.interpretReadyState=()=>{const{readyState:e}=this;"interactive"==e?this.pageIsInteractive():"complete"==e&&this.pageIsComplete()},this.pageWillUnload=()=>{this.delegate.pageWillUnload()},this.delegate=e}start(){this.started||(this.stage==se.initial&&(this.stage=se.loading),document.addEventListener("readystatechange",this.interpretReadyState,!1),addEventListener("pagehide",this.pageWillUnload,!1),this.started=!0)}stop(){this.started&&(document.removeEventListener("readystatechange",this.interpretReadyState,!1),removeEventListener("pagehide",this.pageWillUnload,!1),this.started=!1)}pageIsInteractive(){this.stage==se.loading&&(this.stage=se.interactive,this.delegate.pageBecameInteractive())}pageIsComplete(){this.pageIsInteractive(),this.stage==se.interactive&&(this.stage=se.complete,this.delegate.pageLoaded())}get readyState(){return document.readyState}}class de{constructor(e){this.started=!1,this.onScroll=()=>{this.updatePosition({x:window.pageXOffset,y:window.pageYOffset})},this.delegate=e}start(){this.started||(addEventListener("scroll",this.onScroll,!1),this.onScroll(),this.started=!0)}stop(){this.started&&(removeEventListener("scroll",this.onScroll,!1),this.started=!1)}updatePosition(e){this.delegate.scrollPositionChanged(e)}}class ue{render({fragment:e}){_.preservingPermanentElements(this,function(e){const t=W(document.documentElement),s={};for(const i of t){const{id:t}=i;for(const r of e.querySelectorAll("turbo-stream")){const e=V(r.templateElement.content,t);e&&(s[t]=[i,e])}}return s}(e),(()=>document.documentElement.appendChild(e)))}enteringBardo(e,t){t.replaceWith(e.cloneNode(!0))}leavingBardo(){}}class me{constructor(e){this.sources=new Set,this.started=!1,this.inspectFetchResponse=e=>{const t=function(e){var t;const s=null===(t=e.detail)||void 0===t?void 0:t.fetchResponse;if(s instanceof v)return s}(e);t&&function(e){var t;const s=null!==(t=e.contentType)&&void 0!==t?t:"";return s.startsWith(B.contentType)}(t)&&(e.preventDefault(),this.receiveMessageResponse(t))},this.receiveMessageEvent=e=>{this.started&&"string"==typeof e.data&&this.receiveMessageHTML(e.data)},this.delegate=e}start(){this.started||(this.started=!0,addEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}stop(){this.started&&(this.started=!1,removeEventListener("turbo:before-fetch-response",this.inspectFetchResponse,!1))}connectStreamSource(e){this.streamSourceIsConnected(e)||(this.sources.add(e),e.addEventListener("message",this.receiveMessageEvent,!1))}disconnectStreamSource(e){this.streamSourceIsConnected(e)&&(this.sources.delete(e),e.removeEventListener("message",this.receiveMessageEvent,!1))}streamSourceIsConnected(e){return this.sources.has(e)}async receiveMessageResponse(e){const t=await e.responseHTML;t&&this.receiveMessageHTML(t)}receiveMessageHTML(e){this.delegate.receivedMessageFromStream(B.wrap(e))}}class pe extends K{static renderElement(e,t){const{documentElement:s,body:i}=document;s.replaceChild(t,i)}async render(){this.replaceHeadAndBody(),this.activateScriptElements()}replaceHeadAndBody(){const{documentElement:e,head:t}=document;e.replaceChild(this.newHead,t),this.renderElement(this.currentElement,this.newElement)}activateScriptElements(){for(const e of this.scriptElements){const t=e.parentNode;if(t){const s=b(e);t.replaceChild(s,e)}}}get newHead(){return this.newSnapshot.headSnapshot.element}get scriptElements(){return document.documentElement.querySelectorAll("script")}}class ge extends K{static renderElement(e,t){document.body&&t instanceof HTMLBodyElement?document.body.replaceWith(t):document.documentElement.appendChild(t)}get shouldRender(){return this.newSnapshot.isVisitable&&this.trackedElementsAreIdentical}get reloadReason(){return this.newSnapshot.isVisitable?this.trackedElementsAreIdentical?void 0:{reason:"tracked_element_mismatch"}:{reason:"turbo_visit_control_is_reload"}}async prepareToRender(){await this.mergeHead()}async render(){this.willRender&&await this.replaceBody()}finishRendering(){super.finishRendering(),this.isPreview||this.focusFirstAutofocusableElement()}get currentHeadSnapshot(){return this.currentSnapshot.headSnapshot}get newHeadSnapshot(){return this.newSnapshot.headSnapshot}get newElement(){return this.newSnapshot.element}async mergeHead(){const e=this.mergeProvisionalElements(),t=this.copyNewHeadStylesheetElements();this.copyNewHeadScriptElements(),await e,await t}async replaceBody(){await this.preservingPermanentElements((async()=>{this.activateNewBody(),await this.assignNewBody()}))}get trackedElementsAreIdentical(){return this.currentHeadSnapshot.trackedElementSignature==this.newHeadSnapshot.trackedElementSignature}async copyNewHeadStylesheetElements(){const e=[];for(const t of this.newHeadStylesheetElements)e.push(A(t)),document.head.appendChild(t);await Promise.all(e)}copyNewHeadScriptElements(){for(const e of this.newHeadScriptElements)document.head.appendChild(b(e))}async mergeProvisionalElements(){const e=[...this.newHeadProvisionalElements];for(const t of this.currentHeadProvisionalElements)this.isCurrentElementInElementList(t,e)||document.head.removeChild(t);for(const t of e)document.head.appendChild(t)}isCurrentElementInElementList(e,t){for(const[s,i]of t.entries()){if("TITLE"==e.tagName){if("TITLE"!=i.tagName)continue;if(e.innerHTML==i.innerHTML)return t.splice(s,1),!0}if(i.isEqualNode(e))return t.splice(s,1),!0}return!1}removeCurrentHeadProvisionalElements(){for(const e of this.currentHeadProvisionalElements)document.head.removeChild(e)}copyNewHeadProvisionalElements(){for(const e of this.newHeadProvisionalElements)document.head.appendChild(e)}activateNewBody(){document.adoptNode(this.newElement),this.activateNewBodyScriptElements()}activateNewBodyScriptElements(){for(const e of this.newBodyScriptElements){const t=b(e);e.replaceWith(t)}}async assignNewBody(){await this.renderElement(this.currentElement,this.newElement)}get newHeadStylesheetElements(){return this.newHeadSnapshot.getStylesheetElementsNotInSnapshot(this.currentHeadSnapshot)}get newHeadScriptElements(){return this.newHeadSnapshot.getScriptElementsNotInSnapshot(this.currentHeadSnapshot)}get currentHeadProvisionalElements(){return this.currentHeadSnapshot.provisionalElements}get newHeadProvisionalElements(){return this.newHeadSnapshot.provisionalElements}get newBodyScriptElements(){return this.newElement.querySelectorAll("script")}}class fe{constructor(e){this.keys=[],this.snapshots={},this.size=e}has(e){return f(e)in this.snapshots}get(e){if(this.has(e)){const t=this.read(e);return this.touch(e),t}}put(e,t){return this.write(e,t),this.touch(e),t}clear(){this.snapshots={}}read(e){return this.snapshots[f(e)]}write(e,t){this.snapshots[f(e)]=t}touch(e){const t=f(e),s=this.keys.indexOf(t);s>-1&&this.keys.splice(s,1),this.keys.unshift(t),this.trim()}trim(){for(const e of this.keys.splice(this.size))delete this.snapshots[e]}}class ve extends x{constructor(){super(...arguments),this.snapshotCache=new fe(10),this.lastRenderedLocation=new URL(location.href),this.forceReloaded=!1}renderPage(e,t=!1,s=!0,i){const r=new ge(this.snapshot,e,ge.renderElement,t,s);return r.shouldRender?null==i||i.changeHistory():this.forceReloaded=!0,this.render(r)}renderError(e,t){null==t||t.changeHistory();const s=new pe(this.snapshot,e,pe.renderElement,!1);return this.render(s)}clearSnapshotCache(){this.snapshotCache.clear()}async cacheSnapshot(e=this.snapshot){if(e.isCacheable){this.delegate.viewWillCacheSnapshot();const{lastRenderedLocation:t}=this;await new Promise((e=>setTimeout((()=>e()),0)));const s=e.clone();return this.snapshotCache.put(t,s),s}}getCachedSnapshotForLocation(e){return this.snapshotCache.get(e)}get snapshot(){return Z.fromElement(this.element)}}class be{constructor(e){this.selector="a[data-turbo-preload]",this.delegate=e}get snapshotCache(){return this.delegate.navigator.view.snapshotCache}start(){if("loading"===document.readyState)return document.addEventListener("DOMContentLoaded",(()=>{this.preloadOnLoadLinksForView(document.body)}));this.preloadOnLoadLinksForView(document.body)}preloadOnLoadLinksForView(e){for(const t of e.querySelectorAll(this.selector))this.preloadURL(t)}async preloadURL(e){const t=new URL(e.href);if(!this.snapshotCache.has(t))try{const e=await fetch(t.toString(),{headers:{"VND.PREFETCH":"true",Accept:"text/html"}}),s=await e.text(),i=Z.fromHTMLString(s);this.snapshotCache.put(t,i)}catch(e){}}}function we(e){Object.defineProperties(e,Se)}const Se={absoluteURL:{get(){return this.toString()}}};const Ee={after(){this.targetElements.forEach((e=>{var t;return null===(t=e.parentElement)||void 0===t?void 0:t.insertBefore(this.templateContent,e.nextSibling)}))},append(){this.removeDuplicateTargetChildren(),this.targetElements.forEach((e=>e.append(this.templateContent)))},before(){this.targetElements.forEach((e=>{var t;return null===(t=e.parentElement)||void 0===t?void 0:t.insertBefore(this.templateContent,e)}))},prepend(){this.removeDuplicateTargetChildren(),this.targetElements.forEach((e=>e.prepend(this.templateContent)))},remove(){this.targetElements.forEach((e=>e.remove()))},replace(){this.targetElements.forEach((e=>e.replaceWith(this.templateContent)))},update(){this.targetElements.forEach((e=>{e.innerHTML="",e.append(this.templateContent)}))}},ye=new class{constructor(){this.navigator=new he(this),this.history=new le(this),this.preloader=new be(this),this.view=new ve(this,document.documentElement),this.adapter=new ne(this),this.pageObserver=new ce(this),this.cacheObserver=new oe,this.linkClickObserver=new $(this,window),this.formSubmitObserver=new D(this,document),this.scrollObserver=new de(this),this.streamObserver=new me(this),this.formLinkClickObserver=new z(this,document.documentElement),this.frameRedirector=new ae(this,document.documentElement),this.streamMessageRenderer=new ue,this.drive=!0,this.enabled=!0,this.progressBarDelay=500,this.started=!1,this.formMode="on"}start(){this.started||(this.pageObserver.start(),this.cacheObserver.start(),this.formLinkClickObserver.start(),this.linkClickObserver.start(),this.formSubmitObserver.start(),this.scrollObserver.start(),this.streamObserver.start(),this.frameRedirector.start(),this.history.start(),this.preloader.start(),this.started=!0,this.enabled=!0)}disable(){this.enabled=!1}stop(){this.started&&(this.pageObserver.stop(),this.cacheObserver.stop(),this.formLinkClickObserver.stop(),this.linkClickObserver.stop(),this.formSubmitObserver.stop(),this.scrollObserver.stop(),this.streamObserver.stop(),this.frameRedirector.stop(),this.history.stop(),this.started=!1)}registerAdapter(e){this.adapter=e}visit(e,t={}){const s=t.frame?document.getElementById(t.frame):null;s instanceof l?(s.src=e.toString(),s.loaded):this.navigator.proposeVisit(h(e),t)}connectStreamSource(e){this.streamObserver.connectStreamSource(e)}disconnectStreamSource(e){this.streamObserver.disconnectStreamSource(e)}renderStreamMessage(e){this.streamMessageRenderer.render(B.wrap(e))}clearCache(){this.view.clearSnapshotCache()}setProgressBarDelay(e){this.progressBarDelay=e}setFormMode(e){this.formMode=e}get location(){return this.history.location}get restorationIdentifier(){return this.history.restorationIdentifier}historyPoppedToLocationWithRestorationIdentifier(e,t){this.enabled?this.navigator.startVisit(e,t,{action:"restore",historyChanged:!0}):this.adapter.pageInvalidated({reason:"turbo_disabled"})}scrollPositionChanged(e){this.history.updateRestorationData({scrollPosition:e})}willSubmitFormLinkToLocation(e,t){return this.elementIsNavigatable(e)&&p(t,this.snapshot.rootLocation)}submittedFormLinkToLocation(){}willFollowLinkToLocation(e,t,s){return this.elementIsNavigatable(e)&&p(t,this.snapshot.rootLocation)&&this.applicationAllowsFollowingLinkToLocation(e,t,s)}followedLinkToLocation(e,t){const s=this.getActionForLink(e),i=e.hasAttribute("data-turbo-stream");this.visit(t.href,{action:s,acceptsStreamResponse:i})}allowsVisitingLocationWithAction(e,t){return this.locationWithActionIsSamePage(e,t)||this.applicationAllowsVisitingLocation(e)}visitProposedToLocation(e,t){we(e),this.adapter.visitProposedToLocation(e,t)}visitStarted(e){e.acceptsStreamResponse||C(document.documentElement),we(e.location),e.silent||this.notifyApplicationAfterVisitingLocation(e.location,e.action)}visitCompleted(e){T(document.documentElement),this.notifyApplicationAfterPageLoad(e.getTimingMetrics())}locationWithActionIsSamePage(e,t){return this.navigator.locationWithActionIsSamePage(e,t)}visitScrolledToSamePageLocation(e,t){this.notifyApplicationAfterVisitingSamePageLocation(e,t)}willSubmitForm(e,t){const s=d(e,t);return this.submissionIsNavigatable(e,t)&&p(h(s),this.snapshot.rootLocation)}formSubmitted(e,t){this.navigator.submitForm(e,t)}pageBecameInteractive(){this.view.lastRenderedLocation=this.location,this.notifyApplicationAfterPageLoad()}pageLoaded(){this.history.assumeControlOfScrollRestoration()}pageWillUnload(){this.history.relinquishControlOfScrollRestoration()}receivedMessageFromStream(e){this.renderStreamMessage(e)}viewWillCacheSnapshot(){var e;(null===(e=this.navigator.currentVisit)||void 0===e?void 0:e.silent)||this.notifyApplicationBeforeCachingSnapshot()}allowsImmediateRender({element:e},t){const s=this.notifyApplicationBeforeRender(e,t),{defaultPrevented:i,detail:{render:r}}=s;return this.view.renderer&&r&&(this.view.renderer.renderElement=r),!i}viewRenderedSnapshot(e,t){this.view.lastRenderedLocation=this.history.location,this.notifyApplicationAfterRender()}preloadOnLoadLinksForView(e){this.preloader.preloadOnLoadLinksForView(e)}viewInvalidated(e){this.adapter.pageInvalidated(e)}frameLoaded(e){this.notifyApplicationAfterFrameLoad(e)}frameRendered(e,t){this.notifyApplicationAfterFrameRender(e,t)}applicationAllowsFollowingLinkToLocation(e,t,s){return!this.notifyApplicationAfterClickingLinkToLocation(e,t,s).defaultPrevented}applicationAllowsVisitingLocation(e){return!this.notifyApplicationBeforeVisitingLocation(e).defaultPrevented}notifyApplicationAfterClickingLinkToLocation(e,t,s){return w("turbo:click",{target:e,detail:{url:t.href,originalEvent:s},cancelable:!0})}notifyApplicationBeforeVisitingLocation(e){return w("turbo:before-visit",{detail:{url:e.href},cancelable:!0})}notifyApplicationAfterVisitingLocation(e,t){return w("turbo:visit",{detail:{url:e.href,action:t}})}notifyApplicationBeforeCachingSnapshot(){return w("turbo:before-cache")}notifyApplicationBeforeRender(e,t){return w("turbo:before-render",{detail:Object.assign({newBody:e},t),cancelable:!0})}notifyApplicationAfterRender(){return w("turbo:render")}notifyApplicationAfterPageLoad(e={}){return w("turbo:load",{detail:{url:this.location.href,timing:e}})}notifyApplicationAfterVisitingSamePageLocation(e,t){dispatchEvent(new HashChangeEvent("hashchange",{oldURL:e.toString(),newURL:t.toString()}))}notifyApplicationAfterFrameLoad(e){return w("turbo:frame-load",{target:e})}notifyApplicationAfterFrameRender(e,t){return w("turbo:frame-render",{detail:{fetchResponse:e},target:t,cancelable:!0})}submissionIsNavigatable(e,t){if("off"==this.formMode)return!1;{const s=!t||this.elementIsNavigatable(t);return"optin"==this.formMode?s&&null!=e.closest('[data-turbo="true"]'):s&&this.elementIsNavigatable(e)}}elementIsNavigatable(e){const t=I(e,"[data-turbo]"),s=I(e,"turbo-frame");return this.drive||s?!t||"false"!=t.getAttribute("data-turbo"):!!t&&"true"==t.getAttribute("data-turbo")}getActionForLink(e){return F(e)||"advance"}get snapshot(){return this.view.snapshot}},Le=new class{constructor(e){this.session=e}clear(){this.session.clearCache()}resetCacheControl(){this.setCacheControl("")}exemptPageFromCache(){this.setCacheControl("no-cache")}exemptPageFromPreview(){this.setCacheControl("no-preview")}setCacheControl(e){!function(e,t){let s=k(e);s||(s=document.createElement("meta"),s.setAttribute("name",e),document.head.appendChild(s)),s.setAttribute("content",t)}("turbo-cache-control",e)}}(ye),{navigator:Re}=ye;function Ce(){ye.start()}function Te(e){ye.registerAdapter(e)}function Ae(e,t){ye.visit(e,t)}function Pe(e){ye.connectStreamSource(e)}function Fe(e){ye.disconnectStreamSource(e)}function ke(e){ye.renderStreamMessage(e)}function Me(){console.warn("Please replace `Turbo.clearCache()` with `Turbo.cache.clear()`. The top-level function is deprecated and will be removed in a future version of Turbo.`"),ye.clearCache()}function Ie(e){ye.setProgressBarDelay(e)}function He(e){O.confirmMethod=e}function qe(e){ye.setFormMode(e)}var Be=Object.freeze({__proto__:null,navigator:Re,session:ye,cache:Le,PageRenderer:ge,PageSnapshot:Z,FrameRenderer:Q,start:Ce,registerAdapter:Te,visit:Ae,connectStreamSource:Pe,disconnectStreamSource:Fe,renderStreamMessage:ke,clearCache:Me,setProgressBarDelay:Ie,setConfirmMethod:He,setFormMode:qe,StreamActions:Ee});class Oe extends Error{}function Ne(e){if(null!=e){const t=document.getElementById(e);if(t instanceof l)return t}}function Ve(e,t){if(e){const i=e.getAttribute("src");if(null!=i&&null!=t&&(s=t,h(i).href==h(s).href))throw new Error(`Matching element has a source URL which references itself`);if(e.ownerDocument!==document&&(e=document.importNode(e,!0)),e instanceof l)return e.connectedCallback(),e.disconnectedCallback(),e}var s}class We extends HTMLElement{static async renderElement(e){await e.performAction()}async connectedCallback(){try{await this.render()}catch(e){console.error(e)}finally{this.disconnect()}}async render(){var e;return null!==(e=this.renderPromise)&&void 0!==e?e:this.renderPromise=(async()=>{const e=this.beforeRenderEvent;this.dispatchEvent(e)&&(await S(),await e.detail.render(this))})()}disconnect(){try{this.remove()}catch(e){}}removeDuplicateTargetChildren(){this.duplicateChildren.forEach((e=>e.remove()))}get duplicateChildren(){var e;const t=this.targetElements.flatMap((e=>[...e.children])).filter((e=>!!e.id)),s=[...(null===(e=this.templateContent)||void 0===e?void 0:e.children)||[]].filter((e=>!!e.id)).map((e=>e.id));return t.filter((e=>s.includes(e.id)))}get performAction(){if(this.action){const e=Ee[this.action];if(e)return e;this.raise("unknown action")}this.raise("action attribute is missing")}get targetElements(){return this.target?this.targetElementsById:this.targets?this.targetElementsByQuery:void this.raise("target or targets attribute is missing")}get templateContent(){return this.templateElement.content.cloneNode(!0)}get templateElement(){if(null===this.firstElementChild){const e=this.ownerDocument.createElement("template");return this.appendChild(e),e}if(this.firstElementChild instanceof HTMLTemplateElement)return this.firstElementChild;this.raise("first child element must be a