1
0
Fork 0
mirror of https://github.com/wallabag/wallabag.git synced 2025-09-30 19:22:12 +00:00
This commit is contained in:
Harm te Molder 2025-08-21 10:21:22 +02:00
commit c91a0fa8f5
No known key found for this signature in database
GPG key ID: 74A98B5EEF1920BA
465 changed files with 11366 additions and 10396 deletions

View file

@ -1,10 +0,0 @@
{
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
]
]
}

View file

@ -1,6 +1,9 @@
{
"extends": "airbnb-base",
"parser": "@babel/eslint-parser",
"parserOptions": {
"requireConfigFile": false
},
"env": {
"browser": true,
"es6": true

2
.github/CODEOWNERS vendored Normal file
View file

@ -0,0 +1,2 @@
# Migrated rules from dependabot.yml
composer.* @Kdecherf @j0k3r @yguedidi

View file

@ -24,7 +24,7 @@ If you want to test using an other database than SQLite, uncomment the `postgres
### Using your own PHP server
- Ensure you are running PHP >= 7.4.
- Ensure you are running PHP >= 8.2.
- Clone the repository
- Launch `composer install`
- If you got some errors, fix them (they might be related to some missing PHP extension from your machine)
@ -55,3 +55,7 @@ To run the tests locally run `make test`.
To run the PHP formatter run `make fix-cs`.
To run the PHPStan static analysis run `make phpstan`.
To run the JS linter run `make lint-js`.
To run the SCSS linter run `make lint-scss`.

View file

@ -15,13 +15,13 @@ updates:
patterns:
- "*fontsource*"
ignore:
- dependency-name: materialize-css
- dependency-name: "@materializecss/materialize"
versions:
- "> 0.98.2"
- "> 1.2.2"
- package-ecosystem: composer
directory: "/"
schedule:
interval: daily
interval: weekly
time: "04:00"
timezone: Europe/Paris
open-pull-requests-limit: 10
@ -35,18 +35,9 @@ updates:
phpstan-dependencies:
patterns:
- "phpstan/*"
reviewers:
- j0k3r
- yguedidi
- Kdecherf
ignore:
- dependency-name: lcobucci/jwt
versions:
- ">= 4.2.0"
# until we add support for Symfony 5+
- dependency-name: symfony/*
versions:
- ">= 5.0.0"
update-types: [ "version-update:semver-major" ]
- package-ecosystem: github-actions
directory: "/"
schedule:

View file

@ -13,23 +13,29 @@ permissions:
jobs:
coding-standards:
name: "CS Fixer, PHPStan & TwigCS"
runs-on: "ubuntu-20.04"
runs-on: ubuntu-latest
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"
with:
coverage: "none"
php-version: "7.4"
php-version: "8.2"
tools: cs2pr, pecl
extensions: pdo, pdo_mysql, pdo_sqlite, pdo_pgsql, curl, imagick, pgsql, gd, tidy
ini-values: "date.timezone=Europe/Paris"
env:
COMPOSER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: "Install Node"
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: 'yarn'
- name: "Setup MySQL"
run: |
sudo systemctl start mysql.service
@ -37,24 +43,48 @@ jobs:
cp app/config/tests/parameters_test.mysql.yml app/config/parameters_test.yml
- name: "Install dependencies with Composer"
id: composer-install
uses: "ramsey/composer-install@v3"
with:
composer-options: "--optimize-autoloader --prefer-dist"
- name: "Install dependencies with Yarn"
id: yarn-install
run: yarn install
- name: "Run Composer validate"
if: always() && steps.composer-install.outcome == 'success'
run: "composer validate"
- name: "Run Composer dependency analyser"
if: always() && steps.composer-install.outcome == 'success'
run: "bin/composer-dependency-analyser"
- name: "Run PHP CS Fixer"
if: always() && steps.composer-install.outcome == 'success'
run: "bin/php-cs-fixer fix --verbose --dry-run --format=checkstyle | cs2pr"
- name: "Generate test cache for PHPStan"
id: test-cache
if: always() && steps.composer-install.outcome == 'success'
run: "php bin/console cache:clear --env=test"
- name: "Run PHPStan"
if: always() && steps.test-cache.outcome == 'success'
run: "php bin/phpstan analyse --no-progress --error-format=checkstyle | cs2pr"
- name: "Run TwigCS"
if: always() && steps.composer-install.outcome == 'success'
run: "php bin/twigcs --severity=error --display=blocking --reporter checkstyle app/ src/ | cs2pr"
- name: "Run ergebnis/composer-normalize"
if: always() && steps.composer-install.outcome == 'success'
run: "composer normalize --dry-run --no-check-lock"
- name: "Run ESLint"
if: always() && steps.yarn-install.outcome == 'success'
run: "yarn lint:js"
- name: "Run Stylelint"
if: always() && steps.yarn-install.outcome == 'success'
run: "yarn lint:scss"

View file

@ -16,7 +16,7 @@ env:
jobs:
phpunit:
name: "PHP ${{ matrix.php }} using ${{ matrix.database }}"
runs-on: "ubuntu-20.04"
runs-on: ubuntu-latest
services:
rabbitmq:
image: rabbitmq:3-alpine
@ -31,9 +31,6 @@ jobs:
fail-fast: false
matrix:
php:
- "7.4"
- "8.0"
- "8.1"
- "8.2"
- "8.3"
- "8.4"
@ -44,7 +41,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
@ -57,6 +54,12 @@ jobs:
extensions: json, pdo, pdo_mysql, pdo_sqlite, pdo_pgsql, curl, imagick, pgsql, gd, tidy
ini-values: "date.timezone=Europe/Paris"
- name: "Install Node"
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: 'yarn'
- name: "Setup MySQL"
if: "${{ matrix.database == 'mysql' }}"
run: |
@ -76,6 +79,12 @@ jobs:
with:
composer-options: "--optimize-autoloader --prefer-dist"
- name: "Install dependencies with Yarn"
run: yarn install
- name: "Build assets with Yarn"
run: yarn build:dev
- name: "Prepare database configuration"
run: cp app/config/tests/parameters_test.${{ matrix.database }}.yml app/config/parameters_test.yml
@ -84,7 +93,7 @@ jobs:
phpunit_no_prefix:
name: "PHP ${{ matrix.php }} using ${{ matrix.database }} without prefix"
runs-on: "ubuntu-20.04"
runs-on: ubuntu-latest
services:
rabbitmq:
image: rabbitmq:3-alpine
@ -107,7 +116,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
@ -120,6 +129,12 @@ jobs:
extensions: json, pdo, pdo_mysql, pdo_sqlite, pdo_pgsql, curl, imagick, pgsql, gd, tidy
ini-values: "date.timezone=Europe/Paris"
- name: "Install Node"
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: 'yarn'
- name: "Remove database prefix"
run: |
pip install --user yq
@ -144,6 +159,12 @@ jobs:
with:
composer-options: "--optimize-autoloader --prefer-dist"
- name: "Install dependencies with Yarn"
run: yarn install
- name: "Build assets with Yarn"
run: yarn build:dev
- name: "Prepare database configuration"
run: cp app/config/tests/parameters_test.${{ matrix.database }}.yml app/config/parameters_test.yml
@ -152,7 +173,7 @@ jobs:
phpunit-without-rmq-redis:
name: "PHP ${{ matrix.php }} using ${{ matrix.database }} without Rabbit & Redis"
runs-on: "ubuntu-20.04"
runs-on: ubuntu-latest
strategy:
fail-fast: false
@ -166,7 +187,7 @@ jobs:
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
with:
fetch-depth: 2
@ -179,6 +200,12 @@ jobs:
extensions: json, pdo, pdo_mysql, pdo_sqlite, pdo_pgsql, curl, imagick, pgsql, gd, tidy
ini-values: "date.timezone=Europe/Paris"
- name: "Install Node"
uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
cache: 'yarn'
- name: "Setup MySQL"
if: "${{ matrix.database == 'mysql' }}"
run: |
@ -198,6 +225,12 @@ jobs:
with:
composer-options: "--optimize-autoloader --prefer-dist"
- name: "Install dependencies with Yarn"
run: yarn install
- name: "Build assets with Yarn"
run: yarn build:dev
- name: "Prepare database configuration"
run: cp app/config/tests/parameters_test.${{ matrix.database }}.yml app/config/parameters_test.yml

View file

@ -12,7 +12,7 @@ jobs:
steps:
- name: Dependabot metadata
id: metadata
uses: dependabot/fetch-metadata@v2.2.0
uses: dependabot/fetch-metadata@v2.4.0
with:
github-token: '${{ secrets.GITHUB_TOKEN }}'
- name: Approve and merge minor updates

View file

@ -13,16 +13,16 @@ permissions:
jobs:
translations:
name: "Translations"
runs-on: "ubuntu-20.04"
runs-on: ubuntu-latest
strategy:
matrix:
php:
- "7.4"
- "8.2"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"

View file

@ -12,11 +12,11 @@ jobs:
strategy:
matrix:
php:
- "7.4"
- "8.2"
steps:
- name: "Checkout"
uses: "actions/checkout@v4"
uses: "actions/checkout@v5"
- name: "Install PHP"
uses: "shivammathur/setup-php@v2"

4
.gitignore vendored
View file

@ -29,7 +29,7 @@ web/uploads/
!/web/bundles/.gitkeep
/web/assets/images/*
!web/assets/images/.gitkeep
/web/wallassets/*
/web/build/*
# Build
/app/build
@ -60,3 +60,5 @@ specialexport.json
web/custom.css
.env.local
yarn-error.log

View file

@ -37,17 +37,6 @@ return $config
// 'psr_autoloading' => true,
'strict_comparison' => true,
'strict_param' => true,
// We override next rule because of current @Symfony ruleSet
// 'parameters' element is breaking PHP 7.4
// https://cs.symfony.com/doc/rules/control_structure/trailing_comma_in_multiline.html
// TODO: remove this configuration after dropping support of PHP 7.4
'trailing_comma_in_multiline' => [
'elements' => [
'arrays',
'array_destructuring',
'match',
],
],
'concat_space' => [
'spacing' => 'one',
],

View file

@ -1,5 +1,51 @@
# Changelog
## Upcoming changes
* **[BC BREAK]** Convert 403 errors to 404 errors by @yguedidi in https://github.com/wallabag/wallabag/pull/8075
* `wallassets/` folder renamed to `build/`
## [2.6.13](https://github.com/wallabag/wallabag/tree/2.6.13)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.12...2.6.13)
### Improvements
* Add support of Pocket CSV import by @kdecherf and @nicosomb in [https://github.com/wallabag/wallabag/pull/8240](https://github.com/wallabag/wallabag/pull/8240)
* Backport Pocket and Shaarli HTML imports from master by @nicosomb in [https://github.com/wallabag/wallabag/pull/8193](https://github.com/wallabag/wallabag/pull/8193)
### Fixes
* Avoid non-validated OTP to be enabled #8139 by @j0k3r in [https://github.com/wallabag/wallabag/pull/8139](https://github.com/wallabag/wallabag/pull/8139)
### Technical stuff
* Update j0k3r/php-readability:1.2.13 to fix regression (about latin1 instead of UTF-8 used for entries) by @nicosomb [https://github.com/wallabag/wallabag/pull/8194](https://github.com/wallabag/wallabag/pull/8194)
## [2.6.12](https://github.com/wallabag/wallabag/tree/2.6.12)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.11...2.6.12)
### Technical stuff
* Fix changelog by @yguedidi in [https://github.com/wallabag/wallabag/pull/8135](https://github.com/wallabag/wallabag/pull/8135)
* Update dependencies by @yguedidi in [https://github.com/wallabag/wallabag/pull/8136](https://github.com/wallabag/wallabag/pull/8136)
## [2.6.11](https://github.com/wallabag/wallabag/tree/2.6.11)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.10...2.6.11)
### Security fix
* Protect actions with a CSRF token by @yguedidi in https://github.com/wallabag/wallabag/commit/99c8a06594d6ee7480ce4d041ccff3025b353656
### Fixes
* Fix redirection after action in search results by @nicosomb in [https://github.com/wallabag/wallabag/pull/7827](https://github.com/wallabag/wallabag/pull/7827)
* Fix title tag filter by @nicosomb in [https://github.com/wallabag/wallabag/pull/7846](https://github.com/wallabag/wallabag/pull/7846)
* Change NB_ELEMENTS in pocket importer to 30 by @j0k3r in [https://github.com/wallabag/wallabag/pull/7993](https://github.com/wallabag/wallabag/pull/7993)
* Fix entries counter for annotated entries in the menu by @j0k3r in [https://github.com/wallabag/wallabag/pull/7999](https://github.com/wallabag/wallabag/pull/7999)
### Technical stuff
* Prepare 2.6.11 release by @yguedidi in [https://github.com/wallabag/wallabag/pull/8133](https://github.com/wallabag/wallabag/pull/8133)
## [2.6.10](https://github.com/wallabag/wallabag/tree/2.6.10)
[Full Changelog](https://github.com/wallabag/wallabag/compare/2.6.9...2.6.10)

View file

@ -52,6 +52,15 @@ fix-cs: ## Run PHP-CS-Fixer
phpstan: ## Run PHPStan
@$(PHP_NO_XDEBUG) bin/phpstan analyse
phpstan-baseline: ## Generate PHPStan baseline
@$(PHP_NO_XDEBUG) bin/phpstan analyse --generate-baseline
lint-js: ## Run ESLint
@$(YARN) lint:js
lint-scss: ## Run Stylelint
@$(YARN) lint:scss
release: ## Create a package. Need a VERSION parameter (eg: `make release VERSION=master`).
ifndef VERSION
$(error VERSION is not set)

View file

@ -1,6 +1,6 @@
# wallabag
![CI](https://github.com/wallabag/wallabag/workflows/CI/badge.svg)
[![CI](https://github.com/wallabag/wallabag/actions/workflows/continuous-integration.yml/badge.svg?branch=master)](https://github.com/wallabag/wallabag/actions/workflows/continuous-integration.yml?query=branch%3Amaster)
[![Matrix](https://matrix.to/img/matrix-badge.svg)](https://matrix.to/#/#wallabag:matrix.org)
[![Donation Status](https://img.shields.io/liberapay/goal/wallabag.svg?logo=liberapay)](https://liberapay.com/wallabag/donate)
[![Translation status](https://hosted.weblate.org/widgets/wallabag/-/svg-badge.svg)](https://hosted.weblate.org/engage/wallabag/?utm_source=widget)

View file

@ -25,13 +25,13 @@ During this documentation, we assume the release is `$LAST_WALLABAG_RELEASE` (li
### Target PHP version
`composer.lock` is _always_ built for a particular version, by default the one it is generated (with `composer update`).
If the PHP version used to generate the .lock isn't a widely available one (like PHP 8), a more common one should
If the PHP version used to generate the .lock isn't a widely available one (like latest PHP versions), a more common one should
be locally specified in `composer.lock`:
```json
"config": {
"platform": {
"php": "7.4.29",
"php": "8.2.27",
"ext-something": "4.0"
}
}

View file

@ -1,8 +1,39 @@
<?php
use BabDev\PagerfantaBundle\BabDevPagerfantaBundle;
use Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle;
use Craue\ConfigBundle\CraueConfigBundle;
use DAMA\DoctrineTestBundle\DAMADoctrineTestBundle;
use Doctrine\Bundle\DoctrineBundle\DoctrineBundle;
use Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle;
use Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle;
use FOS\JsRoutingBundle\FOSJsRoutingBundle;
use FOS\OAuthServerBundle\FOSOAuthServerBundle;
use FOS\RestBundle\FOSRestBundle;
use FOS\UserBundle\FOSUserBundle;
use JMS\SerializerBundle\JMSSerializerBundle;
use KPhoen\RulerZBundle\KPhoenRulerZBundle;
use Nelmio\ApiDocBundle\NelmioApiDocBundle;
use Nelmio\CorsBundle\NelmioCorsBundle;
use OldSound\RabbitMqBundle\OldSoundRabbitMqBundle;
use Scheb\TwoFactorBundle\SchebTwoFactorBundle;
use Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle;
use Sentry\SentryBundle\SentryBundle;
use Spiriit\Bundle\FormFilterBundle\SpiriitFormFilterBundle;
use Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle;
use Symfony\Bundle\DebugBundle\DebugBundle;
use Symfony\Bundle\FrameworkBundle\FrameworkBundle;
use Symfony\Bundle\MakerBundle\MakerBundle;
use Symfony\Bundle\MonologBundle\MonologBundle;
use Symfony\Bundle\SecurityBundle\SecurityBundle;
use Symfony\Bundle\TwigBundle\TwigBundle;
use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle;
use Symfony\Bundle\WebServerBundle\WebServerBundle;
use Symfony\Component\Config\Loader\LoaderInterface;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\HttpKernel\Kernel;
use Symfony\WebpackEncoreBundle\WebpackEncoreBundle;
use Twig\Extra\TwigExtraBundle\TwigExtraBundle;
use Wallabag\Import\ImportCompilerPass;
class AppKernel extends Kernel
@ -10,45 +41,45 @@ class AppKernel extends Kernel
public function registerBundles()
{
$bundles = [
new Symfony\Bundle\FrameworkBundle\FrameworkBundle(),
new Symfony\Bundle\SecurityBundle\SecurityBundle(),
new Symfony\Bundle\TwigBundle\TwigBundle(),
new Symfony\Bundle\MonologBundle\MonologBundle(),
new Doctrine\Bundle\DoctrineBundle\DoctrineBundle(),
new Sensio\Bundle\FrameworkExtraBundle\SensioFrameworkExtraBundle(),
new FOS\RestBundle\FOSRestBundle(),
new FOS\UserBundle\FOSUserBundle(),
new JMS\SerializerBundle\JMSSerializerBundle(),
new Nelmio\ApiDocBundle\NelmioApiDocBundle(),
new Nelmio\CorsBundle\NelmioCorsBundle(),
new Bazinga\Bundle\HateoasBundle\BazingaHateoasBundle(),
new Spiriit\Bundle\FormFilterBundle\SpiriitFormFilterBundle(),
new FOS\OAuthServerBundle\FOSOAuthServerBundle(),
new Stof\DoctrineExtensionsBundle\StofDoctrineExtensionsBundle(),
new Scheb\TwoFactorBundle\SchebTwoFactorBundle(),
new KPhoen\RulerZBundle\KPhoenRulerZBundle(),
new Doctrine\Bundle\MigrationsBundle\DoctrineMigrationsBundle(),
new Craue\ConfigBundle\CraueConfigBundle(),
new BabDev\PagerfantaBundle\BabDevPagerfantaBundle(),
new FOS\JsRoutingBundle\FOSJsRoutingBundle(),
new OldSound\RabbitMqBundle\OldSoundRabbitMqBundle(),
new Http\HttplugBundle\HttplugBundle(),
new Sentry\SentryBundle\SentryBundle(),
new Twig\Extra\TwigExtraBundle\TwigExtraBundle(),
new FrameworkBundle(),
new SecurityBundle(),
new TwigBundle(),
new MonologBundle(),
new DoctrineBundle(),
new SensioFrameworkExtraBundle(),
new FOSRestBundle(),
new FOSUserBundle(),
new JMSSerializerBundle(),
new NelmioApiDocBundle(),
new NelmioCorsBundle(),
new BazingaHateoasBundle(),
new SpiriitFormFilterBundle(),
new FOSOAuthServerBundle(),
new StofDoctrineExtensionsBundle(),
new SchebTwoFactorBundle(),
new KPhoenRulerZBundle(),
new DoctrineMigrationsBundle(),
new CraueConfigBundle(),
new BabDevPagerfantaBundle(),
new FOSJsRoutingBundle(),
new OldSoundRabbitMqBundle(),
new SentryBundle(),
new TwigExtraBundle(),
new WebpackEncoreBundle(),
];
if (in_array($this->getEnvironment(), ['dev', 'test'], true)) {
$bundles[] = new Symfony\Bundle\DebugBundle\DebugBundle();
$bundles[] = new Symfony\Bundle\WebProfilerBundle\WebProfilerBundle();
$bundles[] = new Doctrine\Bundle\FixturesBundle\DoctrineFixturesBundle();
$bundles[] = new DebugBundle();
$bundles[] = new WebProfilerBundle();
$bundles[] = new DoctrineFixturesBundle();
if ('test' === $this->getEnvironment()) {
$bundles[] = new DAMA\DoctrineTestBundle\DAMADoctrineTestBundle();
$bundles[] = new DAMADoctrineTestBundle();
}
if ('dev' === $this->getEnvironment()) {
$bundles[] = new Symfony\Bundle\MakerBundle\MakerBundle();
$bundles[] = new Symfony\Bundle\WebServerBundle\WebServerBundle();
$bundles[] = new MakerBundle();
$bundles[] = new WebServerBundle();
}
}
@ -69,30 +100,16 @@ class AppKernel extends Kernel
{
$loader->load($this->getProjectDir() . '/app/config/config_' . $this->getEnvironment() . '.yml');
$loader->load(function ($container) {
if ($container->getParameter('use_webpack_dev_server')) {
$container->loadFromExtension('framework', [
'assets' => [
'base_url' => 'http://localhost:8080/',
],
]);
} else {
$container->loadFromExtension('framework', [
'assets' => [
'base_url' => $container->getParameter('domain_name'),
],
]);
}
});
$loader->load(function (ContainerBuilder $container) {
$loader->load(function (ContainerBuilder $container): void {
// $container->setParameter('container.autowiring.strict_mode', true);
// $container->setParameter('container.dumper.inline_class_loader', true);
$container->addObjectResource($this);
});
$loader->load(function (ContainerBuilder $container) {
$loader->load(function (ContainerBuilder $container): void {
$this->processDatabaseParameters($container);
$this->defineRedisUrlEnvVar($container);
$this->defineRabbitMqUrlEnvVar($container);
});
}
@ -103,19 +120,12 @@ class AppKernel extends Kernel
private function processDatabaseParameters(ContainerBuilder $container)
{
switch ($container->getParameter('database_driver')) {
case 'pdo_mysql':
$scheme = 'mysql';
break;
case 'pdo_pgsql':
$scheme = 'pgsql';
break;
case 'pdo_sqlite':
$scheme = 'sqlite';
break;
default:
throw new RuntimeException('Unsupported database driver: ' . $container->getParameter('database_driver'));
}
$scheme = match ($container->getParameter('database_driver')) {
'pdo_mysql' => 'mysql',
'pdo_pgsql' => 'pgsql',
'pdo_sqlite' => 'sqlite',
default => throw new RuntimeException('Unsupported database driver: ' . $container->getParameter('database_driver')),
};
$container->setParameter('database_scheme', $scheme);
@ -128,4 +138,45 @@ class AppKernel extends Kernel
$container->setParameter('database_port', (string) $container->getParameter('database_port'));
$container->setParameter('database_socket', (string) $container->getParameter('database_socket'));
}
private function defineRedisUrlEnvVar(ContainerBuilder $container)
{
$scheme = $container->getParameter('redis_scheme');
$host = $container->getParameter('redis_host');
$port = $container->getParameter('redis_port');
$path = $container->getParameter('redis_path');
$password = $container->getParameter('redis_password');
$url = $scheme . '://';
if ($password) {
$url .= $password . '@';
}
$url .= $host;
if ($port) {
$url .= ':' . $port;
}
$url .= '/' . ltrim($path, '/');
$container->setParameter('env(REDIS_URL)', $url);
}
private function defineRabbitMqUrlEnvVar(ContainerBuilder $container)
{
$host = $container->getParameter('rabbitmq_host');
$port = $container->getParameter('rabbitmq_port');
$user = $container->getParameter('rabbitmq_user');
$password = $container->getParameter('rabbitmq_password');
$url = 'amqp://' . $user . ':' . $password . '@' . $host;
if ($port) {
$url .= ':' . $port;
}
$container->setParameter('env(RABBITMQ_URL)', $url);
}
}

View file

@ -5,8 +5,6 @@ imports:
- { resource: wallabag.yml }
parameters:
# Allows to use the live reload feature for changes in assets
use_webpack_dev_server: false
craue_config.cache_adapter.class: Craue\ConfigBundle\CacheAdapter\SymfonyCacheComponentAdapter
env(DATABASE_URL): '%database_scheme%://%database_user%:%database_password%@%database_host%:%database_port%/%database_name%?unix_socket=%database_socket%&charset=%database_charset%'
@ -31,9 +29,13 @@ framework:
handler_id: session.handler.native_file
save_path: "%kernel.project_dir%/var/sessions/%kernel.environment%"
cookie_secure: auto
cookie_samesite: lax
storage_factory_id: session.storage.factory.native
fragments: ~
http_method_override: true
assets: ~
assets:
base_url: '%domain_name%'
json_manifest_path: '%kernel.project_dir%/web/build/manifest.json'
mailer:
dsn: "%mailer_dsn%"
http_client:
@ -47,6 +49,10 @@ framework:
X-Accept: 'application/json'
request_html_function.client:
scope: '.*'
browser.client:
scope: '.*'
verify_host: false
verify_peer: false
# Twig Configuration
twig:
@ -56,6 +62,7 @@ twig:
form_themes:
- "@SpiriitFormFilter/Form/form_div_layout.html.twig"
globals:
wallabag_url: '%domain_name%'
registration_enabled: '%fosuser_registration%'
# Doctrine Configuration
@ -72,7 +79,7 @@ doctrine:
auto_mapping: true
mappings:
Wallabag:
type: annotation
type: attribute
is_bundle: false
dir: '%kernel.project_dir%/src/Entity'
prefix: 'Wallabag\Entity'
@ -95,6 +102,8 @@ doctrine_migrations:
version_column_name: 'version'
version_column_length: 192
executed_at_column_name: 'executed_at'
services:
Doctrine\Migrations\Version\MigrationFactory: Wallabag\Doctrine\MigrationFactoryDecorator
fos_rest:
param_fetcher_listener: true
@ -190,7 +199,7 @@ fos_user:
address: "%from_email%"
sender_name: wallabag
service:
mailer: Wallabag\Mailer\UserMailer
mailer: fos_user.mailer.twig_symfony
fos_oauth_server:
db_driver: orm
@ -225,18 +234,10 @@ scheb_two_factor:
template: "Authentication/form.html.twig"
mailer: Wallabag\Mailer\AuthCodeMailer
rulerz:
targets:
doctrine: true
old_sound_rabbit_mq:
connections:
default:
host: "%rabbitmq_host%"
port: "%rabbitmq_port%"
user: "%rabbitmq_user%"
password: "%rabbitmq_password%"
vhost: /
url: "%env(RABBITMQ_URL)%"
lazy: true
producers:
import_pocket:
@ -304,6 +305,11 @@ old_sound_rabbit_mq:
exchange_options:
name: 'wallabag.import.pocket_html'
type: topic
import_pocket_csv:
connection: default
exchange_options:
name: 'wallabag.import.pocket_csv'
type: topic
consumers:
import_pocket:
connection: default
@ -422,6 +428,15 @@ old_sound_rabbit_mq:
name: 'wallabag.import.pocket_html'
callback: wallabag.consumer.amqp.pocket_html
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
import_pocket_csv:
connection: default
exchange_options:
name: 'wallabag.import.pocket_csv'
type: topic
queue_options:
name: 'wallabag.import.pocket_csv'
callback: wallabag.consumer.amqp.pocket_csv
qos_options: {prefetch_count: "%rabbitmq_prefetch_count%"}
fos_js_routing:
routes_to_expose:
@ -449,17 +464,6 @@ sensio_framework_extra:
router:
annotations: false
httplug:
clients:
wallabag:
factory: Wallabag\Helper\HttpClientFactory
config:
defaults:
timeout: 10
plugins: ['httplug.plugin.logger']
discovery:
client: false
# define custom entity so we can override length attribute to fix utf8mb4 issue
craue_config:
entity_name: Wallabag\Entity\InternalSetting
@ -467,3 +471,8 @@ craue_config:
when@dev:
maker:
root_namespace: 'Wallabag'
webpack_encore:
output_path: '%kernel.project_dir%/web/build'
script_attributes:
defer: true

View file

@ -1,10 +1,6 @@
imports:
- { resource: config.yml }
framework:
assets:
# json_manifest_path: '%kernel.project_dir%/web/bundles/wallabagcore/manifest.json'
#doctrine:
# orm:
# metadata_cache_driver: apc

View file

@ -10,7 +10,7 @@ parameters:
framework:
test: ~
session:
storage_id: session.storage.mock_file
storage_factory_id: session.storage.factory.mock_file
profiler:
collect: false
translator:

View file

@ -47,8 +47,6 @@ parameters:
from_email: no-reply@wallabag.org
rss_limit: 50
# RabbitMQ processing
rabbitmq_host: localhost
rabbitmq_port: 5672
@ -57,7 +55,7 @@ parameters:
rabbitmq_prefetch_count: 10
# Redis processing
redis_scheme: tcp
redis_scheme: redis
redis_host: localhost
redis_port: 6379
redis_path: null

View file

@ -13,6 +13,7 @@ doc-api-json:
homepage:
path: "/{page}"
methods: GET
defaults:
_controller: 'Wallabag\Controller\EntryController::showUnreadAction'
page : 1
@ -27,23 +28,27 @@ fos_oauth_server_token:
craue_config_settings_modify:
path: /settings
methods: [GET, POST]
defaults:
_controller: 'Craue\ConfigBundle\Controller\SettingsController::modifyAction'
fos_js_routing:
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing.xml"
resource: "@FOSJsRoutingBundle/Resources/config/routing/routing-sf4.xml"
2fa_login:
path: /2fa
methods: GET
defaults:
_controller: "scheb_two_factor.form_controller:form"
2fa_login_check:
path: /2fa_check
methods: POST
# redirect RSS feed to Atom
rss_to_atom_unread:
path: /{username}/{token}/unread.xml
methods: GET
defaults:
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction'
route: unread_feed
@ -51,6 +56,7 @@ rss_to_atom_unread:
rss_to_atom_archive:
path: /{username}/{token}/archive.xml
methods: GET
defaults:
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction'
route: archive_feed
@ -58,6 +64,7 @@ rss_to_atom_archive:
rss_to_atom_starred:
path: /{username}/{token}/starred.xml
methods: GET
defaults:
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction'
route: starred_feed
@ -65,6 +72,7 @@ rss_to_atom_starred:
rss_to_atom_all:
path: /{username}/{token}/all.xml
methods: GET
defaults:
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction'
route: all_feed
@ -72,6 +80,7 @@ rss_to_atom_all:
rss_to_atom_tags:
path: /{username}/{token}/tags/{slug}.xml
methods: GET
defaults:
_controller: 'Symfony\Bundle\FrameworkBundle\Controller\RedirectController::redirectAction'
route: tag_feed

View file

@ -1,5 +1,5 @@
security:
encoders:
password_hashers:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
@ -70,10 +70,9 @@ security:
- { path: /(unread|starred|archive|annotated|all).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/locale, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /tags/(.*).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/feed, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/feed, roles: PUBLIC_ACCESS }
- { path: /(unread|starred|archive|annotated).xml$, roles: IS_AUTHENTICATED_ANONYMOUSLY } # For backwards compatibility
- { path: ^/share, roles: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/settings, roles: ROLE_SUPER_ADMIN }
- { path: ^/annotations, roles: ROLE_USER }
- { path: ^/2fa, role: IS_AUTHENTICATED_2FA_IN_PROGRESS }
- { path: ^/, roles: ROLE_USER }

View file

@ -30,6 +30,7 @@ services:
$storeArticleHeaders: '@=service(''craue_config'').get(''store_article_headers'')'
$supportUrl: '@=service(''craue_config'').get(''wallabag_support_url'')'
$fonts: '%wallabag.fonts%'
$defaultIgnoreOriginInstanceRules: '%wallabag.default_ignore_origin_instance_rules%'
Wallabag\:
resource: '../../src/*'
@ -107,6 +108,14 @@ services:
$rabbitMqProducer: '@old_sound_rabbit_mq.import_pocket_html_producer'
$redisProducer: '@wallabag.producer.redis.pocket_html'
Wallabag\Controller\Import\PocketCsvController:
arguments:
$rabbitMqProducer: '@old_sound_rabbit_mq.import_pocket_csv_producer'
$redisProducer: '@wallabag.producer.redis.pocket_csv'
Wallabag\Doctrine\MigrationFactoryDecorator:
decorates: doctrine.migrations.migrations_factory
Doctrine\DBAL\Connection:
alias: doctrine.dbal.default_connection
@ -187,11 +196,17 @@ services:
tags:
- { name: doctrine.event_subscriber }
psr18.wallabag.client:
class: Symfony\Component\HttpClient\Psr18Client
arguments:
$client: '@Wallabag\HttpClient\WallabagClient'
Graby\Graby:
arguments:
$config:
error_message: '%wallabag.fetching_error_message%'
error_message_title: '%wallabag.fetching_error_message_title%'
$client: '@psr18.wallabag.client'
calls:
- [ setLogger, [ "@logger" ] ]
tags:
@ -201,9 +216,6 @@ services:
arguments:
$config: {}
wallabag.http_client:
alias: 'httplug.client.wallabag'
Wallabag\SiteConfig\GrabySiteConfigBuilder:
tags:
- { name: monolog.logger, channel: graby }
@ -212,11 +224,9 @@ services:
Wallabag\SiteConfig\SiteConfigBuilder:
alias: Wallabag\SiteConfig\GrabySiteConfigBuilder
GuzzleHttp\Cookie\CookieJar: ~
Wallabag\Helper\HttpClientFactory:
calls:
- ['addSubscriber', ['@Wallabag\Guzzle\AuthenticatorSubscriber']]
Symfony\Component\BrowserKit\HttpBrowser:
arguments:
$client: '@browser.client'
RulerZ\RulerZ:
alias: rulerz
@ -225,30 +235,17 @@ services:
tags:
- { name: rulerz.operator, target: native, operator: matches }
Wallabag\Operator\Doctrine\Matches:
tags:
- { name: rulerz.operator, target: doctrine, operator: matches, inline: true }
Wallabag\Operator\PHP\NotMatches:
tags:
- { name: rulerz.operator, target: native, operator: notmatches }
Wallabag\Operator\Doctrine\NotMatches:
tags:
- { name: rulerz.operator, target: doctrine, operator: notmatches, inline: true }
Wallabag\Operator\PHP\PatternMatches:
tags:
- { name: rulerz.operator, target: native, operator: "~" }
Predis\Client:
arguments:
$parameters:
scheme: '%redis_scheme%'
host: '%redis_host%'
port: '%redis_port%'
path: '%redis_path%'
password: '%redis_password%'
$parameters: '%env(REDIS_URL)%'
Wallabag\Event\Subscriber\SQLiteCascadeDeleteSubscriber:
tags:
@ -268,16 +265,6 @@ services:
$defaultSettings: '%wallabag.default_internal_settings%'
$defaultIgnoreOriginInstanceRules: '%wallabag.default_ignore_origin_instance_rules%'
Wallabag\Mailer\UserMailer:
arguments:
$parameters:
template:
confirmation: '%fos_user.registration.confirmation.template%'
resetting: '%fos_user.resetting.email.template%'
from_email:
confirmation: '%fos_user.registration.confirmation.from_email%'
resetting: '%fos_user.resetting.email.from_email%'
Wallabag\Event\Listener\CreateConfigListener:
arguments:
$itemsOnPage: "%wallabag.items_on_page%"
@ -346,6 +333,10 @@ services:
tags:
- { name: wallabag.import, alias: pocket_html }
Wallabag\Import\PocketCsvImport:
tags:
- { name: wallabag.import, alias: pocket_csv }
# to factorize the proximity and bypass translation for prev & next
pagerfanta.view.default_wallabag:
class: Pagerfanta\View\OptionableView

View file

@ -20,6 +20,7 @@ services:
$elcuratorConsumer: '@old_sound_rabbit_mq.import_elcurator_consumer'
$shaarliConsumer: '@old_sound_rabbit_mq.import_shaarli_consumer'
$pocketHtmlConsumer: '@old_sound_rabbit_mq.import_pocket_html_consumer'
$pocketCsvConsumer: '@old_sound_rabbit_mq.import_pocket_csv_consumer'
$omnivoreConsumer: '@old_sound_rabbit_mq.import_omnivore_consumer'
wallabag.consumer.amqp.pocket:
@ -86,3 +87,8 @@ services:
class: Wallabag\Consumer\AMQPEntryConsumer
arguments:
$import: '@Wallabag\Import\PocketHtmlImport'
wallabag.consumer.amqp.pocket_csv:
class: Wallabag\Consumer\AMQPEntryConsumer
arguments:
$import: '@Wallabag\Import\PocketCsvImport'

View file

@ -212,3 +212,19 @@ services:
class: Wallabag\Consumer\RedisEntryConsumer
arguments:
$import: '@Wallabag\Import\PocketHtmlImport'
# pocket csv
wallabag.queue.redis.pocket_csv:
class: Simpleue\Queue\RedisQueue
arguments:
$queueName: "wallabag.import.pocket_csv"
wallabag.producer.redis.pocket_csv:
class: Wallabag\Redis\Producer
arguments:
- "@wallabag.queue.redis.pocket_csv"
wallabag.consumer.redis.pocket_csv:
class: Wallabag\Consumer\RedisEntryConsumer
arguments:
$import: '@Wallabag\Import\PocketCsvImport'

View file

@ -6,6 +6,9 @@ services:
# fixtures
Wallabag\DataFixtures\:
bind:
$defaultIgnoreOriginInstanceRules: '%wallabag.default_ignore_origin_instance_rules%'
$defaultInternalSettings: '%wallabag.default_internal_settings%'
resource: '../../fixtures/*'
tags: ['doctrine.fixture.orm']
autowire: true

View file

@ -1,5 +1,5 @@
parameters:
wallabag.version: 2.6.10
wallabag.version: 2.7.0-dev
wallabag.paypal_url: "https://liberapay.com/wallabag/donate"
wallabag.languages:
en: 'English'
@ -18,6 +18,7 @@ parameters:
pt: 'Português'
ru: 'Русский'
ja: '日本語'
ko: '한국어'
zh: '简体中文'
uk: 'Українська'
hr: 'Hrvatski'
@ -175,5 +176,11 @@ parameters:
- 'Montserrat'
- 'OpenDyslexicRegular'
- 'Oswald'
wallabag.allow_mimetypes: ['application/octet-stream', 'application/json', 'text/plain', 'text/csv', 'text/html']
wallabag.allow_mimetypes:
- 'application/octet-stream'
- 'application/json'
- 'text/plain'
- 'text/csv'
- 'text/html'
- 'application/vnd.ms-excel'
wallabag.resource_dir: "%kernel.project_dir%/web/uploads/import"

View file

@ -1,37 +0,0 @@
const path = require('path');
const webpack = require('webpack');
const StyleLintPlugin = require('stylelint-webpack-plugin');
const projectDir = path.resolve(__dirname, '../../../');
module.exports = {
entry: {
material: path.join(projectDir, './assets/material/index.js'),
public: path.join(projectDir, './assets/_global/share.js'),
},
output: {
filename: '[name].js',
path: path.resolve(projectDir, 'web/wallassets'),
publicPath: '',
},
plugins: [
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery',
'window.$': 'jquery',
'window.jQuery': 'jquery',
}),
new StyleLintPlugin({
configFile: 'stylelint.config.js',
failOnError: false,
quiet: false,
context: 'assets',
files: '**/*.scss',
}),
],
resolve: {
alias: {
jquery: path.join(projectDir, 'node_modules/jquery/dist/jquery.js'),
},
},
};

View file

@ -1,58 +0,0 @@
const { merge } = require('webpack-merge');
const ESLintPlugin = require('eslint-webpack-plugin');
const commonConfig = require('./common');
module.exports = merge(commonConfig, {
devtool: 'eval-source-map',
output: {
filename: '[name].dev.js',
},
mode: 'development',
devServer: {
static: {
directory: './web',
},
},
plugins: [
new ESLintPlugin(),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.(s)?css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer'],
},
},
},
'sass-loader',
],
},
{
test: /\.(jpg|png|gif|svg|ico|eot|ttf|woff|woff2)$/,
type: 'asset/inline',
},
],
},
});

View file

@ -1,98 +0,0 @@
const webpack = require('webpack');
const { merge } = require('webpack-merge');
const ESLintPlugin = require('eslint-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const commonConfig = require('./common');
module.exports = merge(commonConfig, {
output: {
filename: '[name].js',
},
mode: 'production',
devtool: 'source-map',
optimization: {
minimize: true,
minimizer: [
new TerserPlugin({
parallel: true,
terserOptions: {
output: {
comments: false,
},
},
extractComments: false,
}),
],
},
plugins: [
new ESLintPlugin(),
new MiniCssExtractPlugin(),
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: JSON.stringify('production'),
},
}),
new WebpackManifestPlugin({
fileName: 'manifest.json',
sort: (file1, file2) => file1.path.localeCompare(file2.path),
}),
],
module: {
rules: [
{
test: /\.js$/,
exclude: /(node_modules)/,
use: {
loader: 'babel-loader',
options: {
presets: ['@babel/preset-env'],
},
},
},
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options: {
importLoaders: 1,
},
},
{
loader: 'postcss-loader',
options: {
postcssOptions: {
plugins: ['autoprefixer'],
},
},
},
'sass-loader',
],
},
{
test: /\.(jpg|png|gif|svg|ico)$/,
include: /node_modules/,
type: 'asset/resource',
generator: {
filename: 'img/[name][ext]',
},
},
{
test: /\.(jpg|png|gif|svg|ico)$/,
exclude: /node_modules/,
type: 'asset/resource',
},
{
test: /\.(eot|ttf|woff|woff2)$/,
type: 'asset/resource',
generator: {
filename: 'fonts/[name][ext]',
},
},
],
},
});

View file

@ -1,124 +0,0 @@
/* jQuery */
import $ from 'jquery';
/* Annotations */
import annotator from 'annotator';
import ClipboardJS from 'clipboard';
import 'mathjax/es5/tex-svg';
/* Fonts */
import 'material-design-icons-iconfont/dist/material-design-icons.css';
import 'lato-font/css/lato-font.css';
import 'open-dyslexic/open-dyslexic-regular.css';
import '@fontsource/atkinson-hyperlegible';
import '@fontsource/eb-garamond';
import '@fontsource/montserrat';
import '@fontsource/oswald';
import './global.scss';
/* Shortcuts */
import './js/shortcuts/entry';
import './js/shortcuts/main';
/* Highlight */
import './js/highlight';
import { savePercent, retrievePercent } from './js/tools';
/* ==========================================================================
Annotations & Remember position
========================================================================== */
$(document).ready(() => {
if ($('#article').length) {
const app = new annotator.App();
app.include(annotator.ui.main, {
element: document.querySelector('article'),
});
const authorization = {
permits() { return true; },
};
app.registry.registerUtility(authorization, 'authorizationPolicy');
const x = JSON.parse($('#annotationroutes').html());
app.include(annotator.storage.http, $.extend({}, x, {
onError(msg, xhr) {
if (!Object.prototype.hasOwnProperty.call(xhr, 'responseJSON')) {
annotator.notification.banner('An error occurred', 'error');
return;
}
$.each(xhr.responseJSON.children, (k, v) => {
if (v.errors) {
$.each(v.errors, (n, errorText) => {
annotator.notification.banner(errorText, 'error');
});
}
});
},
}));
app.start().then(() => {
app.annotations.load({ entry: x.entryId });
});
$(window).scroll(() => {
const scrollTop = $(window).scrollTop();
const docHeight = $(document).height();
const scrollPercent = (scrollTop) / (docHeight);
const scrollPercentRounded = Math.round(scrollPercent * 100) / 100;
savePercent(x.entryId, scrollPercentRounded);
});
retrievePercent(x.entryId);
$(window).resize(() => {
retrievePercent(x.entryId, true);
});
}
document.querySelectorAll('[data-handler=tag-rename]').forEach((item) => {
const current = item;
current.wallabag_edit_mode = false;
current.onclick = (event) => {
const target = event.currentTarget;
if (target.wallabag_edit_mode === false) {
$(target.parentNode.querySelector('[data-handle=tag-link]')).addClass('hidden');
$(target.parentNode.querySelector('[data-handle=tag-rename-form]')).removeClass('hidden');
target.parentNode.querySelector('[data-handle=tag-rename-form] input').focus();
target.querySelector('.material-icons').innerHTML = 'done';
target.wallabag_edit_mode = true;
} else {
target.parentNode.querySelector('[data-handle=tag-rename-form]').submit();
}
};
});
// mimic radio button because emailTwoFactor is a boolean
$('#update_user_googleTwoFactor').on('change', () => {
$('#update_user_emailTwoFactor').prop('checked', false);
});
$('#update_user_emailTwoFactor').on('change', () => {
$('#update_user_googleTwoFactor').prop('checked', false);
});
// same mimic for super admin
$('#user_googleTwoFactor').on('change', () => {
$('#user_emailTwoFactor').prop('checked', false);
});
$('#user_emailTwoFactor').on('change', () => {
$('#user_googleTwoFactor').prop('checked', false);
});
// handle copy to clipboard for developer stuff
const clipboard = new ClipboardJS('.btn');
clipboard.on('success', (e) => {
e.clearSelection();
});
});

View file

@ -1,4 +0,0 @@
top['bookmarklet-url@wallabag.org'] = '<!DOCTYPE html><html><head><title>bag it!</title>'
+ '<link rel="icon" href="tpl/img/favicon.ico" />'
+ '</head><body><script>window.onload=function(){window.setTimeout'
+ '(function(){history.back();},250);};</script></body></html>';

View file

@ -1,8 +0,0 @@
import 'highlight.js/styles/atom-one-light.css';
import hljs from 'highlight.js';
window.addEventListener('load', () => {
document.querySelectorAll('pre').forEach((element) => {
hljs.highlightElement(element);
});
});

View file

@ -1,15 +0,0 @@
import Mousetrap from 'mousetrap';
/* Shortcuts */
/* Go to */
Mousetrap.bind('g u', () => { window.location.href = Routing.generate('homepage'); });
Mousetrap.bind('g s', () => { window.location.href = Routing.generate('starred'); });
Mousetrap.bind('g r', () => { window.location.href = Routing.generate('archive'); });
Mousetrap.bind('g a', () => { window.location.href = Routing.generate('all'); });
Mousetrap.bind('g t', () => { window.location.href = Routing.generate('tag'); });
Mousetrap.bind('g c', () => { window.location.href = Routing.generate('config'); });
Mousetrap.bind('g i', () => { window.location.href = Routing.generate('import'); });
Mousetrap.bind('g d', () => { window.location.href = Routing.generate('developer'); });
Mousetrap.bind('?', () => { window.location.href = Routing.generate('howto'); });
Mousetrap.bind('g l', () => { window.location.href = Routing.generate('fos_user_security_logout'); });

View file

@ -1,36 +0,0 @@
import $ from 'jquery';
import './shortcuts/main';
import './shortcuts/entry';
/* Allows inline call qr-code call */
import jrQrcode from 'jr-qrcode'; // eslint-disable-line
function supportsLocalStorage() {
try {
return 'localStorage' in window && window.localStorage !== null;
} catch (e) {
return false;
}
}
function savePercent(id, percent) {
if (!supportsLocalStorage()) { return false; }
localStorage[`wallabag.article.${id}.percent`] = percent;
return true;
}
function retrievePercent(id, resized) {
if (!supportsLocalStorage()) { return false; }
const bheight = $(document).height();
const percent = localStorage[`wallabag.article.${id}.percent`];
const scroll = bheight * percent;
if (!resized) {
$('html,body').animate({ scrollTop: scroll }, 'fast');
}
return true;
}
export { savePercent, retrievePercent };

View file

@ -1 +0,0 @@
import './share.scss';

11
assets/bootstrap.js vendored Normal file
View file

@ -0,0 +1,11 @@
import { startStimulusApp } from '@symfony/stimulus-bridge';
// Registers Stimulus controllers from controllers.json and in the controllers/ directory
export default startStimulusApp(require.context(
'@symfony/stimulus-bridge/lazy-controller-loader!./controllers',
true,
/\.[jt]sx?$/,
));
// register any custom, 3rd party controllers here
// app.register('some_controller_name', SomeImportedController);

4
assets/controllers.json Normal file
View file

@ -0,0 +1,4 @@
{
"controllers": [],
"entrypoints": []
}

View file

@ -0,0 +1,13 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['input'];
toggle() {
this.element.classList.toggle('hidden');
if (!this.element.classList.contains('hidden')) {
this.inputTarget.focus();
}
}
}

View file

@ -0,0 +1,57 @@
import { Controller } from '@hotwired/stimulus';
import annotator from 'annotator';
export default class extends Controller {
static values = {
entryId: Number,
createUrl: String,
updateUrl: String,
destroyUrl: String,
searchUrl: String,
};
connect() {
this.app = new annotator.App();
this.app.include(annotator.ui.main, {
element: this.element,
});
const authorization = {
permits() { return true; },
};
this.app.registry.registerUtility(authorization, 'authorizationPolicy');
this.app.include(annotator.storage.http, {
prefix: '',
urls: {
create: this.createUrlValue,
update: this.updateUrlValue,
destroy: this.destroyUrlValue,
search: this.searchUrlValue,
},
entryId: this.entryIdValue,
onError(msg, xhr) {
if (!Object.prototype.hasOwnProperty.call(xhr, 'responseJSON')) {
annotator.notification.banner('An error occurred', 'error');
return;
}
Object.values(xhr.responseJSON.children).forEach((v) => {
if (v.errors) {
Object.values(v.errors).forEach((errorText) => {
annotator.notification.banner(errorText, 'error');
});
}
});
},
});
this.app.start().then(() => {
this.app.annotations.load({ entry: this.entryIdValue });
});
}
disconnect() {
this.app.destroy();
}
}

View file

@ -0,0 +1,15 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['item', 'tagAction'];
toggleSelection(e) {
this.itemTargets.forEach((item) => {
item.checked = e.currentTarget.checked; // eslint-disable-line no-param-reassign
});
}
tagSelection() {
this.element.requestSubmit(this.tagActionTarget);
}
}

View file

@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
import ClipboardJS from 'clipboard';
export default class extends Controller {
connect() {
this.clipboard = new ClipboardJS(this.element);
this.clipboard.on('success', (e) => {
e.clearSelection();
});
}
disconnect() {
this.clipboard.destroy();
}
}

View file

@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['previewArticle', 'previewContent', 'font', 'fontSize', 'lineHeight', 'maxWidth'];
connect() {
this.updatePreview();
}
updatePreview() {
this.previewArticleTarget.style.maxWidth = `${this.maxWidthTarget.value}em`;
this.previewContentTarget.style.fontFamily = this.fontTarget.value;
this.previewContentTarget.style.fontSize = `${this.fontSizeTarget.value}em`;
this.previewContentTarget.style.lineHeight = `${this.lineHeightTarget.value}em`;
}
}

View file

@ -0,0 +1,39 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
connect() {
this.#choose();
this.mql = window.matchMedia('(prefers-color-scheme: dark)');
this.mql.addEventListener('change', this.#choose.bind(this));
}
useLight() {
this.element.classList.remove('dark-theme');
document.cookie = 'theme=light;samesite=Lax;path=/;max-age=31536000';
}
useDark() {
this.element.classList.add('dark-theme');
document.cookie = 'theme=dark;samesite=Lax;path=/;max-age=31536000';
}
useAuto() {
document.cookie = 'theme=auto;samesite=Lax;path=/;max-age=0';
this.#choose();
}
#choose() {
const themeCookieExists = document.cookie.split(';').some((cookie) => cookie.trim().startsWith('theme='));
if (themeCookieExists) {
return;
}
if (this.mql.matches) {
this.element.classList.add('dark-theme');
} else {
this.element.classList.remove('dark-theme');
}
}
}

View file

@ -0,0 +1,58 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['card', 'paginationWrapper'];
connect() {
this.pagination = this.paginationWrapperTarget.querySelector('.pagination');
this.cardIndex = 0;
this.lastCardIndex = this.cardTargets.length - 1;
/* If we come from next page */
if (window.location.hash === '#prev') {
this.cardIndex = this.lastCardIndex;
}
this.currentCard = this.cardTargets[this.cardIndex];
this.currentCard.classList.add('z-depth-4');
}
selectRightCard() {
if (this.cardIndex >= 0 && this.cardIndex < this.lastCardIndex) {
this.currentCard.classList.remove('z-depth-4');
this.cardIndex += 1;
this.currentCard = this.cardTargets[this.cardIndex];
this.currentCard.classList.add('z-depth-4');
return;
}
if (this.pagination && this.pagination.querySelector('a[rel="next"]')) {
window.location.href = this.pagination.querySelector('a[rel="next"]').href;
}
}
selectLeftCard() {
if (this.cardIndex > 0 && this.cardIndex <= this.lastCardIndex) {
this.currentCard.classList.remove('z-depth-4');
this.cardIndex -= 1;
this.currentCard = this.cardTargets[this.cardIndex];
this.currentCard.classList.add('z-depth-4');
return;
}
if (this.pagination && this.pagination.querySelector('a[rel="prev"]')) {
window.location.href = `${this.pagination.querySelector('a[rel="prev"]').href}#prev`;
}
}
selectCurrentCard() {
const url = this.currentCard.querySelector('a.card-title').href;
if (url) {
window.location.href = url;
}
}
}

View file

@ -0,0 +1,13 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['emailTwoFactor', 'googleTwoFactor'];
uncheckGoogle() {
this.googleTwoFactorTarget.checked = false;
}
uncheckEmail() {
this.emailTwoFactorTarget.checked = false;
}
}

View file

@ -0,0 +1,11 @@
import { Controller } from '@hotwired/stimulus';
import 'highlight.js/styles/atom-one-light.css';
import hljs from 'highlight.js';
export default class extends Controller {
connect() {
this.element.querySelectorAll('pre code').forEach((element) => {
hljs.highlightElement(element);
});
}
}

View file

@ -0,0 +1,7 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
toggleAddTagForm() {
this.dispatch('toggleAddTagForm');
}
}

View file

@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
static values = {
accordion: { type: Boolean, default: true },
};
connect() {
this.instance = M.Collapsible.init(this.element, { accordion: this.accordionValue });
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,16 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
connect() {
this.instance = M.Dropdown.init(this.element, {
hover: false,
coverTrigger: false,
constrainWidth: false,
});
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,32 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
static values = {
edge: { type: String, default: 'left' },
};
connect() {
this.instance = M.FloatingActionButton.init(this.element);
}
autoDisplay() {
const scrolled = (window.innerHeight + window.scrollY) >= document.body.offsetHeight;
if (scrolled) {
this.toggleScroll = true;
this.instance.open();
} else if (this.toggleScroll === true) {
this.toggleScroll = false;
this.instance.close();
}
}
click() {
this.dispatch('click');
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,12 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
connect() {
this.instance = M.FormSelect.init(this.element.querySelector('select'));
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,24 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
const mobileMaxWidth = 993;
export default class extends Controller {
static values = {
edge: { type: String, default: 'left' },
};
connect() {
this.instance = M.Sidenav.init(this.element, { edge: this.edgeValue });
}
close() {
if (window.innerWidth < mobileMaxWidth) {
this.instance.close();
}
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,12 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
connect() {
this.instance = M.Tabs.init(this.element);
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,12 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
connect() {
this.instance = M.toast({ text: this.element.innerText });
}
disconnect() {
this.instance.dismissAll();
}
}

View file

@ -0,0 +1,12 @@
import { Controller } from '@hotwired/stimulus';
import M from '@materializecss/materialize';
export default class extends Controller {
connect() {
this.instance = M.Tooltip.init(this.element);
}
disconnect() {
this.instance.destroy();
}
}

View file

@ -0,0 +1,10 @@
import { Controller } from '@hotwired/stimulus';
import jrQrcode from 'jr-qrcode';
export default class extends Controller {
static values = { url: String };
connect() {
this.element.setAttribute('src', jrQrcode.getQrBase64(this.urlValue));
}
}

View file

@ -0,0 +1,10 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
updateWidth() {
const referenceHeight = document.body.offsetHeight - window.innerHeight;
const scrollPercent = (window.scrollY / referenceHeight) * 100;
this.element.style.width = `${scrollPercent}%`;
}
}

View file

@ -0,0 +1,19 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static values = { entryId: Number };
connect() {
window.scrollTo({
top: window.innerHeight * localStorage[`wallabag.article.${this.entryIdValue}.percent`],
behavior: 'smooth',
});
}
saveScroll() {
const scrollPercent = window.scrollY / window.innerHeight;
const scrollPercentRounded = Math.round(scrollPercent * 100) / 100;
localStorage[`wallabag.article.${this.entryIdValue}.percent`] = scrollPercentRounded;
}
}

View file

@ -0,0 +1,141 @@
import { Controller } from '@hotwired/stimulus';
import Mousetrap from 'mousetrap';
export default class extends Controller {
static targets = ['openOriginal', 'markAsFavorite', 'markAsRead', 'deleteEntry', 'showAddUrl', 'showSearch', 'showActions'];
static outlets = ['entries-navigation'];
connect() {
/* Go to */
Mousetrap.bind('g u', () => {
window.location.href = Routing.generate('homepage');
});
Mousetrap.bind('g s', () => {
window.location.href = Routing.generate('starred');
});
Mousetrap.bind('g r', () => {
window.location.href = Routing.generate('archive');
});
Mousetrap.bind('g a', () => {
window.location.href = Routing.generate('all');
});
Mousetrap.bind('g t', () => {
window.location.href = Routing.generate('tag');
});
Mousetrap.bind('g c', () => {
window.location.href = Routing.generate('config');
});
Mousetrap.bind('g i', () => {
window.location.href = Routing.generate('import');
});
Mousetrap.bind('g d', () => {
window.location.href = Routing.generate('developer');
});
Mousetrap.bind('?', () => {
window.location.href = Routing.generate('howto');
});
Mousetrap.bind('g l', () => {
window.location.href = Routing.generate('fos_user_security_logout');
});
/* open original article */
Mousetrap.bind('o', () => {
if (!this.hasOpenOriginalTarget) {
return;
}
this.openOriginalTarget.click();
});
/* mark as favorite */
Mousetrap.bind('f', () => {
if (!this.hasMarkAsFavoriteTarget) {
return;
}
this.markAsFavoriteTarget.click();
});
/* mark as read */
Mousetrap.bind('a', () => {
if (!this.hasMarkAsReadTarget) {
return;
}
this.markAsReadTarget.click();
});
/* delete */
Mousetrap.bind('del', () => {
if (!this.hasDeleteEntryTarget) {
return;
}
this.deleteEntryTarget.click();
});
/* Actions */
Mousetrap.bind('g n', (e) => {
if (!this.hasShowAddUrlTarget) {
return;
}
e.preventDefault();
this.showAddUrlTarget.click();
});
Mousetrap.bind('s', (e) => {
if (!this.hasShowSearchTarget) {
return;
}
e.preventDefault();
this.showSearchTarget.click();
});
Mousetrap.bind('esc', (e) => {
if (!this.hasShowActionsTarget) {
return;
}
e.preventDefault();
this.showActionsTarget.click();
});
const originalStopCallback = Mousetrap.prototype.stopCallback;
Mousetrap.prototype.stopCallback = (e, element, combo) => {
// allow esc key to be used in input fields of topbar
if (combo === 'esc' && element.dataset.topbarTarget !== undefined) {
return false;
}
return originalStopCallback(e, element);
};
Mousetrap.bind('right', () => {
if (!this.hasEntriesNavigationOutlet) {
return;
}
this.entriesNavigationOutlet.selectRightCard();
});
Mousetrap.bind('left', () => {
if (!this.hasEntriesNavigationOutlet) {
return;
}
this.entriesNavigationOutlet.selectLeftCard();
});
Mousetrap.bind('enter', () => {
if (!this.hasEntriesNavigationOutlet) {
return;
}
this.entriesNavigationOutlet.selectCurrentCard();
});
}
}

View file

@ -0,0 +1,7 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
toggle() {
this.element.classList.toggle('entry-nav-top--sticky');
}
}

View file

@ -0,0 +1,12 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['link', 'edit', 'form', 'input'];
showForm() {
this.formTarget.classList.remove('hidden');
this.editTarget.classList.add('hidden');
this.linkTarget.classList.add('hidden');
this.inputTarget.focus();
}
}

View file

@ -0,0 +1,31 @@
import { Controller } from '@hotwired/stimulus';
export default class extends Controller {
static targets = ['addUrl', 'addUrlInput', 'search', 'searchInput', 'actions'];
showAddUrl() {
this.actionsTarget.style.display = 'none';
this.addUrlTarget.style.display = 'flex';
this.searchTarget.style.display = 'none';
this.addUrlInputTarget.focus();
}
submittingUrl(e) {
e.currentTarget.disabled = true;
this.addUrlInputTarget.readOnly = true;
this.addUrlInputTarget.blur();
}
showSearch() {
this.actionsTarget.style.display = 'none';
this.addUrlTarget.style.display = 'none';
this.searchTarget.style.display = 'flex';
this.searchInputTarget.focus();
}
showActions() {
this.actionsTarget.style.display = 'flex';
this.addUrlTarget.style.display = 'none';
this.searchTarget.style.display = 'none';
}
}

View file

Before

Width:  |  Height:  |  Size: 891 B

After

Width:  |  Height:  |  Size: 891 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 688 B

After

Width:  |  Height:  |  Size: 688 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 995 B

After

Width:  |  Height:  |  Size: 995 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 1,012 B

After

Width:  |  Height:  |  Size: 1,012 B

Before After
Before After

View file

Before

Width:  |  Height:  |  Size: 718 B

After

Width:  |  Height:  |  Size: 718 B

Before After
Before After

19
assets/index.js Executable file
View file

@ -0,0 +1,19 @@
import './bootstrap';
/* Materialize imports */
import '@materializecss/materialize/dist/css/materialize.css';
import '@materializecss/materialize/dist/js/materialize';
import 'mathjax/es5/tex-svg';
/* Fonts */
import 'material-design-icons-iconfont/dist/material-design-icons.css';
import 'lato-font/css/lato-font.css';
import 'open-dyslexic/open-dyslexic-regular.css';
import '@fontsource/atkinson-hyperlegible';
import '@fontsource/eb-garamond';
import '@fontsource/montserrat';
import '@fontsource/oswald';
/* Theme style */
import './scss/index.scss';

View file

@ -1,50 +0,0 @@
/* ==========================================================================
Side-nav
========================================================================== */
.side-nav {
width: 240px;
li {
padding: 0;
&.logo > a:hover {
background: initial;
}
& > a > i.material-icons.theme-toggle-icon {
float: none;
margin-left: 0;
}
}
a {
margin: 0;
}
&.fixed a {
font-size: 13px;
line-height: 44px;
height: 44px;
}
.collapsible-header,
&.fixed .collapsible-header {
height: 45px;
line-height: 44px;
padding: 0 20px;
}
> li.logo {
line-height: 0;
text-align: center;
}
}
.bold > a {
font-weight: bold;
}
.items-number {
float: right;
}

View file

@ -1,263 +0,0 @@
import $ from 'jquery';
/* Materialize imports */
import 'materialize-css/dist/css/materialize.css';
import 'materialize-css/dist/js/materialize';
/* Global imports */
import '../_global/index';
/* Tools */
import {
initExport, initFilters, initRandom, initPreviewText,
} from './js/tools';
/* Import shortcuts */
import './js/shortcuts/main';
import './js/shortcuts/entry';
/* Theme style */
import './css/index.scss';
const mobileMaxWidth = 993;
(function darkTheme() {
const rootEl = document.querySelector('html');
const themeDom = {
darkClass: 'dark-theme',
toggleClass(el) {
return el.classList.toggle(this.darkClass);
},
addClass(el) {
return el.classList.add(this.darkClass);
},
removeClass(el) {
return el.classList.remove(this.darkClass);
},
};
const themeCookie = {
values: {
light: 'light',
dark: 'dark',
},
name: 'theme',
getValue(isDarkTheme) {
return isDarkTheme ? this.values.dark : this.values.light;
},
setCookie(isDarkTheme) {
const value = this.getValue(isDarkTheme);
document.cookie = `${this.name}=${value};samesite=Lax;path=/;max-age=31536000`;
},
removeCookie() {
document.cookie = `${this.name}=auto;samesite=Lax;path=/;max-age=0`;
},
exists() {
return document.cookie.split(';').some((cookie) => cookie.trim().startsWith(`${this.name}=`));
},
};
const preferedColorScheme = {
choose() {
const themeCookieExists = themeCookie.exists();
if (this.isAvailable() && !themeCookieExists) {
const isPreferedColorSchemeDark = window.matchMedia('(prefers-color-scheme: dark)').matches === true;
if (!themeCookieExists) {
themeDom[isPreferedColorSchemeDark ? 'addClass' : 'removeClass'](rootEl);
}
}
},
isAvailable() {
return typeof window.matchMedia === 'function';
},
init() {
if (!this.isAvailable()) {
return false;
}
this.choose();
window.matchMedia('(prefers-color-scheme: dark)').addListener(() => {
this.choose();
});
return true;
},
};
const addDarkThemeListeners = () => {
$(document).ready(() => {
const lightThemeButtons = document.querySelectorAll('.js-theme-toggle[data-theme="light"]');
[...lightThemeButtons].map((lightThemeButton) => {
lightThemeButton.addEventListener('click', (e) => {
e.preventDefault();
themeDom.removeClass(rootEl);
themeCookie.setCookie(false);
});
return true;
});
const darkThemeButtons = document.querySelectorAll('.js-theme-toggle[data-theme="dark"]');
[...darkThemeButtons].map((darkThemeButton) => {
darkThemeButton.addEventListener('click', (e) => {
e.preventDefault();
themeDom.addClass(rootEl);
themeCookie.setCookie(true);
});
return true;
});
const autoThemeButtons = document.querySelectorAll('.js-theme-toggle[data-theme="auto"]');
[...autoThemeButtons].map((autoThemeButton) => {
autoThemeButton.addEventListener('click', (e) => {
e.preventDefault();
themeCookie.removeCookie();
preferedColorScheme.choose();
});
return true;
});
});
};
preferedColorScheme.init();
addDarkThemeListeners();
}());
const stickyNav = () => {
const nav = $('.js-entry-nav-top');
$('[data-toggle="actions"]').click(() => {
nav.toggleClass('entry-nav-top--sticky');
});
};
const articleScroll = () => {
const articleEl = $('#article');
if (articleEl.length > 0) {
$(window).scroll(() => {
const s = $(window).scrollTop();
const d = $(document).height();
const c = $(window).height();
const articleElBottom = articleEl.offset().top + articleEl.height();
const scrollPercent = (s / (d - c)) * 100;
$('.progress .determinate').css('width', `${scrollPercent}%`);
const fixedActionBtn = $('.js-fixed-action-btn');
const toggleScrollDataName = 'toggle-auto';
if ((s + c) > articleElBottom) {
fixedActionBtn.data(toggleScrollDataName, true);
fixedActionBtn.openFAB();
} else if (fixedActionBtn.data(toggleScrollDataName) === true) {
fixedActionBtn.data(toggleScrollDataName, false);
fixedActionBtn.closeFAB();
}
});
}
};
$(document).ready(() => {
// sideNav
$('.button-collapse').sideNav();
$('select').material_select();
$('.collapsible').collapsible({
accordion: false,
});
$('.datepicker').pickadate({
selectMonths: true,
selectYears: 15,
formatSubmit: 'yyyy-mm-dd',
hiddenName: false,
format: 'yyyy-mm-dd',
container: 'body',
});
$('.dropdown-trigger').dropdown({ hover: false });
initFilters();
initExport();
initRandom();
stickyNav();
articleScroll();
initPreviewText();
const toggleNav = (toShow, toFocus) => {
$('.nav-panel-actions').hide(100);
$(toShow).show(100);
$(toFocus).focus();
};
$('#nav-btn-add-tag').on('click', () => {
$('.nav-panel-add-tag').toggle(100);
$('.nav-panel-menu').addClass('hidden');
if (window.innerWidth < mobileMaxWidth) {
$('.side-nav').sideNav('hide');
}
$('#tag_label').focus();
return false;
});
$('#nav-btn-add').on('click', () => {
toggleNav('.nav-panel-add', '#entry_url');
return false;
});
$('#config_fontsize').on('input', () => {
const value = $('#config_fontsize').val();
const css = `${value}em`;
$('#preview-content').css('font-size', css);
});
$('#config_font').on('change', () => {
const value = $('#config_font').val();
$('#preview-content').css('font-family', value);
});
$('#config_lineHeight').on('input', () => {
const value = $('#config_lineHeight').val();
const css = `${value}em`;
$('#preview-content').css('line-height', css);
});
$('#config_maxWidth').on('input', () => {
const value = $('#config_maxWidth').val();
const css = `${value}em`;
$('#preview-article').css('max-width', css);
});
const materialAddForm = $('.nav-panel-add');
materialAddForm.on('submit', () => {
materialAddForm.addClass('disabled');
$('input#entry_url', materialAddForm).prop('readonly', true).trigger('blur');
});
$('#nav-btn-search').on('click', () => {
toggleNav('.nav-panel-search', '#search_entry_term');
return false;
});
$('.close').on('click', (e) => {
$(e.target).parent('.nav-panel-item').hide(100);
$('.nav-panel-actions').show(100);
return false;
});
const mainCheckboxes = document.querySelectorAll('[data-js="checkboxes-toggle"]');
if (mainCheckboxes.length) {
[...mainCheckboxes].forEach((el) => {
el.addEventListener('click', () => {
const checkboxes = document.querySelectorAll(el.dataset.toggle);
[...checkboxes].forEach((checkbox) => {
const checkboxClone = checkbox;
checkboxClone.checked = el.checked;
});
});
});
}
$('form[name="form_mass_action"] input[name="tags"]').on('keydown', (e) => {
if (e.key === 'Enter') {
e.preventDefault();
$('form[name="form_mass_action"] button[name="tag"]').trigger('click');
}
});
});

View file

@ -1,26 +0,0 @@
import Mousetrap from 'mousetrap';
import $ from 'jquery';
$(document).ready(() => {
if ($('#article').length > 0) {
/* open original article */
Mousetrap.bind('o', () => {
$('ul.side-nav a.original i')[0].click();
});
/* mark as favorite */
Mousetrap.bind('f', () => {
$('ul.side-nav a.favorite i')[0].click();
});
/* mark as read */
Mousetrap.bind('a', () => {
$('ul.side-nav a.markasread i')[0].click();
});
/* delete */
Mousetrap.bind('del', () => {
$('ul.side-nav a.delete i')[0].click();
});
}
});

View file

@ -1,92 +0,0 @@
import Mousetrap from 'mousetrap';
import $ from 'jquery';
function toggleFocus(cardToToogleFocus) {
if (cardToToogleFocus) {
$(cardToToogleFocus).toggleClass('z-depth-4');
}
}
$(document).ready(() => {
const cards = $('#content').find('.card');
const cardNumber = cards.length;
let cardIndex = 0;
/* If we come from next page */
if (window.location.hash === '#prev') {
cardIndex = cardNumber - 1;
}
let card = cards[cardIndex];
const pagination = $('.pagination');
/* Show nothing on quickstart */
if ($('#content > div.quickstart').length > 0) {
return;
}
/* Show nothing on login/register page */
if ($('#username').length > 0 || $('#fos_user_registration_form_username').length > 0) {
return;
}
/* Show nothing on login/register page */
if ($('#username').length > 0 || $('#fos_user_registration_form_username').length > 0) {
return;
}
/* Focus current card */
toggleFocus(card);
/* Actions */
Mousetrap.bind('g n', () => {
$('#nav-btn-add').trigger('click');
return false;
});
Mousetrap.bind('s', () => {
$('#nav-btn-search').trigger('click');
return false;
});
Mousetrap.bind('esc', () => {
$('.close').trigger('click');
});
/* Select right card. If there's a next page, go to next page */
Mousetrap.bind('right', () => {
if (cardIndex >= 0 && cardIndex < cardNumber - 1) {
toggleFocus(card);
cardIndex += 1;
card = cards[cardIndex];
toggleFocus(card);
return;
}
if (pagination.length > 0 && pagination.find('li.next:not(.disabled)').length > 0 && cardIndex === cardNumber - 1) {
window.location.href = window.location.origin + $(pagination).find('li.next a').attr('href');
}
});
/* Select previous card. If there's a previous page, go to next page */
Mousetrap.bind('left', () => {
if (cardIndex > 0 && cardIndex < cardNumber) {
toggleFocus(card);
cardIndex -= 1;
card = cards[cardIndex];
toggleFocus(card);
return;
}
if (pagination.length > 0 && $(pagination).find('li.prev:not(.disabled)').length > 0 && cardIndex === 0) {
window.location.href = `${window.location.origin + $(pagination).find('li.prev a').attr('href')}#prev`;
}
});
Mousetrap.bind('enter', () => {
if (typeof card !== 'object') {
return;
}
const url = $(card).find('.card-title a').attr('href');
if (typeof url === 'string' && url.length > 0) {
window.location.href = window.location.origin + url;
}
});
});

View file

@ -1,53 +0,0 @@
import $ from 'jquery';
function initFilters() {
// no display if filters not available
if ($('div').is('#filters')) {
$('#button_filters').show();
$('.js-filters-action').sideNav({ edge: 'right' });
$('#clear_form_filters').on('click', () => {
$('#filters input').val('');
$('#filters :checked').removeAttr('checked');
return false;
});
}
}
function initExport() {
// no display if export not available
if ($('div').is('#export')) {
$('#button_export').show();
$('.js-export-action').sideNav({ edge: 'right' });
}
}
function initRandom() {
// no display if export (ie: entries) not available
if ($('div').is('#export')) {
$('#button_random').show();
}
}
function initPreviewText() {
// no display if preview_text not available
if ($('div').is('#preview-article')) {
const defaultFontFamily = $('#config_font').val();
const defaultFontSize = $('#config_fontsize').val();
const defaultLineHeight = $('#config_lineHeight').val();
const defaultMaxWidth = $('#config_maxWidth').val();
const previewContent = $('#preview-content');
previewContent.css('font-family', defaultFontFamily);
previewContent.css('font-size', `${defaultFontSize}em`);
previewContent.css('line-height', `${defaultLineHeight}em`);
$('#preview-article').css('max-width', `${defaultMaxWidth}em`);
}
}
export {
initExport,
initFilters,
initRandom,
initPreviewText,
};

View file

@ -154,6 +154,15 @@ a.original:not(.waves-effect) {
}
}
.card .card-content .card-title,
.card-stacked .card-content .card-title {
display: -webkit-box;
overflow: hidden;
text-overflow: ellipsis;
-webkit-box-orient: vertical;
-webkit-line-clamp: 2;
}
.card-entry-labels li,
.card-tag-labels li {
margin: 10px 10px 10px auto;
@ -179,6 +188,7 @@ a.original:not(.waves-effect) {
.card-entry-tags a,
.card-entry-labels a,
.card-tag-labels a,
.card-tag-labels button,
.card-entry-labels-hidden a,
#list .chip a {
text-decoration: none;
@ -186,6 +196,14 @@ a.original:not(.waves-effect) {
color: #fff;
}
.card-tag-labels button {
background: transparent;
border: none;
font-weight: normal;
color: #fff;
cursor: pointer;
}
.card-tag-link {
width: calc(100% - 24px);
line-height: 1.3;
@ -196,6 +214,7 @@ a.original:not(.waves-effect) {
.card-tag-form {
display: flex;
align-items: center;
min-width: 100px;
flex-grow: 1;
}

View file

@ -12,9 +12,9 @@
.collapsible-header,
.collection,
.dropdown-content,
.side-nav,
.side-nav .collapsible-body,
.side-nav.fixed .collapsible-body,
.sidenav,
.sidenav .collapsible-body,
.sidenav.sidenav-fixed .collapsible-body,
.tabs {
background-color: #131716;
}
@ -59,10 +59,13 @@
#article article h5,
#article article h6,
.dropdown-content li > a,
.nav-panels .input-field input:focus,
.input-field input,
.input-field input:focus,
.results-item,
.side-nav li > a,
.side-nav li > a > i.material-icons {
.sidenav li > a,
.sidenav li > a > i.material-icons,
.sidenav li button,
.sidenav li button > i.material-icons {
color: #dfdfdf;
}
@ -81,14 +84,15 @@
color: #dfdfdf !important;
}
.side-nav li.active {
.sidenav li.active {
background-color: #2f2f2f;
}
.mass-action-tags .mass-action-tags-input.mass-action-tags-input,
.side-nav li:not(.logo) > a:hover,
.side-nav .collapsible-header:hover,
.side-nav.fixed .collapsible-header:hover {
.sidenav li:not(.logo) > a:hover,
.sidenav li:not(.logo) button:hover,
.sidenav .collapsible-header:hover,
.sidenav.sidenav-fixed .collapsible-header:hover {
background-color: #1d1d1d;
}
@ -141,6 +145,12 @@
background-color: transparent;
}
.z-depth-4 {
box-shadow: 0 16px 24px 2px rgba(255 255 255 / 14%),
0 6px 30px 5px rgba(255 255 255 / 12%),
0 8px 10px -7px rgba(255 255 255 / 20%);
}
@media only screen and (min-width: 992px) {
#article {
background-color: #101010;

View file

@ -125,24 +125,24 @@ a.icon-image {
}
&.diaspora::before {
background: url("../../_global/img/icons/diaspora-icon--black.png") no-repeat center/80%;
background: url("../img/icons/diaspora-icon--black.png") no-repeat center/80%;
}
&.unmark::before {
background: url("../../_global/img/icons/unmark-icon--black.png") no-repeat center/80%;
background: url("../img/icons/unmark-icon--black.png") no-repeat center/80%;
}
&.linkding::before {
background: url("../../_global/img/icons/linkding.svg") no-repeat center/80%;
background: url("../img/icons/linkding.svg") no-repeat center/80%;
filter: grayscale(1);
}
&.shaarli::before {
background: url("../../_global/img/icons/shaarli.png") no-repeat center/80%;
background: url("../img/icons/shaarli.png") no-repeat center/80%;
}
&.scuttle::before {
background: url("../../_global/img/icons/scuttle.png") no-repeat center/80%;
background: url("../img/icons/scuttle.png") no-repeat center/80%;
}
}

View file

@ -6,17 +6,38 @@ nav {
line-height: initial;
}
// adapted from anchor styles from node_modules/@materializecss/materialize/sass/components/_navbar.scss
nav ul button {
transition: background-color .3s;
font-size: 1rem;
color: #fff;
display: block;
padding: 0 15px;
cursor: pointer;
background: none;
border: 0;
&:focus {
background: none;
}
&:hover {
background-color: rgba(0 0 0 / 10%);
}
}
nav {
input {
color: #aaa;
}
ul button:hover,
ul a:hover {
background-color: initial;
}
}
.nav-panel-item .button-collapse {
.nav-panel-item .sidenav-trigger {
margin-left: 0;
margin-right: 0.5rem;
padding-left: 0.5rem;
@ -34,6 +55,7 @@ nav {
justify-content: space-between;
align-items: center;
button,
a {
padding: 10px 15px;
}
@ -143,14 +165,6 @@ nav {
margin: 0 1%;
}
.button-filters {
display: none;
}
.button-export {
display: none;
}
.entry-nav-top--sticky {
position: sticky;
top: 0;
@ -183,7 +197,7 @@ nav {
justify-content: end;
}
.button-collapse {
.sidenav-trigger {
display: none;
}

85
assets/scss/_sidenav.scss Normal file
View file

@ -0,0 +1,85 @@
/* ==========================================================================
Sidenav
========================================================================== */
.sidenav {
width: 240px;
li {
padding: 0;
&.logo > a:hover {
background: initial;
}
& button > i.material-icons.theme-toggle-icon,
& > a > i.material-icons.theme-toggle-icon {
float: none;
margin-left: 0;
}
}
a {
margin: 0;
}
&.sidenav-fixed button,
&.sidenav-fixed a {
font-size: 13px;
line-height: 44px;
height: 44px;
}
.collapsible-header,
&.sidenav-fixed .collapsible-header {
height: 45px;
line-height: 44px;
padding: 0 20px;
}
> li.logo {
line-height: 0;
text-align: center;
}
}
// adapted from anchor styles from node_modules/@materializecss/materialize/sass/components/_sidenav.scss
.sidenav li button {
color: rgba(0 0 0 / 87%);
display: block;
font-size: 14px;
font-weight: 500;
height: 48px;
line-height: 48px;
padding: 0 (16px * 2);
width: 100%;
text-align: left;
&:hover {
background-color: rgba(0 0 0 / 5%);
}
& > i,
& > i.material-icons {
float: left;
height: 48px;
line-height: 48px;
margin: 0 (16px * 2) 0 0;
width: 24px;
color: rgba(0 0 0 / 54%);
}
}
.bold > a,
.bold > button {
font-weight: bold;
}
.items-number {
float: right;
}
.button-filters .sidenav-trigger,
.button-export .sidenav-trigger {
display: block;
}

View file

@ -1,3 +1,5 @@
@use "variables";
/* ==========================================================================
* Various
* ========================================================================== */
@ -38,3 +40,18 @@ nav .input-field input {
.tab {
flex: 1;
}
.btn-link {
background: none;
border: 0;
padding: 0;
color: variables.$blue-accent-color;
&:focus {
background: none;
}
}
.inline-block {
display: inline-block;
}

View file

@ -1,3 +1,4 @@
@use "material-icons";
@use "variables";
/* Style */

1
assets/share.js Normal file
View file

@ -0,0 +1 @@
import './scss/share.scss';

View file

@ -5,8 +5,9 @@ use ShipMonk\ComposerDependencyAnalyser\Config\ErrorType;
$config = new Configuration();
return $config
$config
->disableComposerAutoloadPathScan()
->disableExtensionsAnalysis()
->enableAnalysisOfUnusedDevDependencies()
->addPathToScan(__DIR__ . '/app', false)
->addPathToScan(__DIR__ . '/migrations', false)
@ -22,14 +23,13 @@ return $config
'friendsoftwig/twigcs',
'incenteev/composer-parameter-handler',
'j0k3r/graby-site-config',
'j0k3r/php-readability',
'laminas/laminas-code',
'lcobucci/jwt',
'mgargano/simplehtmldom',
'mnapoli/piwik-twig-extension',
'ocramius/proxy-manager',
'pagerfanta/twig',
'php-http/client-common',
'php-http/httplug',
'php-http/mock-client',
'phpstan/extension-installer',
'phpstan/phpstan',
@ -38,30 +38,22 @@ return $config
'phpstan/phpstan-symfony',
'psr/http-client',
'psr/http-factory',
'psr/http-message',
'rulerz-php/doctrine-orm',
'scheb/2fa-qr-code',
'rector/rector',
'scheb/2fa-trusted-device',
'shipmonk/composer-dependency-analyser',
'symfony/asset',
'symfony/browser-kit',
'symfony/css-selector',
'symfony/doctrine-bridge',
'symfony/google-mailer',
'symfony/intl',
'symfony/phpunit-bridge',
'symfony/polyfill-php80',
'symfony/polyfill-php81',
'symfony/proxy-manager-bridge',
'symfony/templating',
'symfony/var-dumper',
'twig/string-extra',
], [ErrorType::UNUSED_DEPENDENCY])
->ignoreErrorsOnPackages([
'guzzlehttp/streams',
'monolog/monolog',
'symfony/filesystem',
'symfony/http-client',
], [ErrorType::PROD_DEPENDENCY_ONLY_IN_DEV])
->ignoreErrorsOnPackages([
'dama/doctrine-test-bundle',
@ -71,4 +63,9 @@ return $config
'symfony/web-profiler-bundle',
'symfony/web-server-bundle',
], [ErrorType::DEV_DEPENDENCY_IN_PROD])
->ignoreErrorsOnPackages([
'gedmo/doctrine-extensions',
], [ErrorType::SHADOW_DEPENDENCY])
;
return $config;

View file

@ -38,7 +38,7 @@
"issues": "https://github.com/wallabag/wallabag/issues"
},
"require": {
"php": ">=7.4",
"php": ">=8.2",
"ext-ctype": "*",
"ext-curl": "*",
"ext-dom": "*",
@ -57,141 +57,147 @@
"ext-tidy": "*",
"ext-tokenizer": "*",
"ext-xml": "*",
"babdev/pagerfanta-bundle": "^3.8",
"babdev/pagerfanta-bundle": "^4.5",
"craue/config-bundle": "^2.7.0",
"defuse/php-encryption": "^2.4",
"doctrine/collections": "^1.8",
"doctrine/common": "^3.4.3",
"doctrine/dbal": "^3.8.2",
"doctrine/doctrine-bundle": "^2.11.3",
"doctrine/doctrine-migrations-bundle": "^3.3",
"doctrine/collections": "^2.3",
"doctrine/common": "^3.5.0",
"doctrine/dbal": "^3.9.4",
"doctrine/doctrine-bundle": "^2.13.2",
"doctrine/doctrine-migrations-bundle": "^3.4.1",
"doctrine/event-manager": "^1.2",
"doctrine/migrations": "^3.5.5",
"doctrine/orm": "^2.18.1",
"doctrine/persistence": "^3.2",
"egulias/email-validator": "^3.2.6",
"enshrined/svg-sanitize": "^0.21",
"friendsofsymfony/jsrouting-bundle": "^2.8",
"doctrine/migrations": "^3.8.2",
"doctrine/orm": "^2.20.2",
"doctrine/persistence": "^3.4",
"egulias/email-validator": "^4.0.4",
"enshrined/svg-sanitize": "^0.22",
"friendsofsymfony/jsrouting-bundle": "^3.5",
"friendsofsymfony/oauth-server-bundle": "dev-master#dc8ff343363cf794d30eb1a123610d186a43f162",
"friendsofsymfony/rest-bundle": "^3.6",
"friendsofsymfony/user-bundle": "^3.2.1",
"guzzlehttp/guzzle": "^5.3.4",
"guzzlehttp/psr7": "^2.6.2",
"guzzlehttp/streams": "^3.0",
"html2text/html2text": "^4.3.1",
"friendsofsymfony/rest-bundle": "^3.8",
"friendsofsymfony/user-bundle": "^3.4.0",
"guzzlehttp/psr7": "^2.7.0",
"html2text/html2text": "^4.3.2",
"incenteev/composer-parameter-handler": "^2.2",
"j0k3r/graby": "^2.4.5",
"j0k3r/graby-site-config": "^1.0",
"j0k3r/graby": "^2.4.6",
"j0k3r/graby-site-config": "^1.0.197",
"j0k3r/php-readability": "^1.2.13",
"javibravo/simpleue": "^2.1",
"jms/serializer": "^3.29.1",
"jms/serializer-bundle": "^5.4",
"laminas/laminas-code": "^4.7.1",
"jms/serializer": "^3.32.3",
"jms/serializer-bundle": "^5.5.1",
"laminas/laminas-code": "^4.16",
"lcobucci/jwt": "^4.3",
"league/html-to-markdown": "^5.1",
"league/html-to-markdown": "^5.1.1",
"mgargano/simplehtmldom": "^1.5",
"mnapoli/piwik-twig-extension": "^3.0",
"monolog/monolog": "^2.9",
"nelmio/api-doc-bundle": "^4.20.0",
"nelmio/cors-bundle": "^2.4",
"monolog/monolog": "^2.10",
"nelmio/api-doc-bundle": "^4.38.1",
"nelmio/cors-bundle": "^2.5",
"ocramius/proxy-manager": "^2.1.1",
"pagerfanta/core": "^3.8",
"pagerfanta/doctrine-orm-adapter": "^3.8",
"pagerfanta/twig": "^3.8",
"php-amqplib/php-amqplib": "^3.6.1",
"php-amqplib/rabbitmq-bundle": "^2.14.0",
"php-http/client-common": "^2.7.1",
"php-http/guzzle5-adapter": "^2.0",
"php-http/httplug": "^2.4",
"php-http/httplug-bundle": "^1.32",
"pagerfanta/doctrine-orm-adapter": "^4.7",
"pagerfanta/twig": "^4.7",
"php-amqplib/php-amqplib": "^3.7.3",
"php-amqplib/rabbitmq-bundle": "^2.17.3",
"pragmarx/recovery": "^0.2.1",
"predis/predis": "^2.2.2",
"predis/predis": "^3.2.0",
"psr/http-client": "^1.0.3",
"psr/http-factory": "^1.0.2",
"psr/http-factory": "^1.1.0",
"psr/http-message": "^2.0",
"psr/log": "^1.1.4",
"rulerz-php/doctrine-orm": "dev-master",
"scheb/2fa-backup-code": "^5.13.2",
"scheb/2fa-bundle": "^5.13.2",
"scheb/2fa-email": "^5.13.2",
"scheb/2fa-google-authenticator": "^5.13.2",
"scheb/2fa-qr-code": "^5.13.2",
"scheb/2fa-trusted-device": "^5.13.2",
"scssphp/scssphp": "^1.12.1",
"scssphp/scssphp": "^2.0.1",
"sensio/framework-extra-bundle": "^6.2.10",
"sentry/sentry-symfony": "^5.0.1",
"spiriitlabs/form-filter-bundle": "^10.0",
"stof/doctrine-extensions-bundle": "^1.11.0",
"symfony/asset": "^5.4.35",
"symfony/config": "^5.4.35",
"symfony/console": "^5.4.35",
"symfony/dependency-injection": "^5.4.35",
"symfony/doctrine-bridge": "^5.4.35",
"symfony/dom-crawler": "^5.4.35",
"symfony/error-handler": "^5.4.35",
"symfony/event-dispatcher": "^5.4.35",
"symfony/event-dispatcher-contracts": "^2.5.2",
"symfony/expression-language": "^5.4.35",
"symfony/filesystem": "^5.4",
"symfony/finder": "^5.4.35",
"symfony/form": "^5.4.35",
"symfony/framework-bundle": "^5.4.35",
"symfony/google-mailer": "^5.4.35",
"symfony/http-client": "^5.4.35",
"symfony/http-client-contracts": "^2.5",
"symfony/http-foundation": "^5.4.35",
"symfony/http-kernel": "^5.4.35",
"symfony/intl": "^5.4.35",
"symfony/mailer": "^5.4.35",
"symfony/mime": "^5.4.35",
"sentry/sentry-symfony": "^5.2.0",
"spiriitlabs/form-filter-bundle": "^10.0.2",
"stof/doctrine-extensions-bundle": "^1.13.0",
"symfony/asset": "^5.4.45",
"symfony/browser-kit": "^5.4.45",
"symfony/config": "^5.4.46",
"symfony/console": "^5.4.47",
"symfony/dependency-injection": "^5.4.48",
"symfony/doctrine-bridge": "^5.4.48",
"symfony/dom-crawler": "^5.4.48",
"symfony/error-handler": "^5.4.46",
"symfony/event-dispatcher": "^5.4.45",
"symfony/event-dispatcher-contracts": "^2.5.4",
"symfony/expression-language": "^5.4.45",
"symfony/filesystem": "^5.4.45",
"symfony/finder": "^5.4.45",
"symfony/form": "^5.4.45",
"symfony/framework-bundle": "^5.4.45",
"symfony/google-mailer": "^5.4.45",
"symfony/http-client": "^5.4.49",
"symfony/http-client-contracts": "^2.5.5",
"symfony/http-foundation": "^5.4.48",
"symfony/http-kernel": "^5.4.48",
"symfony/intl": "^5.4.47",
"symfony/mailer": "^5.4.45",
"symfony/mime": "^5.4.45",
"symfony/monolog-bundle": "^3.10",
"symfony/options-resolver": "^5.4.21",
"symfony/polyfill-php80": "^1.29",
"symfony/polyfill-php81": "^1.29",
"symfony/proxy-manager-bridge": "^5.4.21",
"symfony/routing": "^5.4.35",
"symfony/security-bundle": "^5.4.35",
"symfony/security-core": "^5.4.35",
"symfony/security-http": "^5.4.35",
"symfony/templating": "^5.4.35",
"symfony/translation-contracts": "^2.5.2",
"symfony/twig-bundle": "^5.4.35",
"symfony/validator": "^5.4.35",
"tecnickcom/tcpdf": "^6.6.5",
"twig/extra-bundle": "^3.8",
"twig/string-extra": "^3.8",
"twig/twig": "^3.8.0",
"symfony/options-resolver": "^5.4.45",
"symfony/proxy-manager-bridge": "^5.4.45",
"symfony/routing": "^5.4.48",
"symfony/security-bundle": "^5.4.45",
"symfony/security-core": "^5.4.48",
"symfony/security-http": "^5.4.47",
"symfony/templating": "^5.4.45",
"symfony/translation-contracts": "^2.5.4",
"symfony/twig-bundle": "^5.4.45",
"symfony/validator": "^5.4.48",
"symfony/webpack-encore-bundle": "^1.17.2",
"tecnickcom/tcpdf": "^6.8.2",
"twig/extra-bundle": "^3.20",
"twig/string-extra": "^3.20",
"twig/twig": "^3.20.0",
"wallabag/phpepub": "^4.0.10",
"wallabag/rulerz": "dev-master",
"wallabag/rulerz-bundle": "dev-master",
"willdurand/hateoas": "^3.10",
"willdurand/hateoas-bundle": "^2.6"
"willdurand/hateoas": "^3.12",
"willdurand/hateoas-bundle": "^2.7"
},
"require-dev": {
"dama/doctrine-test-bundle": "^8.0.2",
"doctrine/data-fixtures": "^1.7",
"doctrine/doctrine-fixtures-bundle": "^3.5.1",
"ergebnis/composer-normalize": "^2.42.0",
"friendsofphp/php-cs-fixer": "^3.49",
"friendsoftwig/twigcs": "^6.1",
"dama/doctrine-test-bundle": "^8.2.2",
"doctrine/data-fixtures": "^2.0.2",
"doctrine/doctrine-fixtures-bundle": "^3.7.1",
"ergebnis/composer-normalize": "^2.45.0",
"friendsofphp/php-cs-fixer": "^3.70.2",
"friendsoftwig/twigcs": "^6.5",
"m6web/redis-mock": "^5.6",
"php-http/mock-client": "^1.6",
"phpstan/extension-installer": "^1.3.1",
"phpstan/phpstan": "^1.10.59",
"phpstan/phpstan-doctrine": "^1.3.62",
"phpstan/phpstan-phpunit": "^1.3.16",
"phpstan/phpstan-symfony": "^1.3.7",
"phpunit/phpunit": "^9.6.17",
"shipmonk/composer-dependency-analyser": "^1.7",
"symfony/browser-kit": "^5.4.35",
"symfony/css-selector": "^5.4.35",
"symfony/debug-bundle": "^5.4.35",
"symfony/maker-bundle": "^1.43",
"symfony/phpunit-bridge": "^7.0.3",
"symfony/process": "^5.4",
"symfony/var-dumper": "^5.4.35",
"symfony/web-profiler-bundle": "^5.4.35",
"php-http/mock-client": "^1.6.1",
"phpstan/extension-installer": "^1.4.3",
"phpstan/phpstan": "^1.12.20",
"phpstan/phpstan-doctrine": "^1.5.7",
"phpstan/phpstan-phpunit": "^1.4.2",
"phpstan/phpstan-symfony": "^1.4.13",
"phpunit/phpunit": "^9.6.22",
"rector/rector": "^1.2",
"shipmonk/composer-dependency-analyser": "^1.8.2",
"symfony/css-selector": "^5.4.45",
"symfony/debug-bundle": "^5.4.45",
"symfony/maker-bundle": "^1.50",
"symfony/phpunit-bridge": "^7.2.0",
"symfony/process": "^5.4.47",
"symfony/var-dumper": "^5.4.48",
"symfony/web-profiler-bundle": "^5.4.48",
"symfony/web-server-bundle": "^4.4.44"
},
"replace": {
"symfony/polyfill-php54": "*",
"symfony/polyfill-php55": "*",
"symfony/polyfill-php56": "*",
"symfony/polyfill-php70": "*",
"symfony/polyfill-php71": "*",
"symfony/polyfill-php72": "*",
"symfony/polyfill-php73": "*",
"symfony/polyfill-php74": "*",
"symfony/polyfill-php80": "*",
"symfony/polyfill-php81": "*",
"symfony/polyfill-php82": "*"
},
"suggest": {
"ext-imagick": "To keep GIF animation when downloading image is enabled"
},
@ -222,9 +228,6 @@
"phpstan/extension-installer": true
},
"bin-dir": "bin",
"platform": {
"php": "7.4.29"
},
"sort-packages": true
},
"extra": {

4120
composer.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,13 @@
FROM php:8.1-fpm AS rootless
FROM golang as envsubst
ARG ENVSUBST_VERSION=v1.3.0
# envsubst from gettext can not replace env vars with default values
# this package is not available for ARM32 and we have to build it from source code
# flag -ldflags "-s -w" produces a smaller executable
RUN go install -ldflags "-s -w" -v github.com/a8m/envsubst/cmd/envsubst@${ENVSUBST_VERSION}
FROM php:8.2-fpm AS rootless
ARG DEBIAN_FRONTEND=noninteractive
ARG NODE_VERSION=20
@ -12,8 +21,7 @@ RUN apt-get update \
openssl \
software-properties-common
RUN curl 'https://deb.nodesource.com/gpgkey/nodesource.gpg.key' | apt-key add - \
&& echo "deb https://deb.nodesource.com/node_${NODE_VERSION}.x $(lsb_release -cs) main" > /etc/apt/sources.list.d/nodesource.list
RUN curl -fsSL https://deb.nodesource.com/setup_${NODE_VERSION}.x | bash -
RUN apt-get update && apt-get install -y \
libmcrypt-dev \
@ -51,14 +59,13 @@ RUN docker-php-ext-install -j "$(nproc)" \
tidy \
zip
RUN pecl install redis; \
pecl install imagick; \
pecl install xdebug-3.1.6; \
docker-php-ext-enable \
RUN pecl install redis-6.1.0 \
&& pecl install imagick-3.7.0 \
&& pecl install xdebug-3.4.1 \
&& docker-php-ext-enable \
redis \
imagick \
xdebug \
;
xdebug
RUN version=$(php -r "echo PHP_MAJOR_VERSION.PHP_MINOR_VERSION;") \
&& architecture=$(uname -m) \
@ -77,10 +84,8 @@ RUN mkdir -p /tmp/blackfire \
RUN npm install -g yarn
RUN curl -L -o /usr/local/bin/envsubst https://github.com/a8m/envsubst/releases/download/v1.1.0/envsubst-`uname -s`-`uname -m`; \
chmod +x /usr/local/bin/envsubst
COPY --from=composer:latest /usr/bin/composer /usr/local/bin/composer
COPY --from=envsubst /go/bin/envsubst /usr/local/bin/envsubst
COPY entrypoint.sh /entrypoint.sh
COPY config/ /opt/wallabag/config/

View file

@ -5,9 +5,9 @@ parameters:
database_name: ${DATABASE_NAME:-symfony}
database_user: ${DATABASE_USER:-root}
database_password: ${DATABASE_PASSWORD:-~}
database_path: '${DATABASE_PATH:-"%kernel.project_dir%/data/db/wallabag.sqlite"}'
database_path: ${DATABASE_PATH:-"%kernel.project_dir%/data/db/wallabag.sqlite"}
database_table_prefix: ${DATABASE_TABLE_PREFIX:-wallabag_}
database_socket: null
database_socket: ${DATABASE_SOCKET:-~}
database_charset: ${DATABASE_CHARSET:-utf8}
domain_name: ${DOMAIN_NAME:-https://www.example.com}
@ -27,22 +27,20 @@ parameters:
fosuser_registration: ${FOSUSER_REGISTRATION:-false}
fosuser_confirmation: ${FOSUSER_CONFIRMATION:-true}
fos_oauth_server_access_token_lifetime: 3600
fos_oauth_server_refresh_token_lifetime: 1209600
fos_oauth_server_access_token_lifetime: ${FOS_OAUTH_SERVER_ACCESS_TOKEN_LIFETIME:-3600}
fos_oauth_server_refresh_token_lifetime: ${FOS_OAUTH_SERVER_REFRESH_TOKEN_LIFETIME:-1209600}
from_email: ${FROM_EMAIL:-wallabag@example.com}
rss_limit: 50
# RabbitMQ processing
rabbitmq_host: ${RABBITMQ_HOST:-rabbitmq}
rabbitmq_port: ${RABBITMQ_PORT:-5672}
rabbitmq_user: ${RABBITMQ_USER:-guest}
rabbitmq_password: ${RABBITMQ_PASSWORD:-guest}
rabbitmq_prefetch_count: 10
rabbitmq_prefetch_count: ${RABBITMQ_PREFETCH_COUNT:-10}
# Redis processing
redis_scheme: ${REDIS_SCHEME:-tcp}
redis_scheme: ${REDIS_SCHEME:-redis}
redis_host: ${REDIS_HOST:-redis}
redis_port: ${REDIS_PORT:-6379}
redis_path: ${REDIS_PATH:-~}

View file

@ -4,9 +4,9 @@ DATABASE_PORT=~
DATABASE_NAME=symfony
DATABASE_USER=root
DATABASE_PASSWORD=~
DATABASE_PATH="%kernel.project_dir%/data/db/wallabag.sqlite"
DOMAIN_NAME=http://localhost:8000
DATABASE_PATH='"%kernel.project_dir%/data/db/wallabag.sqlite"'
DOMAIN_NAME=http://127.0.0.1:8000
SECRET=ch4n63m31fy0uc4n
PHP_SESSION_SAVE_PATH=tcp://redis:6379?database=2
PHP_SESSION_SAVE_PATH=redis://redis:6379?database=2
PHP_SESSION_HANDLER=redis
TRUSTED_PROXIES=0.0.0.0/0

View file

@ -11,7 +11,7 @@ use Wallabag\Entity\User;
class AnnotationFixtures extends Fixture implements DependentFixtureInterface
{
public function load(ObjectManager $manager)
public function load(ObjectManager $manager): void
{
$annotation1 = new Annotation($this->getReference('admin-user', User::class));
$annotation1->setEntry($this->getReference('entry1', Entry::class));
@ -43,7 +43,7 @@ class AnnotationFixtures extends Fixture implements DependentFixtureInterface
$manager->flush();
}
public function getDependencies()
public function getDependencies(): array
{
return [
EntryFixtures::class,

Some files were not shown because too many files have changed in this diff Show more